7 Commits

Author SHA1 Message Date
David Alves
30fc2d6554 Merge pull request #1 from davidalves04/leo
Feat: Implement core discrete-event simulation logic and external configuration
2025-10-21 11:32:16 +01:00
Leandro Afonso
d41973d27f added bike//heavy prob & cross time 2025-10-21 11:19:40 +01:00
Leandro Afonso
ce226f261a added intersect, vehicle and light logic + random poisson dist 2025-10-21 11:11:56 +01:00
874fd53a21 Diagrama de Arquitetura 2025-10-20 12:35:15 +01:00
David Alves
19bf313c81 Actualizar Diagrama de arquitetura - SD.drawio 2025-10-20 12:00:44 +01:00
David Alves
cfb24b21bf Diagrama de arquitetura - SD.drawio 2025-10-20 11:50:37 +01:00
David Alves
b9991ba6ba Adicionado Diagrama de arquitetura - SD.drawio 2025-10-20 11:49:32 +01:00
10 changed files with 807 additions and 39 deletions

50
.gitignore vendored Normal file
View File

@@ -0,0 +1,50 @@
# Compiled class files
*.class
# Log files
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# VS Code settings
.vscode/
# Eclipse files
*.pydevproject
.project
.classpath
.cproject
.settings/
bin/
tmp/
# IntelliJ IDEA files
*.iml
.idea/
out/
# Mac system files
.DS_Store
# Windows system files
Thumbs.db
# Maven
target/
# Gradle
.gradle/
build/
# Other
*.swp
*.pdf

View File

