resetting route planner

This commit is contained in:
Stephan Richter
2021-03-13 13:19:49 +01:00
parent 5b2bf1ddc0
commit 9939d8d630
7 changed files with 20 additions and 389 deletions

View File

@@ -1,98 +0,0 @@
package de.srsoftware.web4rail.threads;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.srsoftware.web4rail.BaseClass;
import de.srsoftware.web4rail.Route;
import de.srsoftware.web4rail.moving.Train;
/**
* @author Stephan Richter, SRSoftware
*
*/
public class BrakeProcessor extends BaseClass implements Runnable {
private enum State {
IDLE, BRAKING, ABORTED, ENDED;
}
private static final Logger LOG = LoggerFactory.getLogger(BrakeProcessor.class);
public static int defaultEndSpeed;
private Train train;
private State state = State.IDLE;
private long measuredDistance;
private long lastTime;
private Integer brakeTime;
private int startSpeed;
public BrakeProcessor(Train train) {
this.train = train;
Thread thread = new Thread(this);
thread.setName(getClass().getSimpleName());
thread.start();
}
public void end() {
state = State.ENDED;
measuredDistance += train.speed * (BaseClass.timestamp() - lastTime);
train.setSpeed(0);
Route route = train.route();
if (isNull(route)) return;
LOG.debug("old brake time: {}, measured distance: {}", brakeTime, measuredDistance);
int step = brakeTime;
for (int i = 0; i < 15; i++) {
long calculatedDistance = calculate(brakeTime, startSpeed);
if (measuredDistance > calculatedDistance) {
brakeTime += brakeTime;
step = brakeTime/3;
}
if (measuredDistance < calculatedDistance) {
step /= 2;
if (step < 1) step = 1;
brakeTime -= step;
}
LOG.debug("new brake time: {}, calculated distance: {}", brakeTime, calculatedDistance);
}
route.brakeTime(train.brakeId(), brakeTime);
}
private static long calculate(int brakeTime, int speed) {
long dist = 0;
while (speed > defaultEndSpeed) {
dist += speed * brakeTime;
speed -= 10;
}
return dist;
}
@Override
public void run() {
LOG.debug("run()");
Route route = train.route();
if (isNull(route)) return;
brakeTime = route.brakeTime(train.brakeId());
if (isNull(brakeTime)) brakeTime = 250;
state = State.BRAKING;
measuredDistance = 0;
lastTime = BaseClass.timestamp();
startSpeed = train.speed;
int targetSpeed = defaultEndSpeed;
while (state == State.BRAKING) {
sleep(brakeTime);
long newTime = BaseClass.timestamp();
if (isNull(train.route())) state = State.ABORTED;
if (state != State.BRAKING) break;
measuredDistance += train.speed * (newTime - lastTime);
int newSpeed = train.speed - 10;
if (newSpeed < targetSpeed) {
train.setSpeed(targetSpeed);
break;
}
train.setSpeed(newSpeed);
lastTime = newTime;
}
LOG.debug("{} reached final speed.", train);
}
}

View File

