1 Commits

Author SHA1 Message Date
128e2e2366 pre-build dash 2025-10-22 22:55:48 +01:00
7 changed files with 36 additions and 237 deletions

View File

@@ -1,61 +0,0 @@
name: Java CI with Maven
on:
push:
branches: [ "main" ]
tags:
- 'v*.*.*'
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn -B package
working-directory: main
- name: Upload built JAR
uses: actions/upload-artifact@v4
with:
name: package
path: main/target/*.jar
- name: Generate dependency graph
run: mvn -B -f main/pom.xml com.github.ferstl:depgraph-maven-plugin:4.0.1:graph
- name: Upload dependency graph artifact
uses: actions/upload-artifact@v4
with:
name: dependency-graph
path: main/target/**
publish-release:
runs-on: ubuntu-latest
needs: [build]
if: startsWith(github.ref, 'refs/tags/')
permissions:
contents: write
steps:
- name: Download built JAR
uses: actions/download-artifact@v4
with:
name: package
path: main/target/
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: main/target/*.jar

2
.gitignore vendored
View File

@@ -47,4 +47,4 @@ build/
# Other # Other
*.swp *.swp
*.pdf *.pdf

View File

@@ -1,134 +0,0 @@
# 🏁 Single-Process Prototype — Implementation Summary
**Status:** ✅ Complete
**Date:** October 22, 2025
**Branch:** `8-single-process-prototype`
---
## Overview
The single-process prototype implements a **discrete event simulation (DES)** of a 3×3 urban grid with five intersections, realistic vehicle behavior, and fully synchronized traffic lights. Everything runs under one process, laying the groundwork for the distributed architecture in Phase 3.
---
## Core Architecture
### **SimulationEngine**
Drives the DES loop with a priority queue of timestamped events — vehicles, lights, crossings, and periodic stats updates. Handles five intersections (Cr1Cr5) and six event types.
**Main loop:**
```
while (events && time < duration):
event = nextEvent()
time = event.timestamp
handle(event)
```
### **VehicleGenerator**
Spawns vehicles via:
* **Poisson arrivals** (λ = 0.5 veh/s) or fixed intervals
* **Probabilistic routes** from E1E3
* **Type distribution**: 20% BIKE, 60% LIGHT, 20% HEAVY
### **StatisticsCollector**
Tracks system-wide and per-type metrics: throughput, avg. wait, queue sizes, light cycles — updated every 10 s and at simulation end.
---
## Model Highlights
* **Vehicle** type, route, timings, lifecycle.
* **Intersection** routing tables, traffic lights, queues.
* **TrafficLight** red/green cycles with FIFO queues.
* **Event** timestamped, comparable; 6 types for all DES actions.
---
## Configuration (`simulation.properties`)
```properties
simulation.duration=60.0
simulation.arrival.model=POISSON
simulation.arrival.rate=0.5
vehicle.bike.crossingTime=1.5
vehicle.light.crossingTime=2.0
vehicle.heavy.crossingTime=4.0
statistics.update.interval=10.0
```
**Speed logic:**
`t_bike = 0.5×t_car`, `t_heavy = 2×t_car`.
---
## Topology
```
E1→Cr1→Cr4→Cr5→S
E2→Cr2→Cr5→S
E3→Cr3→S
Bi-dir: Cr1↔Cr2, Cr2↔Cr3
```
---
## Results
**Unit Tests:** 7/7 ✅
**60-Second Simulation:**
* Generated: 22 vehicles
* Completed: 5 (22.7%)
* Avg system time: 15.47 s
* Throughput: 0.08 veh/s
* All lights & intersections operational
**Performance:**
~0.03 s real-time run (≈2000× speed-up), < 50 MB RAM.
---
## Code Structure
```
sd/
├── engine/SimulationEngine.java
├── model/{Vehicle,Intersection,TrafficLight,Event}.java
├── util/{VehicleGenerator,StatisticsCollector}.java
└── config/SimulationConfig.java
```
---
## Key Flow
1. Initialize intersections, lights, first events.
2. Process events chronologically.
3. Vehicles follow routes queue cross exit.
4. Lights toggle, queues drain, stats update.
5. Print summary and performance metrics.
---
## Next Steps — Phase 3
* Split intersections into independent **processes**.
* Add **socket-based communication**.
* Run **traffic lights as threads**.
* Enable **distributed synchronization** and fault handling.
---
## TL;DR
Solid single-process DES
Everythings working traffic lights, routing, vehicles, stats.
Ready to go distributed next.

27
TODO.md
View File

@@ -1,26 +1,3 @@
## ✅ SINGLE-PROCESS PROTOTYPE - COMPLETED
### Phase 2 Status: DONE ✅
All components for the single-process prototype have been successfully implemented and tested:
-**SimulationEngine** - Priority queue-based discrete event simulation
-**VehicleGenerator** - Poisson and Fixed arrival models
-**StatisticsCollector** - Comprehensive metrics tracking
-**Entry point** - Main simulation runner
-**60s test simulation** - Successfully validated event processing and routing
### Test Results:
- All 7 unit tests passing
- 60-second simulation completed successfully
- Generated 22 vehicles with 5 completing their routes
- Traffic light state changes working correctly
- Vehicle routing through intersections validated
---
## NEXT: Distributed Architecture Implementation
### Compreender os Conceitos Fundamentais ### Compreender os Conceitos Fundamentais
Primeiro, as tecnologias e paradigmas chave necessários para este projeto devem ser totalmente compreendidos. Primeiro, as tecnologias e paradigmas chave necessários para este projeto devem ser totalmente compreendidos.
@@ -39,7 +16,7 @@ Primeiro, as tecnologias e paradigmas chave necessários para este projeto devem
- Uma **lista de eventos** central, frequentemente uma fila de prioridades, será necessária para armazenar eventos futuros, ordenados pelo seu timestamp. O ciclo principal da simulação retira o próximo evento da lista, processa-o e adiciona quaisquer novos eventos que resultem dele. - Uma **lista de eventos** central, frequentemente uma fila de prioridades, será necessária para armazenar eventos futuros, ordenados pelo seu timestamp. O ciclo principal da simulação retira o próximo evento da lista, processa-o e adiciona quaisquer novos eventos que resultem dele.
- **Processo de Poisson:** Para o modelo 'mais realista' de chegadas de veículos, é especificado um processo de Poisson. A principal conclusão é que o tempo _entre_ chegadas consecutivas de veículos segue uma **distribuição exponencial**. Em Java, este intervalo pode ser gerado usando `Math.log(1 - Math.random()) / -lambda`, onde `lambda` (λi) é a taxa de chegada especificada. - **Processo de Poisson:** Para o modelo "mais realista" de chegadas de veículos, é especificado um processo de Poisson. A principal conclusão é que o tempo _entre_ chegadas consecutivas de veículos segue uma **distribuição exponencial**. Em Java, este intervalo pode ser gerado usando `Math.log(1 - Math.random()) / -lambda`, onde `lambda` (λi) é a taxa de chegada especificada.
--- ---
@@ -195,4 +172,4 @@ Assim que o sistema completo estiver a funcionar, as experiências exigidas pela
- **Debugging:** Debugging de sistemas distribuídos podem ser difíceis. Uma framework de logging (como Log4j 2 ou SLF4J) pode ser usada para registar eventos//alterações de estado nos diferentes processos. - **Debugging:** Debugging de sistemas distribuídos podem ser difíceis. Uma framework de logging (como Log4j 2 ou SLF4J) pode ser usada para registar eventos//alterações de estado nos diferentes processos.
- **Configuração:** Valores como endereços IP, números de porta ou parâmetros da simulação não devem ser "hardcoded". Um ficheiro de configuração (ex: um ficheiro `.properties` ou `.json`) torna a aplicação mais fácil de executar e testar. - **Configuração:** Valores como endereços IP, números de porta ou parâmetros da simulação não devem ser "hardcoded". Um ficheiro de configuração (ex: um ficheiro `.properties` ou `.json`) torna a aplicação mais fácil de executar e testar.

View File

@@ -31,7 +31,7 @@ public class SimulationConfig {
* (por exemplo quando executado a partir do classpath/jar), * (por exemplo quando executado a partir do classpath/jar),
* faz fallback para carregar a partir do classpath usando o ClassLoader. * faz fallback para carregar a partir do classpath usando o ClassLoader.
*/ */
IOException lastException = null; //FIXME: melhorar esta parte para reportar erros de forma mais clara IOException lastException = null;
try { try {
try (InputStream input = new FileInputStream(filePath)) { try (InputStream input = new FileInputStream(filePath)) {

View File

@@ -264,19 +264,32 @@ public class SimulationEngine {
*/ */
private void processEvent(Event event) { private void processEvent(Event event) {
switch (event.getType()) { switch (event.getType()) {
case VEHICLE_GENERATION -> handleVehicleGeneration(); case VEHICLE_GENERATION:
handleVehicleGeneration();
break;
case VEHICLE_ARRIVAL -> handleVehicleArrival(event); case VEHICLE_ARRIVAL:
handleVehicleArrival(event);
break;
case TRAFFIC_LIGHT_CHANGE -> handleTrafficLightChange(event); case TRAFFIC_LIGHT_CHANGE:
handleTrafficLightChange(event);
break;
case CROSSING_START -> handleCrossingStart(event); case CROSSING_START:
handleCrossingStart(event);
break;
case CROSSING_END -> handleCrossingEnd(event); case CROSSING_END:
handleCrossingEnd(event);
break;
case STATISTICS_UPDATE -> handleStatisticsUpdate(); case STATISTICS_UPDATE:
handleStatisticsUpdate();
break;
default -> System.err.println("Unknown event type: " + event.getType()); default:
System.err.println("Unknown event type: " + event.getType());
} }
} }
@@ -373,7 +386,7 @@ public class SimulationEngine {
* @param vehicle The vehicle to process. * @param vehicle The vehicle to process.
* @param intersection The intersection where the vehicle is. * @param intersection The intersection where the vehicle is.
*/ */
private void tryProcessVehicle(Vehicle vehicle, Intersection intersection) { //FIXME private void tryProcessVehicle(Vehicle vehicle, Intersection intersection) {
// Find the direction (and light) this vehicle is queued at // Find the direction (and light) this vehicle is queued at
// This logic is a bit flawed: it just finds the *first* non-empty queue // This logic is a bit flawed: it just finds the *first* non-empty queue
// A better approach would be to get the light from the vehicle's route // A better approach would be to get the light from the vehicle's route
@@ -578,12 +591,16 @@ public class SimulationEngine {
* @return The crossing time in seconds. * @return The crossing time in seconds.
*/ */
private double getCrossingTime(VehicleType type) { private double getCrossingTime(VehicleType type) {
return switch (type) { switch (type) {
case BIKE -> config.getBikeVehicleCrossingTime(); case BIKE:
case LIGHT -> config.getLightVehicleCrossingTime(); return config.getBikeVehicleCrossingTime();
case HEAVY -> config.getHeavyVehicleCrossingTime(); case LIGHT:
default -> 2.0; return config.getLightVehicleCrossingTime();
}; // Default fallback case HEAVY:
return config.getHeavyVehicleCrossingTime();
default:
return 2.0; // Default fallback
}
} }
/** /**

View File

@@ -43,7 +43,7 @@ class SimulationTest {
assertEquals("TEST1", vehicle.getId()); assertEquals("TEST1", vehicle.getId());
assertNotNull(vehicle.getType()); assertNotNull(vehicle.getType());
assertNotNull(vehicle.getRoute()); assertNotNull(vehicle.getRoute());
assertTrue(!vehicle.getRoute().isEmpty()); assertTrue(vehicle.getRoute().size() > 0);
} }
@Test @Test