@@ -0,0 +1,27 @@
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" version="28.2.7">
<diagram name="Página-1" id="B1_hHcevBzWlEwI7FSV6">
<mxGraphModel dx="778" dy="476" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="vcp7vux32DhQR4tKQhnF-8" value="Dashboard" style="sketch=0;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=#C73500;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;fillColor=#fa6800;shape=mxgraph.mscae.oms.dashboard;fontColor=#000000;" vertex="1" parent="1">
<mxGeometry x="389" y="230" width="50" height="41" as="geometry" />
</mxCell>
<mxCell id="vcp7vux32DhQR4tKQhnF-12" value="Semaforo.java" style="shape=image;html=1;verticalAlign=top;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;imageAspect=0;aspect=fixed;image=https://icons.diagrams.net/icon-cache1/Strabo-2829/traffic_light-1068.png" vertex="1" parent="1">
<mxGeometry x="230" y="350" width="53" height="53" as="geometry" />
</mxCell>
<mxCell id="vcp7vux32DhQR4tKQhnF-13" value="" style="endArrow=classic;startArrow=classic;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="310" y="330" as="sourcePoint" />
<mxPoint x="360" y="280" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="vcp7vux32DhQR4tKQhnF-14" value="CruzamentoServer.java" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=1;points=[];movable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;" vertex="1" connectable="0" parent="vcp7vux32DhQR4tKQhnF-13">
<mxGeometry x="-0.3933" relative="1" as="geometry">
<mxPoint x="25" y="25" as="offset" />
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -0,0 +1,172 @@
<?xml version='1.0' encoding='utf-8'?>
<mxfile host="app.diagrams.net" agent="Gemini" version="28.2.7">
<diagram name="Arquitetura-Sistema-Trafego" id="L-jWkP8vD7q_2fM6N-yC">
<mxGraphModel dx="1434" dy="746" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1654" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="E1-process" value="Processo Gerador E1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="140" y="100" width="140" height="60" as="geometry" />
</mxCell>
<mxCell id="E2-process" value="Processo Gerador E2" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="430" y="100" width="140" height="60" as="geometry" />
</mxCell>
<mxCell id="E3-process" value="Processo Gerador E3" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="720" y="100" width="140" height="60" as="geometry" />
</mxCell>
<mxCell id="Cr1-process" value="Processo Cruzamento (Cr1)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;verticalAlign=top;spacingTop=5;" vertex="1" parent="1">
<mxGeometry x="140" y="240" width="140" height="100" as="geometry" />
</mxCell>
<mxCell id="Cr1-thread1" value="Thread Semáforo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr1-process">
<mxGeometry x="20" y="30" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="Cr1-thread2" value="Thread Semáforo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr1-process">
<mxGeometry x="20" y="65" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="Cr2-process" value="Processo Cruzamento (Cr2)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;verticalAlign=top;spacingTop=5;" vertex="1" parent="1">
<mxGeometry x="430" y="240" width="140" height="140" as="geometry" />
</mxCell>
<mxCell id="Cr2-thread1" value="Thread Semáforo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr2-process">
<mxGeometry x="20" y="30" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="Cr2-thread2" value="Thread Semáforo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr2-process">
<mxGeometry x="20" y="65" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="Cr2-thread3" value="Thread Semáforo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr2-process">
<mxGeometry x="20" y="100" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="Cr3-process" value="Processo Cruzamento (Cr3)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;verticalAlign=top;spacingTop=5;" vertex="1" parent="1">
<mxGeometry x="720" y="240" width="140" height="140" as="geometry" />
</mxCell>
<mxCell id="Cr3-thread1" value="Thread Semáforo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr3-process">
<mxGeometry x="20" y="30" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="Cr3-thread2" value="Thread Semáforo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr3-process">
<mxGeometry x="20" y="65" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="Cr3-thread3" value="Thread Semáforo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr3-process">
<mxGeometry x="20" y="100" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="Cr4-process" value="Processo Cruzamento (Cr4)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;verticalAlign=top;spacingTop=5;" vertex="1" parent="1">
<mxGeometry x="140" y="460" width="140" height="100" as="geometry" />
</mxCell>
<mxCell id="Cr4-thread1" value="Thread Semáforo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr4-process">
<mxGeometry x="20" y="30" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="Cr4-thread-peao" value="Thread Semáforo (Peões)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr4-process">
<mxGeometry x="20" y="65" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="Cr5-process" value="Processo Cruzamento (Cr5)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;verticalAlign=top;spacingTop=5;" vertex="1" parent="1">
<mxGeometry x="430" y="460" width="140" height="100" as="geometry" />
</mxCell>
<mxCell id="Cr5-thread1" value="Thread Semáforo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr5-process">
<mxGeometry x="20" y="30" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="Cr5-thread2" value="Thread Semáforo" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="Cr5-process">
<mxGeometry x="20" y="65" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="S-process" value="Processo Saída (S)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
<mxGeometry x="720" y="460" width="140" height="60" as="geometry" />
</mxCell>
<mxCell id="dashboard-server" value="Servidor Dashboard" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1">
<mxGeometry x="430" y="640" width="140" height="80" as="geometry" />
</mxCell>
<mxCell id="arrow-E1-Cr1" value="Fluxo Veículos&lt;br&gt;(Sockets/Middleware)" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;fontSize=10;align=left;verticalAlign=bottom;" edge="1" parent="1" source="E1-process" target="Cr1-process">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="arrow-E2-Cr2" value="Fluxo Veículos&lt;br&gt;(Sockets/Middleware)" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;fontSize=10;align=left;verticalAlign=bottom;" edge="1" parent="1" source="E2-process" target="Cr2-process">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="arrow-E3-Cr3" value="Fluxo Veículos&lt;br&gt;(Sockets/Middleware)" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;fontSize=10;align=left;verticalAlign=bottom;" edge="1" parent="1" source="E3-process" target="Cr3-process">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="arrow-Cr1-Cr4" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;" edge="1" parent="1" source="Cr1-process" target="Cr4-process">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="arrow-Cr2-Cr5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;" edge="1" parent="1" source="Cr2-process" target="Cr5-process">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="arrow-Cr4-Cr5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;" edge="1" parent="1" source="Cr4-process" target="Cr5-process">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="arrow-Cr5-S" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;" edge="1" parent="1" source="Cr5-process" target="S-process">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="arrow-Cr3-S" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;" edge="1" parent="1" source="Cr3-process" target="S-process">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="arrow-Cr1-Cr2" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;" edge="1" parent="1" source="Cr1-process" target="Cr2-process">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="280" y="290" />
<mxPoint x="430" y="290" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="arrow-Cr2-Cr1" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;" edge="1" parent="1" source="Cr2-process" target="Cr1-process">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="430" y="310" />
<mxPoint x="280" y="310" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="arrow-Cr2-Cr3" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;" edge="1" parent="1" source="Cr2-process" target="Cr3-process">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="570" y="290" />
<mxPoint x="720" y="290" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="arrow-Cr3-Cr2" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;" edge="1" parent="1" source="Cr3-process" target="Cr2-process">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="720" y="310" />
<mxPoint x="570" y="310" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="stats-Cr1-Dash" value="Envio de Estatísticas" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;dashed=1;strokeColor=#9673a6;fontSize=10;verticalAlign=bottom;" edge="1" parent="1" source="Cr1-process" target="dashboard-server">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="210" y="680" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="stats-Cr2-Dash" value="Envio de Estatísticas" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;dashed=1;strokeColor=#9673a6;fontSize=10;verticalAlign=bottom;" edge="1" parent="1" source="Cr2-process" target="dashboard-server">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="stats-Cr3-Dash" value="Envio de Estatísticas" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;dashed=1;strokeColor=#9673a6;fontSize=10;verticalAlign=bottom;" edge="1" parent="1" source="Cr3-process" target="dashboard-server">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="790" y="680" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="stats-Cr4-Dash" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;dashed=1;strokeColor=#9673a6;" edge="1" parent="1" source="Cr4-process" target="dashboard-server">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="210" y="680" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="stats-Cr5-Dash" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;dashed=1;strokeColor=#9673a6;" edge="1" parent="1" source="Cr5-process" target="dashboard-server">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="stats-S-Dash" value="Estatísticas Globais" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;endFill=1;dashed=1;strokeColor=#9673a6;fontSize=10;verticalAlign=bottom;" edge="1" parent="1" source="S-process" target="dashboard-server">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="790" y="680" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="legend" value="Legenda simplificada (removida tabela)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#999999;" vertex="1" parent="1">
</mxCell>
<mxCell id="title" value="Diagrama de Arquitetura - Simulador de Tráfego Distribuído" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="290" y="40" width="420" height="30" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -81,6 +81,18 @@ public class SimulationConfig {
return Double.parseDouble(properties.getProperty("vehicle.crossing.time.light", "2.0"));
}
public double getBikeVehicleProbability() {
return Double.parseDouble(properties.getProperty("vehicle.probability.bike", "0.0"));
}
public double getBikeVehicleCrossingTime() {
return Double.parseDouble(properties.getProperty("vehicle.crossing.time.bike", "1.5"));
}
public double getHeavyVehicleProbability() {
return Double.parseDouble(properties.getProperty("vehicle.probability.heavy", "0.0"));
}
public double getHeavyVehicleCrossingTime() {
return Double.parseDouble(properties.getProperty("vehicle.crossing.time.heavy", "4.0"));
}

