diff --git a/src/edu/kit/informatik/modelrailwaysimulator/model/Coach.java b/src/edu/kit/informatik/modelrailwaysimulator/model/Coach.java index 9a1f294..3db9d13 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/model/Coach.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/model/Coach.java @@ -34,13 +34,12 @@ public abstract class Coach extends RollingStock { * @param length length of coach * @param couplingFront whether the coach should have a front coupling * @param couplingBack whether the coach should have a back coupling - * @throws InvalidInputException on invalid user input (zero-sized coach) - * @throws IllegalArgumentException if the identifier is not positive + * @throws InvalidInputException on invalid user input (e.g. zero-sized coach) */ public Coach(int identifier, int length, boolean couplingFront, boolean couplingBack) throws InvalidInputException { super(length, couplingFront, couplingBack); if (identifier < 1) { - throw new IllegalArgumentException("coach id has to be positive!"); + throw new InvalidInputException("coach id has to be positive!"); } this.identifier = identifier; } diff --git a/src/edu/kit/informatik/modelrailwaysimulator/model/Engine.java b/src/edu/kit/informatik/modelrailwaysimulator/model/Engine.java index deef325..c9d0b14 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/model/Engine.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/model/Engine.java @@ -51,7 +51,7 @@ public abstract class Engine extends RollingStock { @Override public String getIdentifier() { - return String.format("%s-%s", series, getName()); + return String.format("%s-%s", series, name); } @Override @@ -84,7 +84,7 @@ public abstract class Engine extends RollingStock { */ @Override public String toString() { - return String.format("%s %s %s %d %b %b", getType(), getSeries(), getName(), getLength(), + return String.format("%s %s %s %d %b %b", getType(), series, name, getLength(), hasCouplingFront(), hasCouplingBack()); } } diff --git a/src/edu/kit/informatik/modelrailwaysimulator/model/ModelRailwaySimulation.java b/src/edu/kit/informatik/modelrailwaysimulator/model/ModelRailwaySimulation.java index e339889..ec07c72 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/model/ModelRailwaySimulation.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/model/ModelRailwaySimulation.java @@ -237,8 +237,7 @@ public class ModelRailwaySimulation { if (engine != null) { return Optional.of(engine); } - final TrainSet trainSet = trainSets.get(id); - return Optional.ofNullable(trainSet); + return Optional.ofNullable(trainSets.get(id)); } } @@ -317,7 +316,7 @@ public class ModelRailwaySimulation { * Move the trains in this simulation. * * @param speed amount of steps to move the trains - * @return train collisions, empty if no trains are placed + * @return train collisions, no value if no trains are placed * @throws InvalidInputException if the simulation is not yet ready */ public Optional>> step(short speed) throws InvalidInputException { diff --git a/src/edu/kit/informatik/modelrailwaysimulator/model/Rail.java b/src/edu/kit/informatik/modelrailwaysimulator/model/Rail.java index bc2969f..48787bb 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/model/Rail.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/model/Rail.java @@ -123,6 +123,8 @@ public abstract class Rail { public abstract Vector2D move(Vector2D position, Vector2D direction, long steps); /** + * Check whether this rail is ready for usage by trains. + * * @return whether the rail is ready for trains running on it */ public abstract boolean isReadyForTrains(); diff --git a/src/edu/kit/informatik/modelrailwaysimulator/model/RollingStock.java b/src/edu/kit/informatik/modelrailwaysimulator/model/RollingStock.java index 03316a1..ae70de4 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/model/RollingStock.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/model/RollingStock.java @@ -8,7 +8,7 @@ import edu.kit.informatik.modelrailwaysimulator.ui.InvalidInputException; * @author Arne Keller * @version 1.0 */ -public abstract class RollingStock implements Comparable { +public abstract class RollingStock { /** * Length of this rolling stock. */ @@ -96,15 +96,4 @@ public abstract class RollingStock implements Comparable { * @return textual description of this rolling stock */ public abstract String description(); - - /** - * Compare two rolling stocks based on their textual identifier. - * - * @param other rolling stock to compare to - * @return lexicographic comparison of the identifiers - */ - @Override - public int compareTo(RollingStock other) { - return this.getIdentifier().compareTo(other.getIdentifier()); - } } diff --git a/src/edu/kit/informatik/modelrailwaysimulator/model/Switch.java b/src/edu/kit/informatik/modelrailwaysimulator/model/Switch.java index d01fb6e..dd049eb 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/model/Switch.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/model/Switch.java @@ -62,6 +62,12 @@ public final class Switch extends Rail { return rail.canConnectToRail(positionOne) || rail.canConnectToRail(positionTwo); } + /** + * Reconfigure this switch. Allows setting the same position again. + * + * @param position point to connect to + * @return whether switching was successful + */ @Override public boolean switchTo(Vector2D position) { if (positionOne.canConnectTo(position)) { @@ -84,7 +90,7 @@ public final class Switch extends Rail { /** * @param position the point to check - * @return whether the active switch configuration contains that position + * @return whether the active switch configuration {@link Track#contains(Vector2D) contains} that position */ @Override public boolean contains(Vector2D position) { @@ -129,7 +135,7 @@ public final class Switch extends Rail { if (selection == null) { return String.format("s %d %s -> %s,%s", getIdentifier(), positionOne.getStart(), positionOne.getEnd(), positionTwo.getEnd()); - } else { + } else { // print length of active segment return String.format("s %d %s -> %s,%s %d", getIdentifier(), positionOne.getStart(), positionOne.getEnd(), positionTwo.getEnd(), getLength()); } @@ -153,6 +159,7 @@ public final class Switch extends Rail { @Override public int hashCode() { + // consistent with equals: ignores current configuration return Objects.hash(positionOne, positionTwo); } } diff --git a/src/edu/kit/informatik/modelrailwaysimulator/model/Track.java b/src/edu/kit/informatik/modelrailwaysimulator/model/Track.java index aaf5ff9..dd56df9 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/model/Track.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/model/Track.java @@ -74,15 +74,19 @@ public final class Track extends Rail { @Override public Vector2D move(Vector2D position, Vector2D direction, long steps) { + if (!connectsTo(position) && !contains(position)) { + return null; + } + // attempt to move exactly in the specified direction final Vector2D nextPosition = position.add(direction.scale(steps)); if (contains(nextPosition) || connectsTo(nextPosition)) { return nextPosition; } else if (direction.equals(getDirectionFrom(start))) { - return end; + return end; // can not go further than end of rail } else if (direction.equals(getDirectionFrom(end))) { return start; } else if (position.equals(end) && !direction.equals(getDirectionFrom(start))) { - return move(position, getDirectionFrom(end), steps); + return move(position, getDirectionFrom(end), steps); // attempt to correct direction } else if (position.equals(start) && !direction.equals(getDirectionFrom(end))) { return move(position, getDirectionFrom(start), steps); } diff --git a/src/edu/kit/informatik/modelrailwaysimulator/model/Train.java b/src/edu/kit/informatik/modelrailwaysimulator/model/Train.java index 9a35d6b..27dd113 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/model/Train.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/model/Train.java @@ -219,13 +219,55 @@ public final class Train implements Comparable { return new HashSet<>(occupiedRails); } + /** + * Move this train one step forward. + * + * @param railNetwork railway network to move on + * @return new position, null if derailing + */ + public Vector2D stepForward(RailwayNetwork railNetwork) { + final Vector2D position = getFrontPosition(); + final Vector2D direction = getDirection(); + final Vector2D nextPosition = railNetwork.move(position, direction, 1); + if (nextPosition == null || nextPosition.equals(position)) { + // train is derailing + moveTo(railNetwork, null); + return null; + } else { + // train is moving successfully + moveTo(railNetwork, nextPosition); + return nextPosition; + } + } + + /** + * Move this train one step backward. + * + * @param railNetwork railway network to move on + * @return new position, null if derailing + */ + public Vector2D stepBackward(RailwayNetwork railNetwork) { + final Vector2D position = getRearPosition(); + final Vector2D direction = getRearDirection(); + final Vector2D nextPosition = railNetwork.move(position, direction, 1); + if (nextPosition == null || nextPosition.equals(position)) { + // derailing + moveBackTo(railNetwork, null); + return null; + } else { + // train moving successfully + moveBackTo(railNetwork, nextPosition); + return nextPosition; + } + } + /** * Move this train on a train network to the specified position. Will not remove itself from rails if derailing. * * @param railNetwork rail network to move train on * @param nextPosition position to move train to */ - public void moveTo(RailwayNetwork railNetwork, Vector2D nextPosition) { + private void moveTo(RailwayNetwork railNetwork, Vector2D nextPosition) { final Optional railUnderBackOfTrain = railNetwork.findContainingRail(positions.getLast()); positions.set(positions.size() - 1, positions.getLast().subtract(getRearDirection())); if (positions.getLast().equals(positions.get(positions.size() - 2))) { // left a rail behind @@ -247,7 +289,7 @@ public final class Train implements Comparable { * @param railNetwork rail network to move train on * @param backPosition position to move back of the train to */ - public void moveBackTo(RailwayNetwork railNetwork, Vector2D backPosition) { + private void moveBackTo(RailwayNetwork railNetwork, Vector2D backPosition) { // a common method for both directions would be a huge mess: requires at least six (!) extra parameters final Optional railUnderFrontOfTrain = railNetwork.findContainingRail(positions.getFirst()); positions.set(0, positions.getFirst().subtract(getDirection())); diff --git a/src/edu/kit/informatik/modelrailwaysimulator/model/TrainManager.java b/src/edu/kit/informatik/modelrailwaysimulator/model/TrainManager.java index 36e2b14..b05e3d3 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/model/TrainManager.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/model/TrainManager.java @@ -14,6 +14,7 @@ import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -280,45 +281,13 @@ public final class TrainManager { * * @return list of collisions (never null, sometimes empty) */ - private List> getCollisionsOfOneStep() { + private List> getCollisionsOfOneStep(Function movementFunction) { final List> collisions = new ArrayList<>(); trains.values().stream().filter(Train::isPlaced).forEach(train -> { - final Vector2D position = train.getFrontPosition(); - final Vector2D direction = train.getDirection(); - final Vector2D nextPosition = railNetwork.move(position, direction, 1); - if (nextPosition == null || nextPosition.equals(position)) { + final Vector2D nextPosition = movementFunction.apply(train); + if (nextPosition == null) { // train is derailing - train.moveTo(railNetwork, null); collisions.add(Stream.of(train).collect(Collectors.toCollection(TreeSet::new))); - } else { - // train is moving successfully - train.moveTo(railNetwork, nextPosition); - } - }); - getStaticCollisions(collisions); - collisions.forEach(collision -> collision.forEach(Train::removeFromRails)); - return collisions; - } - - /** - * Get collisions of moving the trains one step backward, removing crashing trains from the rails in the process. - * - * @return list of collisions (never null, sometimes empty) - */ - private List> getCollisionsOfOneReverseStep() { - final List> collisions = new ArrayList<>(); - // perform step - trains.values().stream().filter(Train::isPlaced).forEach(train -> { - final Vector2D position = train.getRearPosition(); - final Vector2D direction = train.getRearDirection(); - final Vector2D nextPosition = railNetwork.move(position, direction, 1); - if (nextPosition == null || nextPosition.equals(position)) { - // derailing - train.moveBackTo(railNetwork, nextPosition); - collisions.add(Stream.of(train).collect(Collectors.toCollection(TreeSet::new))); - } else { - // train moving successfully - train.moveBackTo(railNetwork, nextPosition); } }); getStaticCollisions(collisions); @@ -330,7 +299,7 @@ public final class TrainManager { * Move the trains in this simulation. * * @param speed amount of steps to move the trains - * @return train collisions, empty if no trains are placed + * @return train collisions, no value if no trains are placed * @throws InvalidInputException if simulation is not yet ready */ public Optional>> step(short speed) throws InvalidInputException { @@ -342,11 +311,14 @@ public final class TrainManager { } return Optional.of(IntStream.range(0, Math.abs(speed)) - .mapToObj(step -> speed >= 0 ? getCollisionsOfOneStep() : getCollisionsOfOneReverseStep()) + .mapToObj(step -> speed >= 0 + ? getCollisionsOfOneStep(train -> train.stepForward(railNetwork)) + : getCollisionsOfOneStep(train -> train.stepBackward(railNetwork))) // replace train references with identifiers to prevent modification by caller .flatMap(collisions -> collisions.stream() .map(collision -> collision.stream().map(Train::getIdentifier) .collect(Collectors.toCollection(TreeSet::new)))) + // sort by train with lowest identifier in crash .sorted(Comparator.comparing(TreeSet::first)) .collect(Collectors.toList())); } diff --git a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteRollingStock.java b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteRollingStock.java index d7cc1cc..9d44cf6 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteRollingStock.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteRollingStock.java @@ -2,12 +2,12 @@ package edu.kit.informatik.modelrailwaysimulator.ui.command; import edu.kit.informatik.modelrailwaysimulator.model.ModelRailwaySimulation; import edu.kit.informatik.Terminal; +import edu.kit.informatik.modelrailwaysimulator.ui.CommandLine; import edu.kit.informatik.modelrailwaysimulator.ui.InvalidInputException; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static edu.kit.informatik.modelrailwaysimulator.ui.CommandLine.OK; import static edu.kit.informatik.modelrailwaysimulator.ui.command.CommandFactory.ROLLING_STOCK_IDENTIFIER; /** @@ -34,7 +34,7 @@ public class DeleteRollingStock extends Command { throw new IllegalStateException("command not initialized"); } if (simulation.deleteRollingStock(id)) { - Terminal.printLine(OK); + Terminal.printLine(CommandLine.OK); } else { Terminal.printError("could not delete rolling stock"); } diff --git a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteTrack.java b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteTrack.java index 97e9d51..ea3c185 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteTrack.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteTrack.java @@ -2,9 +2,9 @@ package edu.kit.informatik.modelrailwaysimulator.ui.command; import edu.kit.informatik.modelrailwaysimulator.model.ModelRailwaySimulation; import edu.kit.informatik.Terminal; +import edu.kit.informatik.modelrailwaysimulator.ui.CommandLine; import edu.kit.informatik.modelrailwaysimulator.ui.InvalidInputException; -import static edu.kit.informatik.modelrailwaysimulator.ui.CommandLine.OK; import static edu.kit.informatik.modelrailwaysimulator.ui.command.CommandFactory.NUMBER; /** @@ -27,7 +27,7 @@ public class DeleteTrack extends Command { @Override public void apply(ModelRailwaySimulation simulation) { if (simulation.removeRail(id)) { - Terminal.printLine(OK); + Terminal.printLine(CommandLine.OK); } else { Terminal.printError("could not delete rail segment"); } diff --git a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteTrain.java b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteTrain.java index 4925483..e0384d3 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteTrain.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/DeleteTrain.java @@ -2,9 +2,9 @@ package edu.kit.informatik.modelrailwaysimulator.ui.command; import edu.kit.informatik.modelrailwaysimulator.model.ModelRailwaySimulation; import edu.kit.informatik.Terminal; +import edu.kit.informatik.modelrailwaysimulator.ui.CommandLine; import edu.kit.informatik.modelrailwaysimulator.ui.InvalidInputException; -import static edu.kit.informatik.modelrailwaysimulator.ui.CommandLine.OK; import static edu.kit.informatik.modelrailwaysimulator.ui.command.CommandFactory.NUMBER; /** @@ -27,7 +27,7 @@ public class DeleteTrain extends Command { @Override public void apply(ModelRailwaySimulation simulation) { if (simulation.deleteTrain(id)) { - Terminal.printLine(OK); + Terminal.printLine(CommandLine.OK); } else { Terminal.printError("could not remove train"); } diff --git a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/PutTrain.java b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/PutTrain.java index 32ae6c8..fd52a90 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/PutTrain.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/PutTrain.java @@ -3,12 +3,12 @@ package edu.kit.informatik.modelrailwaysimulator.ui.command; import edu.kit.informatik.modelrailwaysimulator.model.ModelRailwaySimulation; import edu.kit.informatik.modelrailwaysimulator.model.Vector2D; import edu.kit.informatik.Terminal; +import edu.kit.informatik.modelrailwaysimulator.ui.CommandLine; import edu.kit.informatik.modelrailwaysimulator.ui.InvalidInputException; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static edu.kit.informatik.modelrailwaysimulator.ui.CommandLine.OK; import static edu.kit.informatik.modelrailwaysimulator.ui.command.CommandFactory.NUMBER; import static edu.kit.informatik.modelrailwaysimulator.ui.command.CommandFactory.VECTOR; @@ -45,7 +45,7 @@ public class PutTrain extends Command { throw new IllegalStateException("command not initialized"); } if (simulation.putTrain(id, point, direction)) { - Terminal.printLine(OK); + Terminal.printLine(CommandLine.OK); } else { Terminal.printError("could not place train"); } diff --git a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/SetSwitch.java b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/SetSwitch.java index 39a3c74..a96ec4e 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/SetSwitch.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/SetSwitch.java @@ -3,12 +3,12 @@ package edu.kit.informatik.modelrailwaysimulator.ui.command; import edu.kit.informatik.modelrailwaysimulator.model.ModelRailwaySimulation; import edu.kit.informatik.modelrailwaysimulator.model.Vector2D; import edu.kit.informatik.Terminal; +import edu.kit.informatik.modelrailwaysimulator.ui.CommandLine; import edu.kit.informatik.modelrailwaysimulator.ui.InvalidInputException; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static edu.kit.informatik.modelrailwaysimulator.ui.CommandLine.OK; import static edu.kit.informatik.modelrailwaysimulator.ui.command.CommandFactory.NUMBER; import static edu.kit.informatik.modelrailwaysimulator.ui.command.CommandFactory.VECTOR; @@ -41,7 +41,7 @@ public class SetSwitch extends Command { throw new IllegalStateException("command not initialized"); } if (simulation.setSwitch(id, point)) { - Terminal.printLine(OK); + Terminal.printLine(CommandLine.OK); } else { Terminal.printError("could not set switch"); } diff --git a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/Step.java b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/Step.java index 29cee1b..ac078e0 100644 --- a/src/edu/kit/informatik/modelrailwaysimulator/ui/command/Step.java +++ b/src/edu/kit/informatik/modelrailwaysimulator/ui/command/Step.java @@ -3,13 +3,13 @@ package edu.kit.informatik.modelrailwaysimulator.ui.command; import edu.kit.informatik.Terminal; import edu.kit.informatik.modelrailwaysimulator.model.ModelRailwaySimulation; import edu.kit.informatik.modelrailwaysimulator.model.Vector2D; +import edu.kit.informatik.modelrailwaysimulator.ui.CommandLine; import edu.kit.informatik.modelrailwaysimulator.ui.InvalidInputException; import java.util.List; import java.util.Optional; import java.util.SortedSet; -import static edu.kit.informatik.modelrailwaysimulator.ui.CommandLine.OK; import static edu.kit.informatik.modelrailwaysimulator.ui.command.CommandFactory.NUMBER; /** @@ -33,7 +33,7 @@ public class Step extends Command { public void apply(ModelRailwaySimulation simulation) throws InvalidInputException { final Optional>> collisions = simulation.step(speed); if (!collisions.isPresent()) { - Terminal.printLine(OK); + Terminal.printLine(CommandLine.OK); } else { for (final int id : simulation.getTrains().keySet()) { final SortedSet collisionSet = collisions.get().stream()