diff --git a/pom.xml b/pom.xml index b374879..20dec21 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 de.srsoftware web4rail - 0.11.4 + 0.11.5 Web4Rail jar Java Model Railway Control diff --git a/src/main/java/de/srsoftware/web4rail/PathFinder.java b/src/main/java/de/srsoftware/web4rail/PathFinder.java new file mode 100644 index 0000000..71f4336 --- /dev/null +++ b/src/main/java/de/srsoftware/web4rail/PathFinder.java @@ -0,0 +1,116 @@ +package de.srsoftware.web4rail; + +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.Plan.Direction; +import de.srsoftware.web4rail.actions.Action.Context; +import de.srsoftware.web4rail.moving.Train; +import de.srsoftware.web4rail.tiles.Block; + +public class PathFinder extends BaseClass{ + private static final Logger LOG = LoggerFactory.getLogger(PathFinder.class); + + private static TreeMap> availableRoutes(Context context,HashSet visitedRoutes){ + TreeMap> availableRoutes = new TreeMap>(); + + String inset = ""; + for (int i=0; i> forwardRoutes = availableRoutes(forwardContext,visitedRoutes); + visitedRoutes.remove(routeCandidate); + if (forwardRoutes.isEmpty()) continue; // the candidate does not lead to a block, from which routes to the destination exist + Entry> 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 routeSet = availableRoutes.get(priority); + if (isNull(routeSet)) { + routeSet = new Vector(); + availableRoutes.put(priority, routeSet); + } + routeSet.add(routeCandidate); + if (routeCandidate.endBlock() == destination) break; // direct connection to destination discovered, quit search + } + LOG.debug("{}→ Routes from {}: {}",inset,block,availableRoutes.isEmpty()?"none":""); + for (Entry> entry : availableRoutes.entrySet()) { + LOG.debug("{} - Priority {}:",inset,entry.getKey()); + for (Route r : entry.getValue()) { + LOG.debug("{} - {}",inset,r.shortName()); + } + } + return availableRoutes; + } + + public static Route chooseRoute(Context context) { + TreeMap> availableRoutes = PathFinder.availableRoutes(context,new HashSet()); + if (availableRoutes.isEmpty()) return null; + Entry> entry = availableRoutes.lastEntry(); + List preferredRoutes = entry.getValue(); + Route selectetRoute = preferredRoutes.get(random.nextInt(preferredRoutes.size())); + LOG.debug("Chose \"{}\" with priority {}.",selectetRoute,entry.getKey()); + + return selectetRoute; + } + +} diff --git a/src/main/java/de/srsoftware/web4rail/Route.java b/src/main/java/de/srsoftware/web4rail/Route.java index f3fb852..0bd6879 100644 --- a/src/main/java/de/srsoftware/web4rail/Route.java +++ b/src/main/java/de/srsoftware/web4rail/Route.java @@ -70,7 +70,7 @@ public class Route extends BaseClass{ private Vector contacts; private boolean disabled = false; private Block endBlock = null; - private Direction endDirection; + public Direction endDirection; private int id; private Vector path; private Vector signals; @@ -683,4 +683,9 @@ public class Route extends BaseClass{ } return message; } + + public String shortName() { + String[] parts = name().split("-"); + return parts[0].trim()+"–"+parts[parts.length-1].trim(); + } } diff --git a/src/main/java/de/srsoftware/web4rail/actions/Action.java b/src/main/java/de/srsoftware/web4rail/actions/Action.java index 62373b0..0c25c71 100644 --- a/src/main/java/de/srsoftware/web4rail/actions/Action.java +++ b/src/main/java/de/srsoftware/web4rail/actions/Action.java @@ -2,6 +2,7 @@ package de.srsoftware.web4rail.actions; import java.io.IOException; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map.Entry; import java.util.TreeMap; @@ -15,6 +16,7 @@ import de.srsoftware.tools.Tag; import de.srsoftware.web4rail.Application; import de.srsoftware.web4rail.BaseClass; import de.srsoftware.web4rail.Plan; +import de.srsoftware.web4rail.Plan.Direction; import de.srsoftware.web4rail.Route; import de.srsoftware.web4rail.Window; import de.srsoftware.web4rail.moving.Train; @@ -40,6 +42,7 @@ public abstract class Action extends BaseClass { public Route route = null; public Train train = null; public Block block = null; + public Direction direction = null; public Context(Contact c) { contact = c; @@ -66,8 +69,12 @@ public abstract class Action extends BaseClass { if (isSet(train)) { if (isNull(route)) route = train.route; setBlock(train.currentBlock()); - } - + setDirection(train.direction()); + } + } + + private void setDirection(Direction dir) { + direction = dir; } private void setBlock(Block block) { diff --git a/src/main/java/de/srsoftware/web4rail/moving/Train.java b/src/main/java/de/srsoftware/web4rail/moving/Train.java index bee5f4b..06982c8 100644 --- a/src/main/java/de/srsoftware/web4rail/moving/Train.java +++ b/src/main/java/de/srsoftware/web4rail/moving/Train.java @@ -13,7 +13,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.SortedSet; -import java.util.TreeMap; import java.util.TreeSet; import java.util.Vector; @@ -25,6 +24,7 @@ import de.keawe.tools.translations.Translation; import de.srsoftware.tools.Tag; import de.srsoftware.web4rail.Application; import de.srsoftware.web4rail.BaseClass; +import de.srsoftware.web4rail.PathFinder; import de.srsoftware.web4rail.Plan; import de.srsoftware.web4rail.Plan.Direction; import de.srsoftware.web4rail.Range; @@ -172,56 +172,6 @@ public class Train extends BaseClass implements Comparable { showTrace(); } - private static Route chooseRoute(Context context) { - TreeMap> availableRoutes = availableRoutes(context); - if (availableRoutes.isEmpty()) return null; - Entry> entry = availableRoutes.firstEntry(); - List preferredRoutes = entry.getValue(); - Route selectetRoute = preferredRoutes.get(random.nextInt(preferredRoutes.size())); - LOG.debug("Chose \"{}\" with priority {}.",selectetRoute,entry.getKey()); - - return selectetRoute; - } - - private static TreeMap> availableRoutes(Context context){ - TreeMap> availableRoutes = new TreeMap>(); - - boolean error = false; - if (isNull(context.block)) { - LOG.warn("{}.availableRoutes called without context.block!",Train.class.getSimpleName()); - error = true; - } - if (isNull(context.train)) { - LOG.warn("{}.availableRoutes called without context.train!",Train.class.getSimpleName()); - error = true; - } - if (error) return availableRoutes; - - Collection routes = context.block.routes(); - - for (Route rt : routes) { - if (rt.path().firstElement() != context.block) continue; // routen, die nicht vom aktuellen Block starten sind bubu - int priority = 0; - if (rt == context.route) 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(context.train.direction) && rt.startDirection != context.train.direction) { // Route startet entgegen der aktuellen Fahrtrichtung des Zuges - if (!context.train.pushPull) continue; // Zug kann nicht wenden - if (!context.block.turnAllowed) continue; // Wenden im Block nicht gestattet - priority -= 5; - } - if (!rt.isFreeFor(context.train)) continue; // Route ist nicht frei - if (!rt.allowed(context)) continue; // Zug darf auf Grund einer nicht erfüllten Bedingung nicht auf die Route - - List routeSet = availableRoutes.get(priority); - if (isNull(routeSet)) { - routeSet = new Vector(); - availableRoutes.put(priority, routeSet); - } - routeSet.add(rt); - } - - return availableRoutes; - } - @Override public int compareTo(Train o) { return name().compareTo(o.toString()); @@ -622,10 +572,10 @@ public class Train extends BaseClass implements Comparable { public String start() throws IOException { if (isNull(currentBlock)) return t("{} not in a block",this); - Context context = isSet(route) ? new Context( route ) : new Context( this); - if (isSet(context.route)) context.route.reset(); // reset route previously chosen + if (isSet(route)) route.reset(); // reset route previously chosen - route = chooseRoute(context); + Context context = new Context(this); + route = PathFinder.chooseRoute(context); if (isNull(route)) return t("No free routes from {}",currentBlock); if (!route.lock()) return t("Was not able to lock {}",route); @@ -706,4 +656,8 @@ public class Train extends BaseClass implements Comparable { public Block currentBlock() { return currentBlock; } + + public Block destination() { + return destination; + } } diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Block.java b/src/main/java/de/srsoftware/web4rail/tiles/Block.java index c7ed3ee..5bfa94c 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/Block.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/Block.java @@ -293,7 +293,7 @@ public abstract class Block extends StretchableTile{ @Override public String toString() { - return getClass().getSimpleName()+"("+name+") @ ("+x+","+y+")"; + return name + " @ ("+x+","+y+")"; } @Override diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Tile.java b/src/main/java/de/srsoftware/web4rail/tiles/Tile.java index f1cc716..ff07205 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/Tile.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/Tile.java @@ -240,7 +240,7 @@ public abstract class Tile extends BaseClass{ Tag routeList = new Tag("ol"); for (Route route : routes) { String json = new JSONObject(Map.of(REALM,ROUTE,ID,route.id(),ACTION,ACTION_PROPS,CONTEXT,REALM_PLAN+":"+id())).toString().replace("\"", "'"); - Tag li = new Tag("span").attr("onclick","return request("+json+");").content(route.name()+(route.isDisabled()?" ["+t("disabled")+"]" : "")+NBSP).addTo(new Tag("li").clazz("link")); + Tag li = new Tag("span").attr("onclick","return request("+json+");").content(route.shortName()+(route.isDisabled()?" ["+t("disabled")+"]" : "")+NBSP).addTo(new Tag("li").clazz("link")); Map params = Map.of(REALM,REALM_ROUTE,ID,route.id(),ACTION,ACTION_DROP,Tile.class.getSimpleName(),id()); new Button(t("delete route"),params).addTo(li); li.addTo(routeList);