View File

@@ -0,0 +1,132 @@
package sd.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Represents an intersection in the traffic simulation.
*
* Each intersection coordinates multiple traffic lights - one for each direction -
* and handles routing vehicles based on their next destination.
*/
public class Intersection {
// Identity and configuration
private final String id; // ex. "Cr1", "Cr2"
private final Map<String, TrafficLight> trafficLights; // direction -> light
private final Map<String, String> routing; // destination -> direction
// Stats
private int totalVehiclesReceived;
private int totalVehiclesSent;
private double averageWaitingTime;
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;
}
/**
* Registers a traffic light under this intersection.
* The light is identified by its direction (ex., "North", "East").
*/
public void addTrafficLight(TrafficLight trafficLight) {
trafficLights.put(trafficLight.getDirection(), trafficLight);
}
/**
* Defines how vehicles should be routed through this intersection.
*
* @param nextDestination The next intersection or exit on the vehicle's route
* @param direction The direction (traffic light) vehicles should take
*/
public void configureRoute(String nextDestination, String direction) {
routing.put(nextDestination, direction);
}
/**
* Accepts an incoming vehicle and places it in the correct queue.
* If the route or traffic light can't be found, logs an error.
*/
public void receiveVehicle(Vehicle vehicle) {
totalVehiclesReceived++;
String nextDestination = vehicle.getCurrentDestination();
String direction = routing.get(nextDestination);
if (direction != null && trafficLights.containsKey(direction)) {
trafficLights.get(direction).addVehicle(vehicle);
} else {
System.err.printf(
"Routing error: could not place vehicle %s (destination: %s)%n",
vehicle.getId(), nextDestination
);
}
}
/** Returns the traffic light controlling the given direction, if any. */
public TrafficLight getTrafficLight(String direction) {
return trafficLights.get(direction);
}
/** Returns all traffic lights belonging to this intersection. */
public List<TrafficLight> getTrafficLights() {
return new ArrayList<>(trafficLights.values());
}
/** Returns the total number of vehicles currently queued across all directions. */
public int getTotalQueueSize() {
return trafficLights.values().stream()
.mapToInt(TrafficLight::getQueueSize)
.sum();
}
// --- Stats and getters ---
public String getId() {
return id;
}
public int getTotalVehiclesReceived() {
return totalVehiclesReceived;
}
public int getTotalVehiclesSent() {
return totalVehiclesSent;
}
public void incrementVehiclesSent() {
totalVehiclesSent++;
}
public double getAverageWaitingTime() {
return averageWaitingTime;
}
/**
* Updates the running average waiting time with a new sample.
*/
public void updateAverageWaitingTime(double newTime) {
// Weighted incremental average (avoids recalculating from scratch)
averageWaitingTime = (averageWaitingTime * (totalVehiclesSent - 1) + newTime)
/ totalVehiclesSent;
}
@Override
public String toString() {
return String.format(
"Intersection{id='%s', lights=%d, queues=%d, received=%d, sent=%d}",
id,
trafficLights.size(),
getTotalQueueSize(),
totalVehiclesReceived,
totalVehiclesSent
);
}
}

