Files
SD/main/src/main/java/sd/model/Intersection.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
);
}
}