Checkstyle

This commit is contained in:
Arne Keller 2020-03-04 22:56:37 +01:00
parent 4fad0a377e
commit ce63ed3bed
14 changed files with 143 additions and 159 deletions

View File

@ -6,5 +6,10 @@
<language minSize="46" name="Java" /> <language minSize="46" name="Java" />
</Languages> </Languages>
</inspection_tool> </inspection_tool>
<inspection_tool class="FieldMayBeFinal" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LocalCanBeFinal" enabled="true" level="WARNING" enabled_by_default="true">
<option name="REPORT_VARIABLES" value="true" />
<option name="REPORT_PARAMETERS" value="false" />
</inspection_tool>
</profile> </profile>
</component> </component>

View File

@ -109,12 +109,12 @@ class MainTest {
} }
@Test @Test
void newest_ilias_shit() throws IOException { void newestIliasShit() throws IOException {
cmpInOut("newest_ilias_shit_input.txt", "newest_ilias_shit_output.txt"); cmpInOut("newest_ilias_shit_input.txt", "newest_ilias_shit_output.txt");
} }
@Test @Test
void long_train() throws IOException { void longTrain() throws IOException {
cmpInOut("long_train_input.txt", "long_train_output.txt"); cmpInOut("long_train_input.txt", "long_train_output.txt");
} }

View File