View File

@@ -0,0 +1,180 @@
package sd.model;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Represents a single traffic light controlling one direction at an intersection.
*
* Each light maintains its own queue of vehicles and alternates between
* green and red states. It's designed to be thread-safe (maybe...), so multiple
* threads (like vehicles or controllers) can safely interact with it.
*/
public class TrafficLight {
// Identity and configuration
private final String id; // ex. "Cr1-N"
private final String direction; // ex. "North", "South", etc.
private TrafficLightState state;
// Vehicle management
private final Queue<Vehicle> queue;
// Synchronization primitives
private final Lock lock;
private final Condition vehicleAdded;
private final Condition lightGreen;
// Timing configuration (seconds)
private double greenTime;
private double redTime;
// Basic stats
private int totalVehiclesProcessed;
public TrafficLight(String id, String direction, double greenTime, double redTime) {
this.id = id;
this.direction = direction;
this.state = TrafficLightState.RED;
this.queue = new LinkedList<>();
this.lock = new ReentrantLock();
this.vehicleAdded = lock.newCondition();
this.lightGreen = lock.newCondition();
this.greenTime = greenTime;
this.redTime = redTime;
this.totalVehiclesProcessed = 0;
}
/**
* Adds a vehicle to the waiting queue.
* Signals any waiting threads that a new vehicle has arrived.
*/
public void addVehicle(Vehicle vehicle) {
lock.lock();
try {
queue.offer(vehicle);
vehicleAdded.signalAll();
} finally {
lock.unlock();
}
}
/**
* Attempts to let one vehicle pass through.
* Only works if the light is green; otherwise returns null.
*/
public Vehicle removeVehicle() {
lock.lock();
try {
if (state == TrafficLightState.GREEN && !queue.isEmpty()) {
Vehicle vehicle = queue.poll();
totalVehiclesProcessed++;
return vehicle;
}
return null;
} finally {
lock.unlock();
}
}
/**
* Changes the lights state (ex., RED -> GREEN).
* When the light turns green, waiting threads are notified.
* ¯\_(ツ)_/¯
*/
public void changeState(TrafficLightState newState) {
lock.lock();
try {
this.state = newState;
if (newState == TrafficLightState.GREEN) {
lightGreen.signalAll();
}
} finally {
lock.unlock();
}
}
/** Returns how many vehicles are currently queued. */
public int getQueueSize() {
lock.lock();
try {
return queue.size();
} finally {
lock.unlock();
}
}
/** Checks whether there are no vehicles waiting. */
public boolean isQueueEmpty() {
lock.lock();
try {
return queue.isEmpty();
} finally {
lock.unlock();
}
}
// --- Getters & Setters ---
public String getId() {
return id;
}
public String getDirection() {
return direction;
}
public TrafficLightState getState() {
lock.lock();
try {
return state;
} finally {
lock.unlock();
}
}
public double getGreenTime() {
return greenTime;
}
public void setGreenTime(double greenTime) {
this.greenTime = greenTime;
}
public double getRedTime() {
return redTime;
}
public void setRedTime(double redTime) {
this.redTime = redTime;
}
public int getTotalVehiclesProcessed() {
return totalVehiclesProcessed;
}
public Lock getLock() {
return lock;
}
public Condition getVehicleAdded() {
return vehicleAdded;
}
public Condition getLightGreen() {
return lightGreen;
}
@Override
public String toString() {
return String.format(
"TrafficLight{id='%s', direction='%s', state=%s, queueSize=%d}",
id, direction, state, getQueueSize()
);
}
}

