overhauled chooseRoute
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -4,7 +4,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>de.srsoftware</groupId>
|
<groupId>de.srsoftware</groupId>
|
||||||
<artifactId>web4rail</artifactId>
|
<artifactId>web4rail</artifactId>
|
||||||
<version>0.11.3</version>
|
<version>0.11.4</version>
|
||||||
<name>Web4Rail</name>
|
<name>Web4Rail</name>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<description>Java Model Railway Control</description>
|
<description>Java Model Railway Control</description>
|
||||||
|
|||||||
@@ -2,12 +2,15 @@ package de.srsoftware.web4rail;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import de.srsoftware.tools.Tag;
|
import de.srsoftware.tools.Tag;
|
||||||
|
|
||||||
public class BaseClass implements Constants{
|
public abstract class BaseClass implements Constants{
|
||||||
|
|
||||||
|
public static final Random random = new Random();
|
||||||
|
|
||||||
public static Tag link(String tagClass,Map<String,Object> params,Object caption) {
|
public static Tag link(String tagClass,Map<String,Object> params,Object caption) {
|
||||||
String json = new JSONObject(params).toString().replace("\"", "'");
|
String json = new JSONObject(params).toString().replace("\"", "'");
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package de.srsoftware.web4rail;
|
package de.srsoftware.web4rail;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
@@ -9,8 +8,7 @@ import org.json.JSONObject;
|
|||||||
* Class for integer ranges (min…max)
|
* Class for integer ranges (min…max)
|
||||||
* @author Stephan Richter
|
* @author Stephan Richter
|
||||||
*/
|
*/
|
||||||
public class Range {
|
public class Range extends BaseClass{
|
||||||
private static final Random random = new Random();
|
|
||||||
private static final String MAX = "max";
|
private static final String MAX = "max";
|
||||||
private static final String MIN = "min";
|
private static final String MIN = "min";
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import de.srsoftware.web4rail.Window;
|
|||||||
import de.srsoftware.web4rail.moving.Train;
|
import de.srsoftware.web4rail.moving.Train;
|
||||||
import de.srsoftware.web4rail.tags.Label;
|
import de.srsoftware.web4rail.tags.Label;
|
||||||
import de.srsoftware.web4rail.tags.Select;
|
import de.srsoftware.web4rail.tags.Select;
|
||||||
|
import de.srsoftware.web4rail.tiles.Block;
|
||||||
import de.srsoftware.web4rail.tiles.Contact;
|
import de.srsoftware.web4rail.tiles.Contact;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,25 +39,48 @@ public abstract class Action extends BaseClass {
|
|||||||
public Contact contact = null;
|
public Contact contact = null;
|
||||||
public Route route = null;
|
public Route route = null;
|
||||||
public Train train = null;
|
public Train train = null;
|
||||||
|
public Block block = null;
|
||||||
|
|
||||||
public Context(Contact c) {
|
public Context(Contact c) {
|
||||||
contact = c;
|
contact = c;
|
||||||
plan = contact.plan();
|
setPlan(contact.plan());
|
||||||
route = contact.route();
|
setRoute(contact.route());
|
||||||
if (route == null) return;
|
|
||||||
train = route.train;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Context(Train train) {
|
public Context(Train train) {
|
||||||
this.train = train;
|
setTrain(train);
|
||||||
if (isSet(train)) plan = train.locos().get(0).plan();
|
}
|
||||||
|
|
||||||
|
public Context(Route route) {
|
||||||
|
setRoute(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Context(Route route) {
|
private void setRoute(Route route) {
|
||||||
this.route = route;
|
this.route = route;
|
||||||
if (isSet(route)) plan = route.path().firstElement().plan();
|
if (isSet(route)) setTrain(route.train);
|
||||||
train = route.train;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setTrain(Train train) {
|
||||||
|
this.train = train;
|
||||||
|
if (isSet(train)) {
|
||||||
|
if (isNull(route)) route = train.route;
|
||||||
|
setBlock(train.currentBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setBlock(Block block) {
|
||||||
|
this.block = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPlan(Plan plan) {
|
||||||
|
this.plan = plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeMap;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
|||||||
|
|
||||||
private HashSet<String> tags = new HashSet<String>();
|
private HashSet<String> tags = new HashSet<String>();
|
||||||
|
|
||||||
private Block block,destination = null;
|
private Block currentBlock,destination = null;
|
||||||
LinkedList<Tile> trace = new LinkedList<Tile>();
|
LinkedList<Tile> trace = new LinkedList<Tile>();
|
||||||
|
|
||||||
private class Autopilot extends Thread{
|
private class Autopilot extends Thread{
|
||||||
@@ -171,28 +171,55 @@ public class Train extends BaseClass implements Comparable<Train> {
|
|||||||
}
|
}
|
||||||
showTrace();
|
showTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Route chooseRoute(Context context) {
|
private static Route chooseRoute(Context context) {
|
||||||
HashSet<Route> routes = block.routes();
|
TreeMap<Integer, List<Route>> availableRoutes = availableRoutes(context);
|
||||||
Vector<Route> availableRoutes = new Vector<Route>();
|
|
||||||
for (Route rt : routes) {
|
|
||||||
if (rt == route) continue; // andere Route als zuvor wählen
|
|
||||||
if (rt.path().firstElement() != block) continue; // keine Route wählen, die nicht vom aktuellen Block des Zuges startet
|
|
||||||
if (isSet(direction) && rt.startDirection != direction) { // Route ist entgegen der Startrichtung des Zuges
|
|
||||||
if (!pushPull || !block.turnAllowed) { // Zug ist kein Wendezug oder Block erlaubt kein Wenden
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!rt.isFreeFor(this)) { // keine belegten Routen wählen
|
|
||||||
// LOG.debug("{} is not free!",rt);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!rt.allowed(context)) continue;
|
|
||||||
availableRoutes.add(rt);
|
|
||||||
}
|
|
||||||
Random rand = new Random();
|
|
||||||
if (availableRoutes.isEmpty()) return null;
|
if (availableRoutes.isEmpty()) return null;
|
||||||
return availableRoutes.get(rand.nextInt(availableRoutes.size()));
|
Entry<Integer, List<Route>> entry = availableRoutes.firstEntry();
|
||||||
|
List<Route> preferredRoutes = entry.getValue();
|
||||||
|
Route selectetRoute = preferredRoutes.get(random.nextInt(preferredRoutes.size()));
|
||||||
|
LOG.debug("Chose \"{}\" with priority {}.",selectetRoute,entry.getKey());
|
||||||
|
|
||||||
|
return selectetRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TreeMap<Integer,List<Route>> availableRoutes(Context context){
|
||||||
|
TreeMap<Integer,List<Route>> availableRoutes = new TreeMap<Integer, List<Route>>();
|
||||||
|
|
||||||
|
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<Route> 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<Route> routeSet = availableRoutes.get(priority);
|
||||||
|
if (isNull(routeSet)) {
|
||||||
|
routeSet = new Vector<Route>();
|
||||||
|
availableRoutes.put(priority, routeSet);
|
||||||
|
}
|
||||||
|
routeSet.add(rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return availableRoutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -303,7 +330,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
|||||||
|
|
||||||
public Train heading(Direction dir) {
|
public Train heading(Direction dir) {
|
||||||
direction = dir;
|
direction = dir;
|
||||||
if (isSet(block)) plan.place(block);
|
if (isSet(currentBlock)) plan.place(currentBlock);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +343,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
|||||||
json.put(ID, id);
|
json.put(ID, id);
|
||||||
json.put(PUSH_PULL, pushPull);
|
json.put(PUSH_PULL, pushPull);
|
||||||
|
|
||||||
if (isSet(block)) json.put(BLOCK, block.id());
|
if (isSet(currentBlock)) json.put(BLOCK, currentBlock.id());
|
||||||
if (isSet(name))json.put(NAME, name);
|
if (isSet(name))json.put(NAME, name);
|
||||||
if (isSet(route)) json.put(ROUTE, route.id());
|
if (isSet(route)) json.put(ROUTE, route.id());
|
||||||
if (isSet(direction)) json.put(DIRECTION, direction);
|
if (isSet(direction)) json.put(DIRECTION, direction);
|
||||||
@@ -374,7 +401,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
|||||||
if (json.has(NAME)) name = json.getString(NAME);
|
if (json.has(NAME)) name = json.getString(NAME);
|
||||||
if (json.has(TAGS)) json.getJSONArray(TAGS ).forEach(elem -> { tags.add(elem.toString()); });
|
if (json.has(TAGS)) json.getJSONArray(TAGS ).forEach(elem -> { tags.add(elem.toString()); });
|
||||||
if (json.has(TRACE)) json.getJSONArray(TRACE).forEach(elem -> { trace.add(plan.get(elem.toString(), false).set(this)); });
|
if (json.has(TRACE)) json.getJSONArray(TRACE).forEach(elem -> { trace.add(plan.get(elem.toString(), false).set(this)); });
|
||||||
if (json.has(BLOCK)) block = (Block) plan.get(json.getString(BLOCK), false).set(this); // do not move this up! during set, other fields will be referenced!
|
if (json.has(BLOCK)) currentBlock = (Block) plan.get(json.getString(BLOCK), false).set(this); // do not move this up! during set, other fields will be referenced!
|
||||||
for (Object id : json.getJSONArray(CARS)) add(Car.get(id));
|
for (Object id : json.getJSONArray(CARS)) add(Car.get(id));
|
||||||
for (Object id : json.getJSONArray(LOCOS)) add((Locomotive) Car.get(id));
|
for (Object id : json.getJSONArray(LOCOS)) add((Locomotive) Car.get(id));
|
||||||
return this;
|
return this;
|
||||||
@@ -494,8 +521,8 @@ public class Train extends BaseClass implements Comparable<Train> {
|
|||||||
}
|
}
|
||||||
dest.addTo(propList);
|
dest.addTo(propList);
|
||||||
|
|
||||||
if (isSet(block)) {
|
if (isSet(currentBlock)) {
|
||||||
link("li",Map.of(REALM,REALM_PLAN,ID,block.id(),ACTION,ACTION_CLICK),t("Current location: {}",block)).addTo(propList);
|
link("li",Map.of(REALM,REALM_PLAN,ID,currentBlock.id(),ACTION,ACTION_CLICK),t("Current location: {}",currentBlock)).addTo(propList);
|
||||||
Tag actions = new Tag("li").clazz().content(t("Actions:")+NBSP);
|
Tag actions = new Tag("li").clazz().content(t("Actions:")+NBSP);
|
||||||
props.put(ACTION, ACTION_START);
|
props.put(ACTION, ACTION_START);
|
||||||
new Button(t("start"),props).addTo(actions);
|
new Button(t("start"),props).addTo(actions);
|
||||||
@@ -556,8 +583,8 @@ public class Train extends BaseClass implements Comparable<Train> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void set(Block newBlock) {
|
public void set(Block newBlock) {
|
||||||
block = newBlock;
|
currentBlock = newBlock;
|
||||||
if (isSet(block)) block.set(this);
|
if (isSet(currentBlock)) currentBlock.set(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String setDestination(HashMap<String, String> params) {
|
private String setDestination(HashMap<String, String> params) {
|
||||||
@@ -594,13 +621,12 @@ public class Train extends BaseClass implements Comparable<Train> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String start() throws IOException {
|
public String start() throws IOException {
|
||||||
if (isNull(block)) return t("{} not in a block",this);
|
if (isNull(currentBlock)) return t("{} not in a block",this);
|
||||||
Context context = isSet(route) ? new Context( route ) : new Context( this);
|
Context context = isSet(route) ? new Context( route ) : new Context( this);
|
||||||
|
|
||||||
if (isSet(context.route)) context.route.reset(); // reset route previously chosen
|
if (isSet(context.route)) context.route.reset(); // reset route previously chosen
|
||||||
|
|
||||||
route = chooseRoute(context);
|
route = chooseRoute(context);
|
||||||
if (isNull(route)) return t("No free routes from {}",block);
|
if (isNull(route)) return t("No free routes from {}",currentBlock);
|
||||||
if (!route.lock()) return t("Was not able to lock {}",route);
|
if (!route.lock()) return t("Was not able to lock {}",route);
|
||||||
|
|
||||||
if (direction != route.startDirection) turn();
|
if (direction != route.startDirection) turn();
|
||||||
@@ -648,7 +674,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
|||||||
direction = direction.inverse();
|
direction = direction.inverse();
|
||||||
for (Locomotive loco : locos) loco.turn();
|
for (Locomotive loco : locos) loco.turn();
|
||||||
reverseTrace();
|
reverseTrace();
|
||||||
if (isSet(block)) plan.place(block);
|
if (isSet(currentBlock)) plan.place(currentBlock);
|
||||||
}
|
}
|
||||||
return t("{} turned.",this);
|
return t("{} turned.",this);
|
||||||
}
|
}
|
||||||
@@ -676,4 +702,8 @@ public class Train extends BaseClass implements Comparable<Train> {
|
|||||||
public void setWaitTime(Range waitTime) {
|
public void setWaitTime(Range waitTime) {
|
||||||
if (autopilot != null) autopilot.waitTime = waitTime.random();
|
if (autopilot != null) autopilot.waitTime = waitTime.random();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Block currentBlock() {
|
||||||
|
return currentBlock;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import de.srsoftware.web4rail.tags.Radio;
|
|||||||
*/
|
*/
|
||||||
public abstract class Tile extends BaseClass{
|
public abstract class Tile extends BaseClass{
|
||||||
protected static Logger LOG = LoggerFactory.getLogger(Tile.class);
|
protected static Logger LOG = LoggerFactory.getLogger(Tile.class);
|
||||||
private static int DEFAUT_LENGTH = 5;
|
private static int DEFAUT_LENGTH = 100; // 10cm
|
||||||
|
|
||||||
private static final String LENGTH = "length";
|
private static final String LENGTH = "length";
|
||||||
private static final String LOCKED = "locked";
|
private static final String LOCKED = "locked";
|
||||||
|
|||||||
Reference in New Issue
Block a user