@ -4,7 +4,7 @@ package edu.kit.informatik.model;
* Generic rail that other rails can connect to. * Generic rail that other rails can connect to.
* *
* @author Arne Keller * @author Arne Keller
* @version 1.0 * @version 1.2
*/ */
public abstract class Rail { public abstract class Rail {
/** /**
@ -16,7 +16,7 @@ public abstract class Rail {
* Initialize a new rail with the specified identifier. * Initialize a new rail with the specified identifier.
* @param id the identifier of this rail * @param id the identifier of this rail
*/ */
protected Rail(final int id) { protected Rail(int id) {
this.id = id; this.id = id;
} }
@ -27,6 +27,13 @@ public abstract class Rail {
return this.id; return this.id;
} }
/**
* Calculate the (Manhattan) length of this rail.
*
* @return the length of this rail
*/
public abstract long getLength();
/** /**
* @param point point to check for connection * @param point point to check for connection
* @return whether the rail currently connects to the point * @return whether the rail currently connects to the point
@ -45,20 +52,6 @@ public abstract class Rail {
*/ */
public abstract boolean canConnectToRail(Rail rail); public abstract boolean canConnectToRail(Rail rail);
/**
* Try to set the rail to connect to this position. Obviously only makes sense for switches and similar rails.
* @param position point to connect to
* @return whether rail could be successfully set
*/
public boolean switchTo(Vector2D position) {
return false;
}
/**
* @return whether the rail is ready for trains running on it
*/
public abstract boolean isReadyForTrains();
/** /**
* @param position the point to check * @param position the point to check
* @return whether the point is inside this rail (not on the edge) * @return whether the point is inside this rail (not on the edge)
@ -72,7 +65,17 @@ public abstract class Rail {
public abstract boolean canContain(Vector2D position); public abstract boolean canContain(Vector2D position);
/** /**
* Get the direction trains can move on this rail starting at the specified position * Try to set the rail to connect to this position. Obviously only makes sense for switches and similar rails.
* @param position point to connect to
* @return whether rail could be successfully set
*/
public boolean switchTo(Vector2D position) {
return false;
}
/**
* Get the direction trains can move on this rail starting at the specified position.
*
* @param position the position to check * @param position the position to check
* @return the direction trains can move starting at that position * @return the direction trains can move starting at that position
*/ */
@ -80,8 +83,9 @@ public abstract class Rail {
/** /**
* Check whether this rail extends in the specified direction. * Check whether this rail extends in the specified direction.
*
* @param position start position * @param position start position
* @param direction the (normalized) direction to check * @param direction the normalized direction vector to check
* @return whether this rail can extend from that position in that direction * @return whether this rail can extend from that position in that direction
*/ */
public abstract boolean allowsDirectionFrom(Vector2D position, Vector2D direction); public abstract boolean allowsDirectionFrom(Vector2D position, Vector2D direction);
@ -98,9 +102,7 @@ public abstract class Rail {
public abstract Vector2D move(Vector2D position, Vector2D direction, long steps); public abstract Vector2D move(Vector2D position, Vector2D direction, long steps);
/** /**
* Calculate the (Manhattan) length of this rail. * @return whether the rail is ready for trains running on it
*
* @return the length of this rail
*/ */
public abstract long getLength(); public abstract boolean isReadyForTrains();
} }

View File

@ -11,6 +11,7 @@ import java.util.Optional;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream;
/** /**
* A rail network consisting of tracks and switches. Is only concerned with rails, does not process trains. * A rail network consisting of tracks and switches. Is only concerned with rails, does not process trains.
@ -31,27 +32,27 @@ public class RailwayNetwork {
* @return the positive identifier of the new track if successful, -1 if none available * @return the positive identifier of the new track if successful, -1 if none available
* @throws InvalidInputException if the user provides incorrect input * @throws InvalidInputException if the user provides incorrect input
*/ */
public int addTrack(final Vector2D start, final Vector2D end) throws InvalidInputException { public int addTrack(Vector2D start, Vector2D end) throws InvalidInputException {
if (start.distanceTo(end) == 0) { if (start.distanceTo(end) == 0) {
throw new InvalidInputException("track has length zero"); throw new InvalidInputException("track has length zero");
} }
long startPossibleConnections = rails.values().stream().filter(rail -> rail.canConnectTo(start)).count(); final long startPossibleConnections = rails.values().stream().filter(rail -> rail.canConnectTo(start)).count();
long endPossibleConnections = rails.values().stream().filter(rail -> rail.canConnectTo(end)).count(); final long endPossibleConnections = rails.values().stream().filter(rail -> rail.canConnectTo(end)).count();
if (startPossibleConnections == 2 || endPossibleConnections == 2) { if (startPossibleConnections == 2 || endPossibleConnections == 2) {
throw new InvalidInputException("track would connect to two other rails"); throw new InvalidInputException("track would connect to two other rails");
} }
if (rails.isEmpty()) { if (rails.isEmpty()) {
Track newTrack = new Track(start, end, 1); final Track newTrack = new Track(start, end, 1);
rails.put(1, newTrack); rails.put(1, newTrack);
return newTrack.getIdentifier(); return newTrack.getIdentifier();
} else { } else {
for (Rail rail : rails.values()) { for (final Rail rail : rails.values()) {
if (rail.canConnectTo(start) || rail.canConnectTo(end)) { if (rail.canConnectTo(start) || rail.canConnectTo(end)) {
int id = getNextRailIdentifier(); final int id = getNextRailIdentifier();
if (id < 0) { if (id < 0) {
return -1; return -1;
} }
Track newTrack = new Track(start, end, id); final Track newTrack = new Track(start, end, id);
rails.put(id, newTrack); rails.put(id, newTrack);
return newTrack.getIdentifier(); return newTrack.getIdentifier();
} }
@ -68,28 +69,28 @@ public class RailwayNetwork {
* @return the positive identifier of the switch if successful, -1 otherwise * @return the positive identifier of the switch if successful, -1 otherwise
* @throws InvalidInputException when the new switch would be invalid * @throws InvalidInputException when the new switch would be invalid
*/ */
public int addSwitch(final Vector2D start, final Vector2D end1, final Vector2D end2) throws InvalidInputException { public int addSwitch(Vector2D start, Vector2D end1, Vector2D end2) throws InvalidInputException {
if (start.distanceTo(end1) == 0 || start.distanceTo(end2) == 0 || end1.distanceTo(end2) == 0) { if (start.distanceTo(end1) == 0 || start.distanceTo(end2) == 0 || end1.distanceTo(end2) == 0) {
throw new InvalidInputException("switch has length zero"); throw new InvalidInputException("switch has length zero");
} }
if (rails.isEmpty()) { if (rails.isEmpty()) {
Switch newSwitch = new Switch(start, end1, end2, 1); final Switch newSwitch = new Switch(start, end1, end2, 1);
rails.put(1, newSwitch); rails.put(1, newSwitch);
return newSwitch.getIdentifier(); return newSwitch.getIdentifier();
} else { } else {
long startPossibleConnections = rails.values().stream().filter(rail -> rail.canConnectTo(start)).count(); final long startConnections = rails.values().stream().filter(rail -> rail.canConnectTo(start)).count();
long end1PossibleConnections = rails.values().stream().filter(rail -> rail.canConnectTo(end1)).count(); final long end1Connections = rails.values().stream().filter(rail -> rail.canConnectTo(end1)).count();
long end2PossibleConnections = rails.values().stream().filter(rail -> rail.canConnectTo(end2)).count(); final long end2Connections = rails.values().stream().filter(rail -> rail.canConnectTo(end2)).count();
if (startPossibleConnections == 2 || end1PossibleConnections == 2 || end2PossibleConnections == 2) { if (startConnections == 2 || end1Connections == 2 || end2Connections == 2) {
throw new InvalidInputException("switch endpoint would connect to two other rails"); throw new InvalidInputException("switch endpoint would connect to two other rails");
} }
if (rails.values().stream() if (rails.values().stream()
.anyMatch(rail -> rail.canConnectTo(start) || rail.canConnectTo(end1) || rail.canConnectTo(end2))) { .anyMatch(rail -> rail.canConnectTo(start) || rail.canConnectTo(end1) || rail.canConnectTo(end2))) {
int id = getNextRailIdentifier(); final int id = getNextRailIdentifier();
if (id < 0) { if (id < 0) {
return -1; return -1;
} }
Switch newSwitch = new Switch(start, end1, end2, id); final Switch newSwitch = new Switch(start, end1, end2, id);
rails.put(id, newSwitch); rails.put(id, newSwitch);
return newSwitch.getIdentifier(); return newSwitch.getIdentifier();
} else { } else {
@ -112,15 +113,15 @@ public class RailwayNetwork {
* @param id identifier of the rail to remove * @param id identifier of the rail to remove
* @return whether the rail could be successfully removed * @return whether the rail could be successfully removed
*/ */
public boolean removeRail(final int id) { public boolean removeRail(int id) {
Rail toRemove = rails.get(id); final Rail toRemove = rails.get(id);
if (toRemove == null) { if (toRemove == null) {
return false; return false;
} }
// locate one connected rail // locate one connected rail
Rail otherRail = null; Rail otherRail = null;
for (Rail anotherRail : rails.values()) { for (final Rail anotherRail : rails.values()) {
if (anotherRail.getIdentifier() != id && anotherRail.canConnectToRail(toRemove)) { if (anotherRail.getIdentifier() != id && anotherRail.canConnectToRail(toRemove)) {
otherRail = anotherRail; otherRail = anotherRail;
break; break;
@ -134,16 +135,16 @@ public class RailwayNetwork {
} }
// check that rails would still be connected after removing this rail // check that rails would still be connected after removing this rail
Set<Rail> connectedRails = new HashSet<>(); final Set<Rail> connectedRails = new HashSet<>();
connectedRails.add(otherRail); connectedRails.add(otherRail);
Queue<Rail> toProcess = new LinkedList<>(); final Queue<Rail> toProcess = new LinkedList<>();
toProcess.add(otherRail); toProcess.add(otherRail);
// basically breadth-first search, using a queue // basically breadth-first search, using a queue
while (!toProcess.isEmpty()) { while (!toProcess.isEmpty()) {
Rail connected = toProcess.poll(); final Rail connected = toProcess.poll();
for (Rail other : rails.values()) { for (final Rail other : rails.values()) {
if (other != toRemove && !connectedRails.contains(other) && other.canConnectToRail(connected)) { if (other != toRemove && !connectedRails.contains(other) && other.canConnectToRail(connected)) {
connectedRails.add(other); connectedRails.add(other);
toProcess.offer(other); toProcess.offer(other);
@ -166,7 +167,7 @@ public class RailwayNetwork {
* @return whether the switch could be set * @return whether the switch could be set
*/ */
public boolean setSwitch(final int id, final Vector2D position) { public boolean setSwitch(final int id, final Vector2D position) {
Rail toSwitch = rails.get(id); final Rail toSwitch = rails.get(id);
if (toSwitch != null) { if (toSwitch != null) {
return toSwitch.switchTo(position); return toSwitch.switchTo(position);
} }
@ -187,12 +188,9 @@ public class RailwayNetwork {
* @return the next positive rail identifier, or -1 if none available * @return the next positive rail identifier, or -1 if none available
*/ */
private int getNextRailIdentifier() { private int getNextRailIdentifier() {
for (int i = 1; i > 0; i++) { return IntStream.rangeClosed(1, Integer.MAX_VALUE)
if (!rails.containsKey(i)) { .filter(id -> !rails.containsKey(id))
return i; .findFirst().orElse(-1);
}
}
return -1;
} }
/** /**
@ -204,13 +202,13 @@ public class RailwayNetwork {
* @return next position, null if off the rails after single step * @return next position, null if off the rails after single step
*/ */
public Vector2D move(Vector2D position, Vector2D direction, long steps) { public Vector2D move(Vector2D position, Vector2D direction, long steps) {
Rail containingRail = findContainingRail(position); final Rail containingRail = findContainingRail(position);
if (containingRail != null) { if (containingRail != null) {
return containingRail.move(position, direction, steps); return containingRail.move(position, direction, steps);
} }
Rail[] touchingRails = findTouchingRails(position); final Rail[] touchingRails = findTouchingRails(position);
Vector2D nextPossiblePosition = position.add(direction); final Vector2D nextPossiblePosition = position.add(direction);
Rail possibleContainingRail = findRailPotentiallyContaining(nextPossiblePosition); final Rail possibleContainingRail = findRailPotentiallyContaining(nextPossiblePosition);
if (possibleContainingRail != null && !possibleContainingRail.contains(position.subtract(direction))) { if (possibleContainingRail != null && !possibleContainingRail.contains(position.subtract(direction))) {
return possibleContainingRail.move(position, direction, steps); return possibleContainingRail.move(position, direction, steps);
@ -220,15 +218,15 @@ public class RailwayNetwork {
} else if (touchingRails.length == 1) { } else if (touchingRails.length == 1) {
return touchingRails[0].move(position, direction, 1); return touchingRails[0].move(position, direction, 1);
} }
Vector2D onRailOne = touchingRails[0].move(position, new Vector2D(direction), steps); final Vector2D onRailOne = touchingRails[0].move(position, new Vector2D(direction), steps);
Vector2D onRailTwo = touchingRails[1].move(position, new Vector2D(direction), steps); final Vector2D onRailTwo = touchingRails[1].move(position, new Vector2D(direction), steps);
if (position.equals(onRailOne) || onRailOne == null) { if (position.equals(onRailOne) || onRailOne == null) {
// we are moving on rail two // we are moving on rail two
Vector2D newDirection = touchingRails[1].getDirectionFrom(position); final Vector2D newDirection = touchingRails[1].getDirectionFrom(position);
direction.copyFrom(newDirection); direction.copyFrom(newDirection);
return onRailTwo; return onRailTwo;
} else if (position.equals(onRailTwo) || onRailTwo == null) { } else if (position.equals(onRailTwo) || onRailTwo == null) {
Vector2D newDirection = touchingRails[0].getDirectionFrom(position); final Vector2D newDirection = touchingRails[0].getDirectionFrom(position);
direction.copyFrom(newDirection); direction.copyFrom(newDirection);
return onRailOne; return onRailOne;
} else { } else {

View File

@ -30,8 +30,7 @@ public abstract class RollingStock {
* @param couplingBack whether this rolling stock should have a back coupling * @param couplingBack whether this rolling stock should have a back coupling
* @throws InvalidInputException on invalid user input (e.g. zero-sized coach) * @throws InvalidInputException on invalid user input (e.g. zero-sized coach)
*/ */
protected RollingStock(final int length, final boolean couplingFront, final boolean couplingBack) protected RollingStock(int length, boolean couplingFront, boolean couplingBack) throws InvalidInputException {
throws InvalidInputException {
if (length < 1) { if (length < 1) {
throw new InvalidInputException("rolling stock length has to be positive"); throw new InvalidInputException("rolling stock length has to be positive");
} }

View File

@ -30,8 +30,8 @@ public class SteamEngine extends Engine {
* @param couplingBack whether the engine should have a back coupling * @param couplingBack whether the engine should have a back coupling
* @throws InvalidInputException on invalid user input (e.g. zero-sized engine) * @throws InvalidInputException on invalid user input (e.g. zero-sized engine)
*/ */
public SteamEngine(final String series, final String name, final int length, public SteamEngine(String series, String name, int length, boolean couplingFront, boolean couplingBack)
final boolean couplingFront, final boolean couplingBack) throws InvalidInputException { throws InvalidInputException {
super(series, name, length, couplingFront, couplingBack); super(series, name, length, couplingFront, couplingBack);
} }

View File

@ -5,7 +5,7 @@ import edu.kit.informatik.ui.InvalidInputException;
import java.util.Objects; import java.util.Objects;
/** /**
* A switch in the rail network. It connects a start position to two other positions. * A switch in the rail network. It connects a start position to one of two other positions.
* *
* @author Arne Keller * @author Arne Keller
* @version 1.0 * @version 1.0
@ -26,20 +26,15 @@ public final class Switch extends Rail {
/** /**
* Construct a new switch. * Construct a new switch.
*
* @param start start position * @param start start position
* @param end1 end position 1 * @param end1 end position 1
* @param end2 end position 2 * @param end2 end position 2
* @param id identifier of this switch * @param id identifier of this switch
* @throws InvalidInputException if the switch is not composed of straight lines * @throws InvalidInputException if the switch is not composed of straight lines
*/ */
public Switch(final Vector2D start, final Vector2D end1, final Vector2D end2, final int id) public Switch(Vector2D start, Vector2D end1, Vector2D end2, int id) throws InvalidInputException {
throws InvalidInputException {
super(id); super(id);
if (start.getX() != end1.getX() && start.getY() != end1.getY()
|| start.getX() != end2.getX() && start.getY() != end2.getY()) {
throw new InvalidInputException("start has to be connected in straight lines to end positions!");
}
// make sure caller can not modify internal state after calling
this.positionOne = new Track(start, end1, -1); this.positionOne = new Track(start, end1, -1);
this.positionTwo = new Track(start, end2, -1); this.positionTwo = new Track(start, end2, -1);
} }
@ -122,8 +117,8 @@ public final class Switch extends Rail {
@Override @Override
public String toString() { public String toString() {
if (selection == null) { if (selection == null) {
return String.format("s %d %s -> %s,%s", getIdentifier(), positionOne.getStart(), return String.format("s %d %s -> %s,%s", getIdentifier(),
positionOne.getEnd(), positionTwo.getEnd()); positionOne.getStart(), positionOne.getEnd(), positionTwo.getEnd());
} else { } else {
return String.format("s %d %s -> %s,%s %d", getIdentifier(), return String.format("s %d %s -> %s,%s %d", getIdentifier(),
positionOne.getStart(), positionOne.getEnd(), positionTwo.getEnd(), getLength()); positionOne.getStart(), positionOne.getEnd(), positionTwo.getEnd(), getLength());
@ -131,7 +126,7 @@ public final class Switch extends Rail {
} }
@Override @Override
public boolean equals(final Object obj) { public boolean equals(Object obj) {
if (obj != null && getClass().equals(obj.getClass())) { if (obj != null && getClass().equals(obj.getClass())) {
final Switch otherSwitch = (Switch) obj; final Switch otherSwitch = (Switch) obj;

View File

@ -62,14 +62,14 @@ public final class Track extends Rail {
return false; return false;
} }
if (start.getX() == end.getX() && position.getX() == start.getX()) { if (start.getX() == end.getX() && position.getX() == start.getX()) {
int startY = start.getY(); long startY = start.getY();
int endY = end.getY(); long endY = end.getY();
int positionY = position.getY(); long positionY = position.getY();
return startY < positionY && positionY < endY || startY > positionY && positionY > endY; return startY < positionY && positionY < endY || startY > positionY && positionY > endY;
} else if (start.getY() == end.getY() && position.getY() == start.getY()) { } else if (start.getY() == end.getY() && position.getY() == start.getY()) {
int startX = start.getX(); long startX = start.getX();
int endX = end.getX(); long endX = end.getX();
int positionX = position.getX(); long positionX = position.getX();
return startX < positionX && positionX < endX || startX > positionX && positionX > endX; return startX < positionX && positionX < endX || startX > positionX && positionX > endX;
} }
return false; return false;
@ -103,11 +103,11 @@ public final class Track extends Rail {
public Vector2D getDirectionFrom(Vector2D position) { public Vector2D getDirectionFrom(Vector2D position) {
// have to use long arithmetic here to avoid overflows // have to use long arithmetic here to avoid overflows
if (start.equals(position)) { if (start.equals(position)) {
return new Vector2D(Long.signum((long) end.getX() - (long) start.getX()), return new Vector2D(Long.signum(end.getX() - start.getX()),
Long.signum((long) end.getY() - (long) start.getY())); Long.signum(end.getY() - start.getY()));
} else if (end.equals(position)) { } else if (end.equals(position)) {
return new Vector2D(Long.signum((long) start.getX() - (long) end.getX()), return new Vector2D(Long.signum(start.getX() - end.getX()),
Long.signum((long) start.getY() - (long) end.getY())); Long.signum(start.getY() - end.getY()));
} else { } else {
// in the middle of track, simply return direction from start // in the middle of track, simply return direction from start
return getDirectionFrom(start); return getDirectionFrom(start);

View File

@ -40,10 +40,11 @@ public final class Train {
/** /**
* Construct a new train. * Construct a new train.
*
* @param identifier identifier to use * @param identifier identifier to use
* @param rollingStock initial rolling stock * @param rollingStock initial rolling stock
*/ */
public Train(final int identifier, final RollingStock rollingStock) { public Train(int identifier, RollingStock rollingStock) {
this.identifier = identifier; this.identifier = identifier;
this.rollingStocks.add(rollingStock); this.rollingStocks.add(rollingStock);
} }
@ -69,7 +70,7 @@ public final class Train {
* @throws InvalidInputException if the rolling stock could not be added to the train * @throws InvalidInputException if the rolling stock could not be added to the train
*/ */
public void add(RollingStock rollingStock) throws InvalidInputException { public void add(RollingStock rollingStock) throws InvalidInputException {
RollingStock last = rollingStocks.get(rollingStocks.size() - 1); final RollingStock last = rollingStocks.get(rollingStocks.size() - 1);
if (rollingStock.hasCouplingFront() && last.hasCouplingBack() if (rollingStock.hasCouplingFront() && last.hasCouplingBack()
&& rollingStock.canCoupleTo(last) && last.canCoupleTo(rollingStock)) { && rollingStock.canCoupleTo(last) && last.canCoupleTo(rollingStock)) {
rollingStocks.add(rollingStock); rollingStocks.add(rollingStock);
@ -80,8 +81,8 @@ public final class Train {
@Override @Override
public String toString() { public String toString() {
StringBuilder stringBuilder = new StringBuilder(Integer.toString(getIdentifier())); final StringBuilder stringBuilder = new StringBuilder(Integer.toString(getIdentifier()));
for (RollingStock rollingStock : rollingStocks) { for (final RollingStock rollingStock : rollingStocks) {
stringBuilder.append(' '); stringBuilder.append(' ');
stringBuilder.append(rollingStock.getIdentifier()); stringBuilder.append(rollingStock.getIdentifier());
} }
@ -94,15 +95,15 @@ public final class Train {
* @return rows of ASCII art * @return rows of ASCII art
*/ */
public List<String> show() { public List<String> show() {
List<StringBuilder> lines = new ArrayList<>(); final List<StringBuilder> lines = new ArrayList<>();
for (RollingStock rollingStock : rollingStocks) { for (final RollingStock rollingStock : rollingStocks) {
for (StringBuilder line : lines) { for (final StringBuilder line : lines) {
line.append(' '); line.append(' ');
} }
String[] text = rollingStock.textRepresentation(); final String[] text = rollingStock.textRepresentation();
int currentLength = lines.stream().mapToInt(StringBuilder::length).max().orElse(0); final int currentLength = lines.stream().mapToInt(StringBuilder::length).max().orElse(0);
while (lines.size() < text.length) { while (lines.size() < text.length) {
StringBuilder line = new StringBuilder(); final StringBuilder line = new StringBuilder();
for (int i = 0; i < currentLength; i++) { for (int i = 0; i < currentLength; i++) {
line.append(' '); line.append(' ');
} }
@ -111,8 +112,8 @@ public final class Train {
for (int i = 0; i < text.length; i++) { for (int i = 0; i < text.length; i++) {
lines.get(lines.size() - 1 - i).append(text[text.length - 1 - i]); lines.get(lines.size() - 1 - i).append(text[text.length - 1 - i]);
} }
int finalLength = lines.stream().mapToInt(StringBuilder::length).max().getAsInt(); final int finalLength = lines.stream().mapToInt(StringBuilder::length).max().getAsInt();
for (StringBuilder line : lines) { for (final StringBuilder line : lines) {
while (line.length() < finalLength) { while (line.length() < finalLength) {
line.append(' '); line.append(' ');
} }
@ -127,7 +128,7 @@ public final class Train {
* @param rail the rail to check * @param rail the rail to check
* @return whether this train is on that rail * @return whether this train is on that rail
*/ */
public boolean isOnRail(final Rail rail) { public boolean isOnRail(Rail rail) {
return isPlaced() && (occupiedRails.stream().anyMatch(blockedRail -> blockedRail == rail) return isPlaced() && (occupiedRails.stream().anyMatch(blockedRail -> blockedRail == rail)
|| positions.stream().anyMatch(rail::canConnectTo)); || positions.stream().anyMatch(rail::canConnectTo));
} }
@ -180,7 +181,8 @@ public final class Train {
if (occupiedRailsSet.contains(occupiedRail) && positionList.size() >= 4) { if (occupiedRailsSet.contains(occupiedRail) && positionList.size() >= 4) {
// perhaps a self intersection // perhaps a self intersection
final long occupiedAtFrontOfTrain = positionList.get(0).distanceTo(positionList.get(1)); final long occupiedAtFrontOfTrain = positionList.get(0).distanceTo(positionList.get(1));
final long occupiedAtBackOfTrain = positionList.getLast().distanceTo(positionList.get(positionList.size() - 2)); final long occupiedAtBackOfTrain = positionList.getLast()
.distanceTo(positionList.get(positionList.size() - 2));
if (occupiedAtFrontOfTrain + occupiedAtBackOfTrain > occupiedRail.getLength()) { if (occupiedAtFrontOfTrain + occupiedAtBackOfTrain > occupiedRail.getLength()) {
// train definitely intersects itself // train definitely intersects itself
return false; return false;
@ -246,7 +248,10 @@ public final class Train {
} }
/** /**
* @return a set of the rails this train occupies currently * Get the rails this train currently occupies a non-empty part of. Simply touching a point of another rail will
* not include that rail in this set.
*
* @return a set of the rails this train occupies
*/ */
public Set<Rail> getOccupiedRails() { public Set<Rail> getOccupiedRails() {
// make sure caller can not modify internal state // make sure caller can not modify internal state
@ -301,8 +306,10 @@ public final class Train {
if (backPosition != null) { if (backPosition != null) {
// not derailing // not derailing
positions.addLast(new Vector2D(backPosition)); positions.addLast(new Vector2D(backPosition));
if (positions.size() >= 3 && backPosition.subtract(positions.get(positions.size() - 2)).normalized() if (positions.size() >= 3
.equals(positions.get(positions.size() - 2).subtract(positions.get(positions.size() - 3)).normalized()) && backPosition.subtract(positions.get(positions.size() - 2)).normalized()
.equals(positions.get(positions.size() - 2)
.subtract(positions.get(positions.size() - 3)).normalized())
&& railNetwork.findTouchingRails(positions.get(positions.size() - 2)).length == 0) { && railNetwork.findTouchingRails(positions.get(positions.size() - 2)).length == 0) {
positions.remove(positions.size() - 2); positions.remove(positions.size() - 2);
} }
@ -319,11 +326,13 @@ public final class Train {
} }
/** /**
* Check whether this train touches another train. It is considered touching if two trains are behind each other. * Check whether this train touches another train.
* Two trains ends occupying the same point is also considered touching.
*
* @param other other train * @param other other train
* @return whether this train touches the other train * @return whether this train touches the other train
*/ */
public boolean touches(final Train other) { public boolean touches(Train other) {
return positions != null && other.isOnAnyPosition(positions); return positions != null && other.isOnAnyPosition(positions);
} }
@ -333,7 +342,7 @@ public final class Train {
* @param point position to check * @param point position to check
* @return whether this train is on the specified position * @return whether this train is on the specified position
*/ */
public boolean isOnPosition(final Vector2D point) { public boolean isOnPosition(Vector2D point) {
return positions.contains(point); return positions.contains(point);
} }

View File

@ -245,8 +245,9 @@ public final class TrainManager {
*/ */
private void addToSetOrAddNew(List<Set<Train>> setList, Set<Train> newSet) { private void addToSetOrAddNew(List<Set<Train>> setList, Set<Train> newSet) {
Set<Train> existing = null; Set<Train> existing = null;
for (int i = 0; i < setList.size(); i++) { int i = 0;
Set<Train> otherSet = setList.get(i); while (i < setList.size()) {
final Set<Train> otherSet = setList.get(i);
if (otherSet.stream().anyMatch(newSet::contains)) { if (otherSet.stream().anyMatch(newSet::contains)) {
if (existing == null) { if (existing == null) {
existing = otherSet; existing = otherSet;
@ -254,9 +255,10 @@ public final class TrainManager {
} else { } else {
existing.addAll(otherSet); existing.addAll(otherSet);
setList.remove(i); setList.remove(i);
i--; continue;
} }
} }
i++;
} }
if (existing == null) { if (existing == null) {
setList.add(newSet); setList.add(newSet);

View File

@ -41,8 +41,8 @@ public class TrainSet extends RollingStock {
* @param couplingBack whether the train set should have a back coupling * @param couplingBack whether the train set should have a back coupling
* @throws InvalidInputException on invalid user input (e.g. zero-sized train set) * @throws InvalidInputException on invalid user input (e.g. zero-sized train set)
*/ */
public TrainSet(final String series, final String name, final int length, public TrainSet(String series, String name, int length, boolean couplingFront, boolean couplingBack)
final boolean couplingFront, final boolean couplingBack) throws InvalidInputException { throws InvalidInputException {
super(length, couplingFront, couplingBack); super(length, couplingFront, couplingBack);
this.name = name; this.name = name;
this.series = series; this.series = series;

View File

@ -42,9 +42,9 @@ public class Vector2D {
* @return a vector containing the two numbers, null otherwise * @return a vector containing the two numbers, null otherwise
*/ */
public static Vector2D parse(final String input) { public static Vector2D parse(final String input) {
String[] coordinates = input.split(",", 2); final String[] coordinates = input.split(",", 2);
int x = Integer.parseInt(coordinates[0]); final int x = Integer.parseInt(coordinates[0]);
int y = Integer.parseInt(coordinates[1]); final int y = Integer.parseInt(coordinates[1]);
return new Vector2D(x, y); return new Vector2D(x, y);
} }
@ -97,7 +97,6 @@ public class Vector2D {
* Subtract another vector from this one, modifying this vector. * Subtract another vector from this one, modifying this vector.
* *
* @param other another vector * @param other another vector
* @throws NullPointerException if other is null
*/ */
public void subtractInPlace(Vector2D other) { public void subtractInPlace(Vector2D other) {
x -= other.x; x -= other.x;
@ -111,60 +110,35 @@ public class Vector2D {
public Vector2D add(Vector2D movement) { public Vector2D add(Vector2D movement) {
return new Vector2D(x + movement.x, y + movement.y); return new Vector2D(x + movement.x, y + movement.y);
} }
/**
* Calculate multiplier * this, and return a new vector.
*
* @param multiplier any scalar
* @return scaled vector
*/
public Vector2D scale(long multiplier) { public Vector2D scale(long multiplier) {
return new Vector2D(x * multiplier, y * multiplier); return new Vector2D(x * multiplier, y * multiplier);
} }
/** /**
* @return the first component of this vector, casted to an int * @return the first component of this vector
*/ */
public int getX() { public long getX() {
return (int) x;
}
/**
*
* @return
*/
public long getLongX() {
return x; return x;
} }
/** /**
* @return the second component of this vector, casted to an int * @return the second component of this vector
*/ */
public int getY() { public long getY() {
return (int) y;
}
/**
*
* @return
*/
public long getLongY() {
return y; return y;
} }
/** /**
* Change the value of the first component of the vector * Copy another vectors' components into this one.
* @param x value to change to *
*/ * @param other vector to copy data from
public void setX(final int x) {
this.x = x;
}
/**
* Change the value of the second component of the vector
* @param y value to change to
*/
public void setY(final int y) {
this.y = y;
}
/**
*
* @param other
*/ */
public void copyFrom(Vector2D other) { public void copyFrom(Vector2D other) {
this.x = other.x; this.x = other.x;
@ -172,9 +146,9 @@ public class Vector2D {
} }
@Override @Override
public boolean equals(final Object obj) { public boolean equals(Object obj) {
if (obj != null && getClass().equals(obj.getClass())) { if (obj != null && getClass().equals(obj.getClass())) {
Vector2D point = (Vector2D) obj; final Vector2D point = (Vector2D) obj;
return x == point.x && y == point.y; return x == point.x && y == point.y;
} }

View File

@ -11,7 +11,7 @@ public class InvalidInputException extends Exception {
* Construct a new invalid input exception with a specific message. * Construct a new invalid input exception with a specific message.
* @param message the error message * @param message the error message
*/ */
public InvalidInputException(final String message) { public InvalidInputException(String message) {
super(message); super(message);
} }
} }

View File

@ -106,8 +106,8 @@ OK
OK OK
Crash of train 2 Crash of train 2
Crash of train 3,4,5 Crash of train 3,4,5
Error, start has to be connected in straight lines to end positions! Error, invalid track segment: not a straight line
Error, start has to be connected in straight lines to end positions! Error, invalid track segment: not a straight line
Error, invalid add switch argument syntax Error, invalid add switch argument syntax
Error, invalid/missing delete track argument Error, invalid/missing delete track argument
Error, too many arguments for list tracks Error, too many arguments for list tracks