View File

@@ -0,0 +1,117 @@
package sd.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a single vehicle moving through the simulation.
*
* Each vehicle has a route - a sequence of intersections it will pass through -
* and keeps track of how long it has waited and traveled overall.
*
* Serializable so it can be sent between processes or nodes over sockets. type shit
*/
public class Vehicle implements Serializable {
private static final long serialVersionUID = 1L;
// Identity and configuration
private final String id;
private final VehicleType type;
private final double entryTime; // When it entered the system
private final List<String> route; // ex., ["Cr1", "Cr3", "S"]
private int currentRouteIndex; // Current position in the route
// Metrics
private double totalWaitingTime; // Total time spent waiting at red lights
private double totalCrossingTime; // Time spent actually moving between intersections
public Vehicle(String id, VehicleType type, double entryTime, List<String> route) {
this.id = id;
this.type = type;
this.entryTime = entryTime;
this.route = new ArrayList<>(route);
this.currentRouteIndex = 0;
this.totalWaitingTime = 0.0;
this.totalCrossingTime = 0.0;
}
/**
* Moves the vehicle to the next stop in its route.
*
* @return true if there are still destinations ahead, false if the route is finished
*/
public boolean advanceRoute() {
currentRouteIndex++;
return currentRouteIndex < route.size();
}
/**
* Gets the current destination (the next intersection or exit).
* Returns null if the route is already complete.
*/
public String getCurrentDestination() {
return (currentRouteIndex < route.size()) ? route.get(currentRouteIndex) : null;
}
/** Returns true if the vehicle has completed its entire route. */
public boolean hasReachedEnd() {
return currentRouteIndex >= route.size();
}
// --- Getters and metrics management ---
public String getId() {
return id;
}
public VehicleType getType() {
return type;
}
public double getEntryTime() {
return entryTime;
}
public List<String> getRoute() {
return new ArrayList<>(route);
}
public int getCurrentRouteIndex() {
return currentRouteIndex;
}
public double getTotalWaitingTime() {
return totalWaitingTime;
}
public void addWaitingTime(double time) {
totalWaitingTime += time;
}
public double getTotalCrossingTime() {
return totalCrossingTime;
}
public void addCrossingTime(double time) {
totalCrossingTime += time;
}
/**
* Calculates how long the vehicle has been in the system so far.
*
* @param currentTime the current simulation time
* @return total elapsed time since the vehicle entered
*/
public double getTotalTravelTime(double currentTime) {
return currentTime - entryTime;
}
@Override
public String toString() {
return String.format(
"Vehicle{id='%s', type=%s, next='%s', route=%s}",
id, type, getCurrentDestination(), route
);
}
}

View File

