mirror of
https://github.com/davidalves04/Trabalho-Pratico-SD.git
synced 2025-12-12 22:28:05 +00:00
225 lines
7.5 KiB
Java
225 lines
7.5 KiB
Java
package sd.model;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* Representa uma interseção na simulação de tráfego.
|
|
*
|
|
* <p>Uma interseção funciona como um nó central da rede. Não controla lógica diretamente,
|
|
* mas gere um conjunto de semáforos ({@link TrafficLight}).</p>
|
|
*
|
|
* <p>Responsabilidades principais:</p>
|
|
* <ul>
|
|
* <li>Manter um {@link TrafficLight} para cada direção (Norte, Este, etc.)</li>
|
|
* <li>Gerir uma tabela de encaminhamento que mapeia destinos para direções</li>
|
|
* <li>Receber veículos e colocá-los na fila do semáforo correto</li>
|
|
* <li>Acompanhar estatísticas agregadas do tráfego</li>
|
|
* </ul>
|
|
*/
|
|
public class Intersection {
|
|
|
|
/** Identificador único da interseção (ex: "Cr1", "Cr2") */
|
|
private final String id;
|
|
|
|
/**
|
|
* Mapa com todos os semáforos desta interseção.
|
|
* Chave: Direção (String, ex: "Norte", "Este")
|
|
* Valor: Objeto {@link TrafficLight} correspondente
|
|
*/
|
|
private final Map<String, TrafficLight> trafficLights;
|
|
|
|
/**
|
|
* Tabela de encaminhamento da interseção.
|
|
* Chave: Próximo destino (String, ex: "Cr3", "S" para saída)
|
|
* Valor: Direção que o veículo deve tomar nesta interseção
|
|
*/
|
|
private final Map<String, String> routing;
|
|
/** Número total de veículos recebidos por esta interseção */
|
|
private int totalVehiclesReceived;
|
|
|
|
/** Número total de veículos que partiram desta interseção */
|
|
private int totalVehiclesSent;
|
|
|
|
/** Média acumulada do tempo de espera dos veículos nesta interseção */
|
|
private double averageWaitingTime;
|
|
|
|
/**
|
|
* Cria uma nova interseção.
|
|
* Inicializa mapas vazios para semáforos e encaminhamento.
|
|
*
|
|
* @param id identificador único da interseção (ex: "Cr1")
|
|
*/
|
|
public Intersection(String id) {
|
|
this.id = id;
|
|
this.trafficLights = new HashMap<>();
|
|
this.routing = new HashMap<>();
|
|
this.totalVehiclesReceived = 0;
|
|
this.totalVehiclesSent = 0;
|
|
this.averageWaitingTime = 0.0;
|
|
}
|
|
|
|
/**
|
|
* Regista um novo semáforo nesta interseção.
|
|
* O semáforo é mapeado pela sua direção.
|
|
*
|
|
* @param trafficLight o semáforo a adicionar
|
|
*/
|
|
public void addTrafficLight(TrafficLight trafficLight) {
|
|
trafficLights.put(trafficLight.getDirection(), trafficLight);
|
|
}
|
|
|
|
/**
|
|
* Define uma regra de encaminhamento para esta interseção.
|
|
*
|
|
* <p>Por exemplo, {@code configureRoute("Cr3", "Este")} significa:
|
|
* "Qualquer veículo que chegue aqui com destino 'Cr3' deve ser enviado
|
|
* para a fila do semáforo da direção Este."</p>
|
|
*
|
|
* @param nextDestination ID da próxima interseção ou saída (ex: "Cr3", "S")
|
|
* @param direction direção (e respetivo semáforo) a usar nesta interseção
|
|
*/
|
|
public void configureRoute(String nextDestination, String direction) {
|
|
routing.put(nextDestination, direction);
|
|
}
|
|
|
|
/**
|
|
* Recebe um novo veículo e coloca-o na fila do semáforo apropriado.
|
|
* A direção é escolhida com base na tabela de encaminhamento.
|
|
*
|
|
* @param vehicle o veículo que está a chegar a esta interseção
|
|
* @param simulationTime o tempo de simulação atual (em segundos)
|
|
*/
|
|
public void receiveVehicle(Vehicle vehicle, double simulationTime) {
|
|
totalVehiclesReceived++;
|
|
|
|
String nextDestination = vehicle.getCurrentDestination();
|
|
|
|
// Check if vehicle reached final destination
|
|
if (nextDestination == null) {
|
|
System.out.printf("[%s] Vehicle %s reached final destination%n",
|
|
this.id, vehicle.getId());
|
|
return;
|
|
}
|
|
|
|
String direction = routing.get(nextDestination);
|
|
|
|
if (direction != null && trafficLights.containsKey(direction)) {
|
|
// Found a valid route and light, add vehicle to the queue
|
|
trafficLights.get(direction).addVehicle(vehicle, simulationTime);
|
|
} else {
|
|
// Routing error: No rule for this destination or no light for that direction
|
|
System.err.printf(
|
|
"Routing error at %s: could not place vehicle %s (destination: %s, found direction: %s)%n",
|
|
this.id, vehicle.getId(), nextDestination, direction
|
|
);
|
|
}
|
|
} /**
|
|
* Retorna a direção que um veículo deve tomar para alcançar um destino.
|
|
*
|
|
* @param destination o próximo destino (ex: "Cr3", "S")
|
|
* @return a direção (ex: "Este"), ou null se não houver rota configurada
|
|
*/
|
|
public String getDirectionForDestination(String destination) {
|
|
return routing.get(destination);
|
|
}
|
|
|
|
/**
|
|
* Retorna o semáforo que controla uma determinada direção.
|
|
*
|
|
* @param direction a direção (ex: "Norte")
|
|
* @return o objeto {@link TrafficLight}, ou null se não existir
|
|
*/
|
|
public TrafficLight getTrafficLight(String direction) {
|
|
return trafficLights.get(direction);
|
|
}
|
|
|
|
/**
|
|
* Retorna uma lista com todos os semáforos desta interseção.
|
|
*
|
|
* @return uma nova {@link List} com todos os semáforos
|
|
*/
|
|
public List<TrafficLight> getTrafficLights() {
|
|
return new ArrayList<>(trafficLights.values());
|
|
}
|
|
|
|
/**
|
|
* Retorna o número total de veículos em fila em todos os semáforos.
|
|
* Usa Java Stream API para somar os tamanhos de todas as filas.
|
|
*
|
|
* @return a soma dos tamanhos de todas as filas
|
|
*/
|
|
public int getTotalQueueSize() {
|
|
return trafficLights.values().stream()
|
|
.mapToInt(TrafficLight::getQueueSize)
|
|
.sum();
|
|
}
|
|
|
|
/**
|
|
* @return o identificador único desta interseção
|
|
*/
|
|
public String getId() {
|
|
return id;
|
|
}
|
|
|
|
/**
|
|
* @return o número total de veículos que chegaram a esta interseção
|
|
*/
|
|
public int getTotalVehiclesReceived() {
|
|
return totalVehiclesReceived;
|
|
}
|
|
|
|
/**
|
|
* @return o número total de veículos que partiram desta interseção
|
|
*/
|
|
public int getTotalVehiclesSent() {
|
|
return totalVehiclesSent;
|
|
}
|
|
|
|
/**
|
|
* Incrementa o contador de veículos que partiram com sucesso.
|
|
* Tipicamente chamado após um veículo completar a travessia.
|
|
*/
|
|
public void incrementVehiclesSent() {
|
|
totalVehiclesSent++;
|
|
}
|
|
|
|
/**
|
|
* @return a média do tempo de espera dos veículos nesta interseção
|
|
*/
|
|
public double getAverageWaitingTime() {
|
|
return averageWaitingTime;
|
|
}
|
|
|
|
/**
|
|
* Atualiza a média do tempo de espera com uma nova amostra.
|
|
* Usa a fórmula: Nova Média = (Média Antiga * (N-1) + Novo Valor) / N
|
|
*
|
|
* @param newTime tempo de espera (em segundos) do veículo que acabou de partir
|
|
*/
|
|
public void updateAverageWaitingTime(double newTime) {
|
|
if (totalVehiclesSent > 0) {
|
|
averageWaitingTime = (averageWaitingTime * (totalVehiclesSent - 1) + newTime)
|
|
/ totalVehiclesSent;
|
|
} else if (totalVehiclesSent == 1) {
|
|
averageWaitingTime = newTime;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return representação textual do estado atual da interseção
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
return String.format(
|
|
"Intersection{id='%s', lights=%d, queues=%d, received=%d, sent=%d}",
|
|
id,
|
|
trafficLights.size(),
|
|
getTotalQueueSize(),
|
|
totalVehiclesReceived,
|
|
totalVehiclesSent
|
|
);
|
|
}
|
|
} |