package de.hems.trafficsim; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Observable; import java.util.concurrent.Semaphore; /** * Main model class of TrafficSim. Represents a round course containing vehicles. */ public class Track { /** * list a vehicles on the track */ final protected List vehicles; /** * list of resulting time records of the simulation */ final protected List> vtrList; /** * length of the track */ final protected float trackLength; /** * sum of all vehicle speeds during the simulation, used for average calculation */ protected float sumAvgMemory; /** * sum of all vehicle speeds during the simulation ignoring the first ten steps, * used for average calculation */ protected float sumDelAvgMemory; /** * length of the history kept */ final protected int historyLength; /** * average over all velocities in the simulation */ protected float overallAvg; /** * average over all velocities in the simulation, ignoring the first ten steps */ protected float delayedAvg; /** * average over all velocities in the last step */ protected float lastAvg; /** * current configured wait time between two simulation steps */ protected int waitTime; /** * currently configured max velocity for all vehicles */ final protected float maxVelocity; /** * currently configured brake probability for all vehicles */ final protected float brakeProb; /** * counter for executed simulation steps */ protected long steps; /** * semaphore protecting the vtrlist */ final protected Semaphore listSemaphore; /** * Constructor for a new Track. * * @param numberVehicles number of vehicles on the Track * @param trackLength length of the new Track * @param brakeProb probability of a vehicle to suddenly brake without reason * @param maxVelocity maxmimum velocity of the vehicles * @param waitTime time between two simulation steps to slow down the simulation artificially * @param historyLength length of the history to keep */ public Track(int numberVehicles, float trackLength, float brakeProb, float maxVelocity, int waitTime, int historyLength) { this.trackLength = trackLength; this.brakeProb = brakeProb; this.maxVelocity = maxVelocity; this.vehicles = createVehiclesList(numberVehicles); this.vtrList = new LinkedList<>(); this.sumAvgMemory = 0; this.sumDelAvgMemory = 0; this.overallAvg = 0; this.delayedAvg = 0; this.lastAvg = 0; this.historyLength = historyLength; this.waitTime = waitTime; this.steps = 0; this.listSemaphore = new Semaphore(1); } /** * Getter for vtrList * * @return vtrList */ public List> getVtrList() { return vtrList; } /** * Getter for overallAvg * * @return overallAvg */ public float getOverallAvg() { return overallAvg; } /** * Getter for lastAvg * * @return lastAvg */ public float getLastAvg() { return lastAvg; } /** * Getter for delayedAvg * * @return delayedAvg */ public float getDelayedAvg() { return delayedAvg; } /** * Getter for trackLength * * @return trackLength */ public float getTrackLength() { return trackLength; } /** * Getter for steps * * @return steps */ public long getSteps() { return steps; } /** * Getter for listSemaphore * * @return listSemaphore */ public Semaphore getListSemaphore() { return listSemaphore; } /** * Getter for historyLength * * @return historyLength */ public int getHistoryLength() { return historyLength; } /** * Utility function to add vehicles to the Track. * * @param numberVehicles number of vehicles to add * @return filled list with vehicles */ protected List createVehiclesList(int numberVehicles) { List result = new ArrayList<>(); for (int i = 0; i < numberVehicles; i++) { Vehicle vehicle = new Vehicle(i, i, this.maxVelocity, this.brakeProb, this.trackLength); result.add(vehicle); } return result; } /** * Update the wait time of the simulation. * * @param waitTime new wait time in ms */ public void setWaitTime(int waitTime) { this.waitTime = waitTime; } /** * Update the brake probability of all vehicles. * * @param brakeProb new brake probability */ public void setBrakeProb(float brakeProb) { for (Vehicle v : this.vehicles) { v.setBrakeProb(brakeProb); } } /** * Update the maximum velocity of all vehicles. * * @param maxVelocity new maximum velocity */ public void setMaxVelocity(float maxVelocity) { for (Vehicle v : this.vehicles) { v.setMaxVelocity(maxVelocity); } } /** * Calculates on simulation step ahead and then waits for the configured wait time. */ public void timeElapse() { for (int i = 0; i < vehicles.size(); i++) { Vehicle v = vehicles.get(i); int forerunnerIndex = i + 1; if (forerunnerIndex >= vehicles.size()) { forerunnerIndex -= vehicles.size(); } Vehicle forerunner = vehicles.get(forerunnerIndex); float distanceForerunner = forerunner.getPosition() - v.getPosition() - 1; if (distanceForerunner < 0.0) { distanceForerunner += this.trackLength; } v.updateVelocity(distanceForerunner); } try { this.listSemaphore.acquire(); } catch (InterruptedException ex) {return;} List records = new ArrayList<>(vehicles.size()); this.vtrList.add(records); if (this.vtrList.size() > this.historyLength) { this.vtrList.remove(0); } for(Vehicle v: vehicles){ v.timeElapse(); VehicleTimeRecord vtr = new VehicleTimeRecord(v.position, v.curVelocity, v.maxVelocity); records.add(vtr); } steps++; this.listSemaphore.release(); update_avg(); try { Thread.sleep(waitTime); } catch (InterruptedException ignored) { } } /** * Returns the average velocity of the given simulation step. * * @param step index of the step in the history list * @return average velocity */ public float avg_step(int step) { float sum_step = 0; for (VehicleTimeRecord r : vtrList.get(step)) { sum_step += r.velocity; } return sum_step / vehicles.size(); } /** * Utility function which updates the averages values with the results from the last simulation * step. */ protected void update_avg() { lastAvg = avg_step(vtrList.size() - 1); if (this.steps > 10) { sumDelAvgMemory += lastAvg; delayedAvg = sumDelAvgMemory / (this.steps - 10); } sumAvgMemory += lastAvg; overallAvg = sumAvgMemory / this.steps; } }