@@ -1,185 +0,0 @@
package de.srsoftware.web4rail.threads;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.Vector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.srsoftware.web4rail.BaseClass;
import de.srsoftware.web4rail.Plan.Direction;
import de.srsoftware.web4rail.Route;
import de.srsoftware.web4rail.moving.Train;
import de.srsoftware.web4rail.tiles.Block;
/**
* @author Stephan Richter, SRSoftware 2020-2021
*/
public abstract class PathFinder extends BaseClass implements Runnable{
public static final Logger LOG = LoggerFactory.getLogger(PathFinder.class);
// private Context context;
private boolean aborted = false;
private Direction direction;
private Block startBlock;
private Train train;
public PathFinder(Train train, Block start, Direction direction) {
this.train = train;
this.startBlock = start;
this.direction = direction;
Thread thread = new Thread(this);
thread.setName("Pathfinder("+train+")");
thread.start();
}
public void abort() {
aborted = true;
aborted();
LOG.debug("aborted {}",this);
}
private static TreeMap<Integer,List<Route>> availableRoutes(Train train, Block start, Direction startDir, HashSet<Route> visitedRoutes){
String inset = "";
for (int i=0; i<visitedRoutes.size(); i++) inset+=" ";
LOG.debug(inset+"PathFinder.availableRoutes({})",visitedRoutes);
boolean error = false;
if (isNull(start)) {
LOG.warn("{} → {}.availableRoutes called without start block!",inset,Train.class.getSimpleName());
error = true;
}
if (isNull(train)) {
LOG.warn("{}→ {}.availableRoutes called without train!",inset,Train.class.getSimpleName());
error = true;
}
if (error) return new TreeMap<Integer, List<Route>>();
if (isSet(startDir)) {
LOG.debug("{}Looking for {}-bound routes from {}",inset,startDir,start);
} else {
LOG.debug("{}Looking for all routes from {}",inset,start);
}//*/
Block destination = train.destination();
if (isSet(destination) && visitedRoutes.isEmpty()) LOG.debug("{}- Destination: {}",inset,destination);
//Route currentRoute = context.route();
TreeMap<Integer,List<Route>> availableRoutes = new TreeMap<Integer, List<Route>>();
for (Route routeCandidate : start.routes()) {
if (routeCandidate.path().firstElement() != start) continue; // Routen, die nicht vom aktuellen Block starten sind bubu
if (visitedRoutes.contains(routeCandidate)) {
LOG.debug("{}→ Candidate {} would create loop, skipping",inset,routeCandidate.shortName());
continue;
}
Context c = new Context(train).block(start).direction(startDir);
if (!routeCandidate.allowed(c)) {
if (routeCandidate.endBlock() != destination) { // allowance may be overridden by destination
LOG.debug("{} not allowed for {}",routeCandidate,c);
continue; // Zug darf auf Grund einer nicht erfüllten Bedingung nicht auf die Route
}
LOG.debug("{} not allowed for {} overridden by selected destination",routeCandidate,c);
}
int priority = 0;
if (isSet(startDir) && routeCandidate.startDirection != startDir) { // Route startet entgegen der aktuellen Fahrtrichtung des Zuges
if (!train.pushPull) continue; // Zug kann nicht wenden
if (!start.turnAllowed) continue; // Wenden im Block nicht gestattet
priority -= 5;
}
//if (routeCandidate == currentRoute) priority-=10; // möglichst andere Route als zuvor wählen // TODO: den Routen einen "last-used" Zeitstempel hinzufügen, und diesen mit in die Priorisierung einbeziehen
if (isSet(destination)) {
if (routeCandidate.endBlock() == destination) { // route goes directly to destination
LOG.debug("{}→ Candidate {} directly leads to {}",inset,routeCandidate.shortName(),destination);
priority = 1_000_000;
} else {
LOG.debug("{}- Candidate: {}",inset,routeCandidate.shortName());
visitedRoutes.add(routeCandidate);
TreeMap<Integer, List<Route>> forwardRoutes = availableRoutes(train, routeCandidate.endBlock(), routeCandidate.endDirection, visitedRoutes);
visitedRoutes.remove(routeCandidate);
if (forwardRoutes.isEmpty()) continue; // the candidate does not lead to a block, from which routes to the destination exist
Entry<Integer, List<Route>> entry = forwardRoutes.lastEntry();
LOG.debug("{}→ The following routes have connections to {}:",inset,destination);
for (Route rt: entry.getValue()) LOG.debug("{} - {}",inset,rt.shortName());
priority += entry.getKey()-10;
}
}
List<Route> routeSet = availableRoutes.get(priority);
if (isNull(routeSet)) {
routeSet = new Vector<Route>();
availableRoutes.put(priority, routeSet);
}
routeSet.add(routeCandidate);
if (routeCandidate.endBlock() == destination) break; // direct connection to destination discovered, quit search
}
if (!availableRoutes.isEmpty()) LOG.debug("{}→ Routes from {}: {}",inset,start,availableRoutes.isEmpty()?"none":"");
for (Entry<Integer, List<Route>> entry : availableRoutes.entrySet()) {
LOG.debug("{} - Priority {}:",inset,entry.getKey());
for (Route r : entry.getValue()) {
LOG.debug("{} - {}",inset,r.shortName());
}
}
return availableRoutes;
}
public Route chooseRoute() {
LOG.debug("PathFinder.chooseRoute()");
HashSet<Route> visitedRoutes = new HashSet<Route>();
TreeMap<Integer, List<Route>> availableRoutes = availableRoutes(train, startBlock, direction,visitedRoutes);
while (!availableRoutes.isEmpty()) {
LOG.debug("availableRoutes: {}",availableRoutes);
Entry<Integer, List<Route>> entry = availableRoutes.lastEntry();
List<Route> preferredRoutes = entry.getValue();
LOG.debug("preferredRoutes: {}",preferredRoutes);
Route selectedRoute = preferredRoutes.get(random.nextInt(preferredRoutes.size()));
if (selectedRoute.isFreeFor(train)) {
LOG.debug("Chose \"{}\" with priority {}.",selectedRoute,entry.getKey());
return selectedRoute;
}
LOG.debug("Selected route \"{}\" is not free for {}",selectedRoute,train);
preferredRoutes.remove(selectedRoute);
if (preferredRoutes.isEmpty()) availableRoutes.remove(availableRoutes.lastKey());
}
return null;
}
@Override
public void run() {
while (true) {
if (aborted) return;
Route route = chooseRoute();
if (isSet(route)) {
if (aborted) return;
found(route);
if (route.allocateFor(train)) {
if (aborted) {
route.reset();
return;
}
locked(route);
if (route.prepareFor(train)) {
if (aborted) {
route.reset();
return;
}
prepared(route);
return;
}
}
}
sleep(1000);
}
}
public abstract void aborted();
public abstract void locked(Route r);
public abstract void found(Route r);
public abstract void prepared(Route r);
}