7 changed files with 20 additions and 389 deletions
@ -1,98 +0,0 @@
@@ -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); |
||||
} |
||||
} |
@ -1,185 +0,0 @@
@@ -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); |
||||
} |
Loading…
Reference in new issue