Use a map for storing trains

This commit is contained in:
Arne Keller 2020-02-17 14:11:55 +01:00
parent bb9d014508
commit e41badefd9

View File

@ -39,7 +39,7 @@ public class ModelRailwaySimulation {
/** /**
* List of trains simulated. * List of trains simulated.
*/ */
private final List<Train> trains = new ArrayList<>(); private final Map<Integer, Train> trains = new HashMap<>();
/** /**
* Add a new track to the rail network of this simulation. * Add a new track to the rail network of this simulation.
@ -69,7 +69,7 @@ public class ModelRailwaySimulation {
*/ */
public boolean removeRail(final int id) { public boolean removeRail(final int id) {
// check whether any trains are on this rail // check whether any trains are on this rail
if (trains.stream().anyMatch(train -> train.isPlaced() && train.isOnRail(id))) { if (trains.values().stream().anyMatch(train -> train.isPlaced() && train.isOnRail(id))) {
return false; return false;
} }
return railNetwork.removeRail(id); return railNetwork.removeRail(id);
@ -123,7 +123,7 @@ public class ModelRailwaySimulation {
} else { } else {
engines.sort(Comparator.comparing(Engine::getIdentifier)); engines.sort(Comparator.comparing(Engine::getIdentifier));
engine: for (Engine engine : engines) { engine: for (Engine engine : engines) {
for (Train train : trains) { for (Train train : trains.values()) {
int id = train.getIdentifier(); int id = train.getIdentifier();
if (train.contains(engine)) { if (train.contains(engine)) {
Terminal.printLine(String.format("%s %s", id, engine)); Terminal.printLine(String.format("%s %s", id, engine));
@ -176,7 +176,7 @@ public class ModelRailwaySimulation {
Terminal.printLine("No coach exists"); Terminal.printLine("No coach exists");
} else { } else {
coach: for (Coach coach : coaches) { coach: for (Coach coach : coaches) {
for (Train train : trains) { for (Train train : trains.values()) {
if (train.contains(coach)) { if (train.contains(coach)) {
Terminal.printLine(String.format("%d %s %s %d %b %b", Terminal.printLine(String.format("%d %s %s %d %b %b",
coach.getNumericalIdentifier(), train.getIdentifier(), coach.getType(), coach.getNumericalIdentifier(), train.getIdentifier(), coach.getType(),
@ -220,7 +220,7 @@ public class ModelRailwaySimulation {
} else { } else {
trainSets.sort(Comparator.comparing(TrainSet::getIdentifier)); trainSets.sort(Comparator.comparing(TrainSet::getIdentifier));
trainset: for (TrainSet trainSet : trainSets) { trainset: for (TrainSet trainSet : trainSets) {
for (Train train : trains) { for (Train train : trains.values()) {
if (train.contains(trainSet)) { if (train.contains(trainSet)) {
Terminal.printLine(String.format("%s %s", train.getIdentifier(), trainSet)); Terminal.printLine(String.format("%s %s", train.getIdentifier(), trainSet));
continue trainset; continue trainset;
@ -238,7 +238,7 @@ public class ModelRailwaySimulation {
*/ */
public boolean deleteRollingStock(final String id) { public boolean deleteRollingStock(final String id) {
RollingStock rollingStock = getRollingStock(id); RollingStock rollingStock = getRollingStock(id);
if (rollingStock == null || trains.stream().anyMatch(train -> train.contains(rollingStock))) { if (rollingStock == null || trains.values().stream().anyMatch(train -> train.contains(rollingStock))) {
// can not delete rolling stock in use // can not delete rolling stock in use
return false; return false;
} }
@ -287,12 +287,12 @@ public class ModelRailwaySimulation {
if (rollingStock == null) { if (rollingStock == null) {
return false; return false;
} }
for (Train train : trains) { for (Train train : trains.values()) {
if (train.contains(rollingStock)) { if (train.contains(rollingStock)) {
return false; return false;
} }
} }
Train train = getTrain(trainId); Train train = trains.get(trainId);
if (train != null && train.isPlaced()) { if (train != null && train.isPlaced()) {
return false; return false;
} }
@ -304,7 +304,7 @@ public class ModelRailwaySimulation {
return false; return false;
} }
Train newTrain = new Train(trainId, rollingStock); Train newTrain = new Train(trainId, rollingStock);
trains.add(newTrain); trains.put(trainId, newTrain);
return true; return true;
} }
@ -313,13 +313,12 @@ public class ModelRailwaySimulation {
* @return the next train identfier, or -1 if none available * @return the next train identfier, or -1 if none available
*/ */
private int getNextTrainIdentifier() { private int getNextTrainIdentifier() {
int id = 1; for (int id = 1; id > 0; id++) {
for (Train train : trains) { if (!trains.containsKey(id)) {
if (train.getIdentifier() == id) { return id;
id++;
} }
} }
return id; return -1;
} }
/** /**
@ -328,23 +327,14 @@ public class ModelRailwaySimulation {
* @return whether the train could be deleted * @return whether the train could be deleted
*/ */
public boolean deleteTrain(int id) { public boolean deleteTrain(int id) {
Train train = getTrain(id); Train train = trains.get(id);
if (train != null) { if (train != null) {
trains.remove(train); trains.remove(train.getIdentifier());
return true; return true;
} }
return false; return false;
} }
/**
* Find a train by identifier.
* @param id identifier of the train to find.
* @return the specified train, or null if not found
*/
private Train getTrain(int id) {
return trains.stream().filter((train) -> train.getIdentifier() == id).findFirst().orElse(null);
}
/** /**
* Print a list of trains in the simulation. * Print a list of trains in the simulation.
*/ */
@ -353,7 +343,7 @@ public class ModelRailwaySimulation {
Terminal.printLine("No train exists"); // TODO not in fucking spec Terminal.printLine("No train exists"); // TODO not in fucking spec
return; return;
} }
trains.forEach(Terminal::printLine); trains.values().forEach(Terminal::printLine);
} }
/** /**
@ -361,7 +351,7 @@ public class ModelRailwaySimulation {
* @param id identifier of the train to show * @param id identifier of the train to show
*/ */
public void printTrain(int id) { public void printTrain(int id) {
Train train = getTrain(id); Train train = trains.get(id);
if (train != null) { if (train != null) {
train.print(); train.print();
} else { } else {
@ -377,7 +367,7 @@ public class ModelRailwaySimulation {
* @return whether the train was successfully placed * @return whether the train was successfully placed
*/ */
public boolean putTrain(final int trainId, final Vector2D position, final Vector2D direction) { public boolean putTrain(final int trainId, final Vector2D position, final Vector2D direction) {
Train train = getTrain(trainId); Train train = trains.get(trainId);
if (train == null || !train.isProperTrain() || train.isPlaced()) { if (train == null || !train.isProperTrain() || train.isPlaced()) {
// can only place valid trains that are not already placed // can only place valid trains that are not already placed
return false; return false;
@ -410,15 +400,15 @@ public class ModelRailwaySimulation {
return new ArrayList<>(); return new ArrayList<>();
} }
ArrayList<HashSet<Train>> collisions = new ArrayList<>(); ArrayList<HashSet<Train>> collisions = new ArrayList<>();
int maxId = trains.get(trains.size() - 1).getIdentifier(); int maxId = trains.keySet().stream().max(Integer::compareTo).get();
train: for (int id1 = 1; id1 <= maxId; id1++) { train: for (int id1 = 1; id1 <= maxId; id1++) {
Train train1 = getTrain(id1); Train train1 = trains.get(id1);
if (train1 == null || !train1.isPlaced()) { if (train1 == null || !train1.isPlaced()) {
continue; continue;
} }
HashSet<Train> collision = new HashSet<>(); HashSet<Train> collision = new HashSet<>();
for (int id2 = id1 + 1; id2 <= maxId; id2++) { for (int id2 = id1 + 1; id2 <= maxId; id2++) {
Train train2 = getTrain(id2); Train train2 = trains.get(id2);
if (train2 == null || !train2.isPlaced()) { if (train2 == null || !train2.isPlaced()) {
continue; continue;
} }
@ -450,17 +440,14 @@ public class ModelRailwaySimulation {
private ArrayList<Set<Train>> getCollisionsOfOneStep() { private ArrayList<Set<Train>> getCollisionsOfOneStep() {
ArrayList<Set<Train>> collisions = new ArrayList<>(); ArrayList<Set<Train>> collisions = new ArrayList<>();
Map<Train, Set<Rail>> occupiedRails = new HashMap<>(); Map<Train, Set<Rail>> occupiedRails = new HashMap<>();
for (Train train : trains) { for (Train train : trains.values()) {
if (train.isPlaced()) { if (train.isPlaced()) {
occupiedRails.put(train, train.getOccupiedRails()); occupiedRails.put(train, train.getOccupiedRails());
} }
} }
// perform step // perform step
Map<Train, Set<Rail>> nextOccupiedRails = new HashMap<>(); Map<Train, Set<Rail>> nextOccupiedRails = new HashMap<>();
for (Train train : trains) { trains.values().stream().filter(Train::isPlaced).forEach(train -> {
if (!train.isPlaced()) {
continue;
}
Vector2D position = train.getFrontPosition(); Vector2D position = train.getFrontPosition();
Vector2D direction = train.getDirection(); Vector2D direction = train.getDirection();
Vector2D nextPosition = railNetwork.move(position, direction); Vector2D nextPosition = railNetwork.move(position, direction);
@ -470,19 +457,16 @@ public class ModelRailwaySimulation {
collisions.add(new HashSet<>(Arrays.asList(train))); collisions.add(new HashSet<>(Arrays.asList(train)));
train.removeFromRails(); train.removeFromRails();
nextOccupiedRails.put(train, occupiedRails.get(train)); nextOccupiedRails.put(train, occupiedRails.get(train));
continue; } else {
train.moveTo(railNetwork, nextPosition);
train.setDirection(direction);
nextOccupiedRails.put(train, train.getOccupiedRails());
} }
train.moveTo(railNetwork, nextPosition); });
train.setDirection(direction);
nextOccupiedRails.put(train, train.getOccupiedRails());
}
// check for block collisions // check for block collisions
for (Train train : trains) { trains.values().stream().filter(train -> train.isPlaced() && collisions.stream().noneMatch((x) -> x.contains(train))).forEach(train -> {
if (!train.isPlaced() || collisions.stream().anyMatch((x) -> x.contains(train))) {
continue; // already included in collision
}
Set<Rail> occupiedByThisTrain = nextOccupiedRails.get(train); Set<Rail> occupiedByThisTrain = nextOccupiedRails.get(train);
trains.stream().filter((x) -> x != train).forEach((otherTrain) -> { trains.values().stream().filter((x) -> x != train).forEach((otherTrain) -> {
Set<Rail> occupiedByOtherTrainPreviously = occupiedRails.get(otherTrain); Set<Rail> occupiedByOtherTrainPreviously = occupiedRails.get(otherTrain);
Set<Rail> occupiedByOtherTrain = nextOccupiedRails.get(otherTrain); Set<Rail> occupiedByOtherTrain = nextOccupiedRails.get(otherTrain);
if (occupiedByOtherTrain == null || occupiedByOtherTrainPreviously == null) { if (occupiedByOtherTrain == null || occupiedByOtherTrainPreviously == null) {
@ -509,7 +493,7 @@ public class ModelRailwaySimulation {
} }
} }
}); });
} });
return collisions; return collisions;
} }
@ -520,14 +504,14 @@ public class ModelRailwaySimulation {
private ArrayList<Set<Train>> getCollisionsOfOneReverseStep() { private ArrayList<Set<Train>> getCollisionsOfOneReverseStep() {
ArrayList<Set<Train>> collisions = new ArrayList<>(); ArrayList<Set<Train>> collisions = new ArrayList<>();
Map<Train, Set<Rail>> occupiedRails = new HashMap<>(); Map<Train, Set<Rail>> occupiedRails = new HashMap<>();
for (Train train : trains) { for (Train train : trains.values()) {
if (train.isPlaced()) { if (train.isPlaced()) {
occupiedRails.put(train, train.getOccupiedRails()); occupiedRails.put(train, train.getOccupiedRails());
} }
} }
// perform step // perform step
Map<Train, Set<Rail>> nextOccupiedRails = new HashMap<>(); Map<Train, Set<Rail>> nextOccupiedRails = new HashMap<>();
for (Train train : trains) { for (Train train : trains.values()) {
if (!train.isPlaced()) { if (!train.isPlaced()) {
continue; continue;
} }
@ -547,12 +531,12 @@ public class ModelRailwaySimulation {
nextOccupiedRails.put(train, train.getOccupiedRails()); nextOccupiedRails.put(train, train.getOccupiedRails());
} }
// check for block collisions // check for block collisions
for (Train train : trains) { for (Train train : trains.values()) {
if (!train.isPlaced() || collisions.stream().anyMatch((x) -> x.contains(train))) { if (!train.isPlaced() || collisions.stream().anyMatch((x) -> x.contains(train))) {
continue; // already included in collision continue; // already included in collision
} }
Set<Rail> occupiedByThisTrain = nextOccupiedRails.get(train); Set<Rail> occupiedByThisTrain = nextOccupiedRails.get(train);
trains.stream().filter((x) -> x != train).forEach((otherTrain) -> { trains.values().stream().filter((x) -> x != train).forEach((otherTrain) -> {
Set<Rail> occupiedByOtherTrainPreviously = occupiedRails.get(otherTrain); Set<Rail> occupiedByOtherTrainPreviously = occupiedRails.get(otherTrain);
Set<Rail> occupiedByOtherTrain = nextOccupiedRails.get(otherTrain); Set<Rail> occupiedByOtherTrain = nextOccupiedRails.get(otherTrain);
if (occupiedByOtherTrain == null || occupiedByOtherTrainPreviously == null) { if (occupiedByOtherTrain == null || occupiedByOtherTrainPreviously == null) {
@ -589,7 +573,7 @@ public class ModelRailwaySimulation {
Terminal.printError("rail tracks/switches not set up"); Terminal.printError("rail tracks/switches not set up");
return; return;
} }
if (trains.stream().noneMatch(Train::isPlaced)) { if (trains.values().stream().noneMatch(Train::isPlaced)) {
Terminal.printLine("OK"); Terminal.printLine("OK");
return; return;
} }
@ -606,15 +590,17 @@ public class ModelRailwaySimulation {
collisions.addAll(newCollisions); collisions.addAll(newCollisions);
} }
// (only one of the loops above actually runs) // (only one of the loops above actually runs)
train: for (Train train : trains) { train: for (int id : trains.keySet().stream().sorted().collect(Collectors.toList())) {
Train train = trains.get(id);
// print collision // print collision
for (Set<Train> collisionSet : collisions) { for (Set<Train> collisionSet : collisions) {
if (!collisionSet.contains(train)) { if (!collisionSet.contains(train)) {
continue; continue;
} }
List<Train> collision = collisionSet.stream().sorted(Comparator.comparing(Train::getIdentifier)) int first = collisionSet.stream().min(Comparator.comparing(Train::getIdentifier)).get().getIdentifier();
.collect(Collectors.toList()); if (train.getIdentifier() == first) { // only print each collision once
if (collision.indexOf(train) == 0) { List<Train> collision = collisionSet.stream().sorted(Comparator.comparing(Train::getIdentifier))
.collect(Collectors.toList());
Terminal.printLine("Crash of train " + String.join(",", Terminal.printLine("Crash of train " + String.join(",",
collision.stream().map( collision.stream().map(
(x) -> Integer.toString(x.getIdentifier())).toArray(String[]::new))); (x) -> Integer.toString(x.getIdentifier())).toArray(String[]::new)));