@@ -0,0 +1,68 @@
package sd.util;
import java.util.Random;
/**
* Utility class for generating random values used throughout the simulation.
*
* Includes helpers for exponential distributions (for vehicle arrivals),
* uniform randoms, and probability-based decisions.
*/
public class RandomGenerator {
private static final Random random = new Random();
/**
* Returns a random time interval that follows an exponential distribution.
*
* Useful for modeling inter-arrival times in a Poisson process.
*
* @param lambda the arrival rate (λ)
* @return the time interval until the next arrival
*/
public static double generateExponentialInterval(double lambda) {
return Math.log(1 - random.nextDouble()) / -lambda;
}
/**
* Returns a random integer between {@code min} and {@code max}, inclusive.
*/
public static int generateRandomInt(int min, int max) {
return random.nextInt(max - min + 1) + min;
}
/**
* Returns a random double between {@code min} (inclusive) and {@code max} (exclusive).
*/
public static double generateRandomDouble(double min, double max) {
return min + (max - min) * random.nextDouble();
}
/**
* Returns {@code true} with the given probability.
*
* @param probability a value between 0.0 and 1.0
*/
public static boolean occursWithProbability(double probability) {
return random.nextDouble() < probability;
}
/**
* Picks a random element from the given array.
*
* @throws IllegalArgumentException if the array is empty
*/
public static <T> T chooseRandom(T[] array) {
if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
return array[random.nextInt(array.length)];
}
/**
* Sets the random generators seed, allowing reproducible results.
*/
public static void setSeed(long seed) {
random.setSeed(seed);
}
}

View File

@@ -1,8 +1,13 @@
# Traffic simulation configuration
# This file contains all the necessary configurations to run the simulation
# =========================================================
# Traffic Simulation Configuration
# ---------------------------------------------------------
# All parameters controlling network layout, timing,
# and simulation behavior.
# =========================================================
# === NETWORK CONFIGURATIONS ===
# Intersections
# === NETWORK CONFIGURATION ===
# Intersections (each with its host and port)
intersection.Cr1.host=localhost
intersection.Cr1.port=8001
intersection.Cr2.host=localhost
@@ -14,30 +19,32 @@ intersection.Cr4.port=8004
intersection.Cr5.host=localhost
intersection.Cr5.port=8005
# Exit Node
# Exit node
exit.host=localhost
exit.port=9001
# Dashboard
# Dashboard server
dashboard.host=localhost
dashboard.port=9000
# === SIMULATION CONFIGURATIONS ===
# Simulation duration in seconds (3600 = 1 hour)
# === SIMULATION CONFIGURATION ===
# Total duration in seconds (3600 = 1 hour)
simulation.duration=3600.0
# Vehicle arrival model: FIXED or POISSON
simulation.arrival.model=POISSON
# Arrival rate (λ) for Poisson model (vehicles per second)
# λ (lambda): average arrival rate (vehicles per second)
simulation.arrival.rate=0.5
# Fixed interval between arrivals (used if model = FIXED)
# Fixed interval between arrivals (only used if model=FIXED)
simulation.arrival.fixed.interval=2.0
# === TRAFFIC LIGHT CONFIGURATIONS ===
# Times in seconds for each traffic light (green and red)
# Format: trafficlight.<intersection>.<direction>.<state>
# === TRAFFIC LIGHT TIMINGS ===
# Format: trafficlight.<intersection>.<direction>.<state>=<seconds>
# Intersection 1
trafficlight.Cr1.North.green=30.0
@@ -89,15 +96,18 @@ trafficlight.Cr5.East.red=30.0
trafficlight.Cr5.West.green=30.0
trafficlight.Cr5.West.red=30.0
# === VEHICLE CONFIGURATIONS ===
# Probability of generating a light vehicle (0.0 to 1.0)
# The rest will be heavy vehicles
vehicle.probability.light=0.7
# === VEHICLE CONFIGURATION ===
# Probability distribution for vehicle types (must sum to 1.0)
vehicle.probability.bike=0.2
vehicle.probability.light=0.6
vehicle.probability.heavy=0.2
# Crossing time in seconds
# Average crossing times (in seconds)
vehicle.crossing.time.bike=1.5
vehicle.crossing.time.light=2.0
vehicle.crossing.time.heavy=4.0
# === STATISTICS CONFIGURATIONS ===
# Interval to send updates to the dashboard (in seconds)
# === STATISTICS ===
# Interval between dashboard updates (seconds)
statistics.update.interval=10.0

Binary file not shown.