mirror of
https://gitlab.com/arnekeller/kit-programmieren-ws1920-final1.git
synced 2024-11-27 18:55:55 +00:00
Optimize large train placement
This commit is contained in:
parent
70a070d9b1
commit
4fad0a377e
@ -3,6 +3,7 @@ add track (0,0) -> (-2147483648,0)
|
||||
list tracks
|
||||
create engine electrical T3 Marie 1 false true
|
||||
add train 1 T3-Marie
|
||||
put train 1 at (0,0) in direction 0,-1
|
||||
put train 1 at (0,0) in direction -1,0
|
||||
step 1000
|
||||
delete train 1
|
||||
|
@ -4,6 +4,7 @@ t 1 (2147483647,0) -> (0,0) 2147483647
|
||||
t 2 (0,0) -> (-2147483648,0) 2147483648
|
||||
T3-Marie
|
||||
electrical engine T3-Marie added to train 1
|
||||
Error, could not place train
|
||||
OK
|
||||
Train 1 at (-1000,0)
|
||||
OK
|
||||
|
13
long_train_input.txt
Normal file
13
long_train_input.txt
Normal file
@ -0,0 +1,13 @@
|
||||
add track (2147483647,0) -> (0,0)
|
||||
add track (0,0) -> (-2147483648,0)
|
||||
list tracks
|
||||
create engine electrical T3 Marie 2147483647 false true
|
||||
create coach passenger 2147483647 true false
|
||||
add train 1 T3-Marie
|
||||
add train 1 W1
|
||||
put train 1 at (-2147483647,0) in direction -1,0
|
||||
step 1
|
||||
step 1
|
||||
put train 1 at (-2147483647,0) in direction -1,0
|
||||
step -1
|
||||
exit
|
13
long_train_output.txt
Normal file
13
long_train_output.txt
Normal file
@ -0,0 +1,13 @@
|
||||
1
|
||||
2
|
||||
t 1 (2147483647,0) -> (0,0) 2147483647
|
||||
t 2 (0,0) -> (-2147483648,0) 2147483648
|
||||
T3-Marie
|
||||
1
|
||||
electrical engine T3-Marie added to train 1
|
||||
passenger coach W1 added to train 1
|
||||
OK
|
||||
Train 1 at (-2147483648,0)
|
||||
Crash of train 1
|
||||
OK
|
||||
Crash of train 1
|
@ -113,6 +113,11 @@ class MainTest {
|
||||
cmpInOut("newest_ilias_shit_input.txt", "newest_ilias_shit_output.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
void long_train() throws IOException {
|
||||
cmpInOut("long_train_input.txt", "long_train_output.txt");
|
||||
}
|
||||
|
||||
private void cmpInOut(String in, String out) throws IOException {
|
||||
System.setIn(new ByteArrayInputStream(readFile(in)));
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
|
@ -87,11 +87,20 @@ public abstract class Rail {
|
||||
public abstract boolean allowsDirectionFrom(Vector2D position, Vector2D direction);
|
||||
|
||||
/**
|
||||
* Move a position along this rail in the specified direction for the specified amount of steps. This method will
|
||||
* stop at the end of the rail, even if that will omit some steps.
|
||||
*
|
||||
* @param position
|
||||
* @param direction
|
||||
* @param steps
|
||||
* @return
|
||||
* @param position position to move from
|
||||
* @param direction direction to go
|
||||
* @param steps amount of steps
|
||||
* @return moved position
|
||||
*/
|
||||
public abstract Vector2D move(Vector2D position, Vector2D direction, long steps);
|
||||
|
||||
/**
|
||||
* Calculate the (Manhattan) length of this rail.
|
||||
*
|
||||
* @return the length of this rail
|
||||
*/
|
||||
public abstract long getLength();
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
package edu.kit.informatik.model;
|
||||
|
||||
import edu.kit.informatik.Terminal;
|
||||
import edu.kit.informatik.ui.InvalidInputException;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
@ -198,20 +197,22 @@ public class RailwayNetwork {
|
||||
|
||||
/**
|
||||
* Move a position along the rails of this rail network in the specified direction.
|
||||
*
|
||||
* @param position the position to move
|
||||
* @param direction has to be (0,1) (0,-1) (1,0) (-1,0), will be modified if turn is necessary
|
||||
* @return next position, null if off the rails
|
||||
* @param steps amount of steps to go
|
||||
* @return next position, null if off the rails after single step
|
||||
*/
|
||||
public Vector2D move(Vector2D position, Vector2D direction) {
|
||||
public Vector2D move(Vector2D position, Vector2D direction, long steps) {
|
||||
Rail containingRail = findContainingRail(position);
|
||||
if (containingRail != null) {
|
||||
return position.add(direction);
|
||||
return containingRail.move(position, direction, steps);
|
||||
}
|
||||
Rail[] touchingRails = findTouchingRails(position);
|
||||
Vector2D nextPossiblePosition = position.add(direction);
|
||||
Rail possibleContainingRail = findRailPotentiallyContaining(nextPossiblePosition);
|
||||
if (possibleContainingRail != null && !possibleContainingRail.contains(position.subtract(direction))) {
|
||||
return possibleContainingRail.move(position, direction, 1);
|
||||
return possibleContainingRail.move(position, direction, steps);
|
||||
|
||||
}
|
||||
if (touchingRails.length == 0) {
|
||||
@ -219,8 +220,8 @@ public class RailwayNetwork {
|
||||
} else if (touchingRails.length == 1) {
|
||||
return touchingRails[0].move(position, direction, 1);
|
||||
}
|
||||
Vector2D onRailOne = touchingRails[0].move(position, new Vector2D(direction), 1);
|
||||
Vector2D onRailTwo = touchingRails[1].move(position, new Vector2D(direction), 1);
|
||||
Vector2D onRailOne = touchingRails[0].move(position, new Vector2D(direction), steps);
|
||||
Vector2D onRailTwo = touchingRails[1].move(position, new Vector2D(direction), steps);
|
||||
if (position.equals(onRailOne) || onRailOne == null) {
|
||||
// we are moving on rail two
|
||||
Vector2D newDirection = touchingRails[1].getDirectionFrom(position);
|
||||
@ -251,6 +252,20 @@ public class RailwayNetwork {
|
||||
return rails.values().stream().filter(rail -> rail.canContain(position)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a rail that connects to or contains the first position and connects to or contains the second position.
|
||||
*
|
||||
* @param positionA point which the rail should touch or connect to
|
||||
* @param positionB point which the rail should touch or connect to
|
||||
* @return rail satisfying these conditions
|
||||
*/
|
||||
public Optional<Rail> findRail(Vector2D positionA, Vector2D positionB) {
|
||||
return rails.values().stream()
|
||||
.filter(rail -> rail.connectsTo(positionA) || rail.contains(positionA))
|
||||
.filter(rail -> rail.connectsTo(positionB) || rail.contains(positionB))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all rails that *touch* (not contain) this position.
|
||||
* @param position the position to check
|
||||
|
@ -2,7 +2,6 @@ package edu.kit.informatik.model;
|
||||
|
||||
import edu.kit.informatik.ui.InvalidInputException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -108,20 +107,6 @@ public final class Switch extends Rail {
|
||||
return selection.getDirectionFrom(position);
|
||||
}
|
||||
|
||||
private Vector2D[] getPossibleDirectionsFrom(Vector2D position) {
|
||||
if (positionOne.canConnectTo(position) && positionTwo.canConnectTo(position)) {
|
||||
return new Vector2D[] {
|
||||
positionOne.getDirectionFrom(position), positionOne.getDirectionFrom(position).negated(),
|
||||
positionTwo.getDirectionFrom(position), positionTwo.getDirectionFrom(position).negated()};
|
||||
} else if (positionOne.canConnectTo(position)) {
|
||||
return new Vector2D[] {positionOne.getDirectionFrom(position)};
|
||||
} else if (positionTwo.canConnectTo(position)) {
|
||||
return new Vector2D[] {positionTwo.getDirectionFrom(position)};
|
||||
} else {
|
||||
return new Vector2D[0];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowsDirectionFrom(Vector2D position, Vector2D direction) {
|
||||
return (selection != null && selection.contains(position))
|
||||
@ -129,6 +114,11 @@ public final class Switch extends Rail {
|
||||
|| (positionTwo.connectsTo(position) && positionTwo.allowsDirectionFrom(position, direction));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return selection.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (selection == null) {
|
||||
@ -136,8 +126,7 @@ public final class Switch extends Rail {
|
||||
positionOne.getEnd(), positionTwo.getEnd());
|
||||
} else {
|
||||
return String.format("s %d %s -> %s,%s %d", getIdentifier(),
|
||||
positionOne.getStart(), positionOne.getEnd(), positionTwo.getEnd(),
|
||||
selection.getLength());
|
||||
positionOne.getStart(), positionOne.getEnd(), positionTwo.getEnd(), getLength());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,9 @@ public final class Track extends Rail {
|
||||
|
||||
@Override
|
||||
public boolean contains(Vector2D position) {
|
||||
if (position == null) {
|
||||
return false;
|
||||
}
|
||||
if (start.getX() == end.getX() && position.getX() == start.getX()) {
|
||||
int startY = start.getY();
|
||||
int endY = end.getY();
|
||||
@ -130,6 +133,7 @@ public final class Track extends Rail {
|
||||
return new Vector2D(end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return start.distanceTo(end);
|
||||
}
|
||||
|
@ -9,17 +9,16 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A train consisting of one or more rolling stock. Can be placed on a rail network.
|
||||
*
|
||||
* @author Arne Keller
|
||||
* @version 1.0
|
||||
* @version 1.1
|
||||
*/
|
||||
public final class Train {
|
||||
/**
|
||||
* Numerical identifer of this train.
|
||||
* Numerical identifier of this train.
|
||||
*/
|
||||
private final int identifier;
|
||||
/**
|
||||
@ -27,10 +26,13 @@ public final class Train {
|
||||
*/
|
||||
private final List<RollingStock> rollingStocks = new ArrayList<>();
|
||||
/**
|
||||
* List of positions this train touches. This is a linked list because we only have to update the first and last
|
||||
* positions when moving the train.
|
||||
* List of positions this train occupies. More specifically, it only contains:
|
||||
* the position of the front of the train, any positions on rail connections, the position of the back of the train
|
||||
*
|
||||
* This is a linked list because we only have to update
|
||||
* the positions at the start and end of the list when moving the train.
|
||||
*/
|
||||
private LinkedList<Vector2D> position;
|
||||
private LinkedList<Vector2D> positions;
|
||||
/**
|
||||
* Set of rails this train occupies.
|
||||
*/
|
||||
@ -127,33 +129,29 @@ public final class Train {
|
||||
*/
|
||||
public boolean isOnRail(final Rail rail) {
|
||||
return isPlaced() && (occupiedRails.stream().anyMatch(blockedRail -> blockedRail == rail)
|
||||
|| position.stream().anyMatch(rail::canConnectTo));
|
||||
|| positions.stream().anyMatch(rail::canConnectTo));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a train on the rail network.
|
||||
*
|
||||
* @param railNetwork rail network to place the train on
|
||||
* @param position where to place the train
|
||||
* @param rawDirection direction in which the train should initially go
|
||||
* @return whether the train was successfully placed
|
||||
* @throws InvalidInputException when the train is too long to place
|
||||
*/
|
||||
public boolean placeOn(RailwayNetwork railNetwork, Vector2D position, Vector2D rawDirection)
|
||||
throws InvalidInputException {
|
||||
Vector2D direction = rawDirection.normalized();
|
||||
Vector2D positioningDirection = direction.negated();
|
||||
public boolean placeOn(RailwayNetwork railNetwork, Vector2D position, Vector2D rawDirection) {
|
||||
if (isPlaced()) {
|
||||
return false;
|
||||
}
|
||||
final Vector2D direction = rawDirection.normalized();
|
||||
final Vector2D positioningDirection = direction.negated();
|
||||
// size of train that still needs to be placed
|
||||
long length = getLength();
|
||||
if (length > Integer.MAX_VALUE) {
|
||||
// TODO: implement this case
|
||||
throw new InvalidInputException("train length is bigger than 32-bit integer!");
|
||||
}
|
||||
|
||||
LinkedList<Vector2D> positions = new LinkedList<>();
|
||||
positions.addLast(position);
|
||||
final LinkedList<Vector2D> positionList = new LinkedList<>();
|
||||
positionList.addLast(position);
|
||||
Vector2D rollingStockPosition = position;
|
||||
if (length > 10000) {
|
||||
return false; // TODO: remove!
|
||||
}
|
||||
// check that the requested direction is equal to the direction of one the tracks
|
||||
if ((railNetwork.findContainingRail(position) != null
|
||||
&& !railNetwork.findContainingRail(position).allowsDirectionFrom(position, positioningDirection))
|
||||
@ -162,37 +160,37 @@ public final class Train {
|
||||
.noneMatch(rail -> rail.allowsDirectionFrom(position, direction)))) {
|
||||
return false;
|
||||
}
|
||||
if (railNetwork.findTouchingRails(position).length > 0
|
||||
&& (Arrays.stream(railNetwork.findTouchingRails(position))
|
||||
.noneMatch(rail -> rail.connectsTo(position)))) {
|
||||
return false;
|
||||
}
|
||||
// consider fuzz 9 (0,-1)
|
||||
for (int i = 1; i <= length; i++) {
|
||||
rollingStockPosition = railNetwork.move(rollingStockPosition, positioningDirection);
|
||||
if (positions.getLast().distanceTo(rollingStockPosition) == 0) {
|
||||
final Set<Rail> occupiedRailsSet = new HashSet<>();
|
||||
while (length > 0) {
|
||||
rollingStockPosition = railNetwork.move(rollingStockPosition, positioningDirection, length);
|
||||
if (rollingStockPosition == null) {
|
||||
// derailed
|
||||
return false;
|
||||
}
|
||||
final long distanceToLastPosition = positionList.getLast().distanceTo(rollingStockPosition);
|
||||
if (distanceToLastPosition == 0) {
|
||||
// stuck
|
||||
return false;
|
||||
}
|
||||
if (rollingStockPosition == null
|
||||
|| positions.contains(rollingStockPosition) && !positions.get(0).equals(rollingStockPosition)) {
|
||||
return false;
|
||||
|
||||
// successfully placed part of the train
|
||||
length -= distanceToLastPosition;
|
||||
|
||||
final Rail occupiedRail = railNetwork.findRail(positionList.getLast(), rollingStockPosition).get();
|
||||
if (occupiedRailsSet.contains(occupiedRail) && positionList.size() >= 4) {
|
||||
// perhaps a self intersection
|
||||
final long occupiedAtFrontOfTrain = positionList.get(0).distanceTo(positionList.get(1));
|
||||
final long occupiedAtBackOfTrain = positionList.getLast().distanceTo(positionList.get(positionList.size() - 2));
|
||||
if (occupiedAtFrontOfTrain + occupiedAtBackOfTrain > occupiedRail.getLength()) {
|
||||
// train definitely intersects itself
|
||||
return false;
|
||||
}
|
||||
}
|
||||
positions.addLast(rollingStockPosition);
|
||||
occupiedRailsSet.add(occupiedRail);
|
||||
positionList.addLast(rollingStockPosition);
|
||||
}
|
||||
|
||||
Set<Rail> occupiedRailsSet = positions.stream().flatMap(point -> {
|
||||
Rail containingRail = railNetwork.findContainingRail(point);
|
||||
if (containingRail != null) {
|
||||
return Stream.of(containingRail);
|
||||
} else {
|
||||
return Arrays.stream(railNetwork.findTouchingRails(point))
|
||||
// ONLY add rails we fully occupy
|
||||
.filter(rail -> positions.stream().filter(rail::connectsTo).count() == 2);
|
||||
}
|
||||
}).collect(Collectors.toSet());
|
||||
|
||||
this.position = positions;
|
||||
this.positions = positionList;
|
||||
this.occupiedRails = occupiedRailsSet;
|
||||
|
||||
return true;
|
||||
@ -202,7 +200,7 @@ public final class Train {
|
||||
* @return whether this train is placed on a rail network
|
||||
*/
|
||||
public boolean isPlaced() {
|
||||
return position != null && occupiedRails != null;
|
||||
return positions != null && occupiedRails != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -222,7 +220,7 @@ public final class Train {
|
||||
*/
|
||||
public Vector2D getFrontPosition() {
|
||||
// make sure caller can not modify internal data
|
||||
return position != null ? new Vector2D(position.getFirst()) : null;
|
||||
return positions != null ? new Vector2D(positions.getFirst()) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -230,22 +228,21 @@ public final class Train {
|
||||
*/
|
||||
public Vector2D getRearPosition() {
|
||||
// make sure caller can not modify internal data
|
||||
return position != null ? new Vector2D(position.getLast()) : null;
|
||||
return positions != null ? new Vector2D(positions.getLast()) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the direction of this train
|
||||
*/
|
||||
public Vector2D getDirection() {
|
||||
// make sure caller can not modify internal state
|
||||
return position.get(0).subtract(position.get(1));
|
||||
return positions.get(0).subtract(positions.get(1)).normalized();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the rear direction of this train
|
||||
*/
|
||||
public Vector2D getRearDirection() {
|
||||
return position.getLast().subtract(position.get(position.size() - 2)); // TODO: consider longer trains
|
||||
return positions.getLast().subtract(positions.get(positions.size() - 2)).normalized();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -263,15 +260,25 @@ public final class Train {
|
||||
* @param nextPosition position to move train to
|
||||
*/
|
||||
public void moveTo(RailwayNetwork railNetwork, Vector2D nextPosition) {
|
||||
Vector2D last = position.removeLast();
|
||||
final Rail railUnderBackOfTrain = railNetwork.findContainingRail(positions.getLast());
|
||||
positions.getLast().subtractInPlace(getRearDirection());
|
||||
if (positions.getLast().equals(positions.get(positions.size() - 2))) {
|
||||
if (railNetwork.findContainingRail(nextPosition) != railUnderBackOfTrain
|
||||
|| nextPosition == null) {
|
||||
occupiedRails.remove(railUnderBackOfTrain);
|
||||
}
|
||||
positions.removeLast();
|
||||
}
|
||||
if (nextPosition != null) {
|
||||
// not derailing
|
||||
position.addFirst(new Vector2D(nextPosition));
|
||||
updateOccupiedRails(railNetwork, position.getFirst(), last, position.getLast());
|
||||
} else {
|
||||
// derailing
|
||||
updateOccupiedRails(railNetwork, null, last, position.getLast());
|
||||
}
|
||||
positions.addFirst(new Vector2D(nextPosition));
|
||||
if (positions.size() >= 3 && nextPosition.subtract(positions.get(1)).normalized()
|
||||
.equals(positions.get(1).subtract(positions.get(2)).normalized())
|
||||
&& railNetwork.findTouchingRails(positions.get(1)).length == 0) {
|
||||
positions.remove(1);
|
||||
}
|
||||
occupiedRails.add(railNetwork.findRail(positions.get(1), nextPosition).get());
|
||||
} // else: derailing
|
||||
}
|
||||
|
||||
/**
|
||||
@ -279,66 +286,35 @@ public final class Train {
|
||||
* derailing.
|
||||
*
|
||||
* @param railNetwork rail network to move train on
|
||||
* @param rearPosition position to move rear of the train to
|
||||
* @param backPosition position to move back of the train to
|
||||
*/
|
||||
public void moveBackTo(final RailwayNetwork railNetwork, final Vector2D rearPosition) {
|
||||
Vector2D last = position.removeFirst();
|
||||
if (rearPosition != null) {
|
||||
public void moveBackTo(RailwayNetwork railNetwork, Vector2D backPosition) {
|
||||
final Rail railUnderFrontOfTrain = railNetwork.findContainingRail(positions.getFirst());
|
||||
positions.getFirst().subtractInPlace(getDirection());
|
||||
if (positions.getFirst().equals(positions.get(1))) {
|
||||
if (railNetwork.findContainingRail(backPosition) != railUnderFrontOfTrain
|
||||
|| backPosition == null) {
|
||||
occupiedRails.remove(railUnderFrontOfTrain);
|
||||
}
|
||||
positions.removeFirst();
|
||||
}
|
||||
if (backPosition != null) {
|
||||
// not derailing
|
||||
position.addLast(new Vector2D(rearPosition));
|
||||
updateOccupiedRails(railNetwork, position.getLast(), last, position.getFirst());
|
||||
} else {
|
||||
// derailing
|
||||
updateOccupiedRails(railNetwork, null, last, position.getFirst());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update set of occupied rails after modifying position.
|
||||
*
|
||||
* @param railNetwork rail network to use
|
||||
* @param nextPosition where the train just moved (null if derailing)
|
||||
* @param lastPosition where the train just was
|
||||
* @param secondToLastPosition where the end of the train is now
|
||||
*/
|
||||
private void updateOccupiedRails(final RailwayNetwork railNetwork, final Vector2D nextPosition,
|
||||
final Vector2D lastPosition, final Vector2D secondToLastPosition) {
|
||||
if (secondToLastPosition.equals(nextPosition)) {
|
||||
// we are moving in a loop, no need to update
|
||||
return;
|
||||
}
|
||||
// update occupied blocks, first removing the rail block left behind
|
||||
Rail leavingRail = railNetwork.findContainingRail(lastPosition);
|
||||
if (leavingRail != null && !leavingRail.contains(secondToLastPosition)) {
|
||||
// we are leaving this rail
|
||||
occupiedRails.remove(leavingRail);
|
||||
} else if (getLength() == 1 && railNetwork.findContainingRail(secondToLastPosition) == null) {
|
||||
// we evidently just moved into another rail
|
||||
occupiedRails.clear();
|
||||
} // else: only touched rail
|
||||
// update occupied rails, adding next rail
|
||||
if (nextPosition == null) {
|
||||
// derailing
|
||||
return;
|
||||
}
|
||||
Rail nextRail = railNetwork.findContainingRail(nextPosition);
|
||||
if (nextRail != null) {
|
||||
occupiedRails.add(nextRail);
|
||||
} else if (getLength() == 1 && railNetwork.findContainingRail(secondToLastPosition) == null) {
|
||||
// we evidently just moved into another rail
|
||||
Rail[] nextTouchingRails = railNetwork.findTouchingRails(nextPosition);
|
||||
Rail[] alreadyTouchingRails = railNetwork.findTouchingRails(secondToLastPosition);
|
||||
Arrays.stream(nextTouchingRails)
|
||||
.filter(rail -> Arrays.stream(alreadyTouchingRails).anyMatch(rail2 -> rail == rail2))
|
||||
.forEach(occupiedRails::add);
|
||||
} // else: only touching new rail
|
||||
positions.addLast(new Vector2D(backPosition));
|
||||
if (positions.size() >= 3 && 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) {
|
||||
positions.remove(positions.size() - 2);
|
||||
}
|
||||
occupiedRails.add(railNetwork.findRail(positions.get(positions.size() - 2), backPosition).get());
|
||||
} // else: derailing
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this train from the rail network.
|
||||
*/
|
||||
public void removeFromRails() {
|
||||
position = null;
|
||||
positions = null;
|
||||
occupiedRails = null;
|
||||
}
|
||||
|
||||
@ -348,7 +324,7 @@ public final class Train {
|
||||
* @return whether this train touches the other train
|
||||
*/
|
||||
public boolean touches(final Train other) {
|
||||
return position != null && other.isOnAnyPosition(position);
|
||||
return positions != null && other.isOnAnyPosition(positions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -358,7 +334,7 @@ public final class Train {
|
||||
* @return whether this train is on the specified position
|
||||
*/
|
||||
public boolean isOnPosition(final Vector2D point) {
|
||||
return position.contains(point);
|
||||
return positions.contains(point);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -368,7 +344,7 @@ public final class Train {
|
||||
* @return whether this train is on any of the specified positions
|
||||
*/
|
||||
public boolean isOnAnyPosition(List<Vector2D> positions) {
|
||||
return position != null && position.stream().anyMatch(positions::contains);
|
||||
return this.positions != null && this.positions.stream().anyMatch(positions::contains);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,6 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
@ -273,9 +272,8 @@ public final class TrainManager {
|
||||
trains.values().stream().filter(Train::isPlaced).forEach(train -> {
|
||||
Vector2D position = train.getFrontPosition();
|
||||
Vector2D direction = train.getDirection();
|
||||
Vector2D nextPosition = railNetwork.move(position, direction);
|
||||
if (nextPosition == null || nextPosition.equals(position)
|
||||
|| train.isOnPosition(nextPosition) && !train.getRearPosition().equals(train.getFrontPosition())) {
|
||||
Vector2D nextPosition = railNetwork.move(position, direction, 1);
|
||||
if (nextPosition == null || nextPosition.equals(position)) {
|
||||
train.moveTo(railNetwork, null);
|
||||
collisions.add(new HashSet<>(Arrays.asList(train)));
|
||||
} else {
|
||||
@ -295,10 +293,9 @@ public final class TrainManager {
|
||||
List<Set<Train>> collisions = new ArrayList<>();
|
||||
// perform step
|
||||
trains.values().stream().filter(Train::isPlaced).forEach(train -> {
|
||||
Vector2D front = train.getFrontPosition();
|
||||
Vector2D position = train.getRearPosition();
|
||||
Vector2D direction = train.getRearDirection();
|
||||
Vector2D nextPosition = railNetwork.move(position, direction);
|
||||
Vector2D nextPosition = railNetwork.move(position, direction, 1);
|
||||
if (nextPosition == null
|
||||
|| train.isOnPosition(nextPosition) && !train.getRearPosition().equals(train.getFrontPosition())) {
|
||||
train.moveBackTo(railNetwork, nextPosition);
|
||||
|
@ -93,6 +93,17 @@ public class Vector2D {
|
||||
return new Vector2D(x - other.x, y - other.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract another vector from this one, modifying this vector.
|
||||
*
|
||||
* @param other another vector
|
||||
* @throws NullPointerException if other is null
|
||||
*/
|
||||
public void subtractInPlace(Vector2D other) {
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param movement vector to add
|
||||
* @return component-wise sum of this vector and the other vector
|
||||
|
Loading…
Reference in New Issue
Block a user