mirror of
https://gitlab.com/arnekeller/kit-programmieren-ws1920-final1.git
synced 2024-11-24 09:24:58 +00:00
Refactor rail network in own class
This commit is contained in:
parent
a84cb80288
commit
4ffb3a5665
@ -1,5 +1,7 @@
|
|||||||
package edu.kit.informatik;
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ui.CommandLine;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
CommandLine.startInteractive();
|
CommandLine.startInteractive();
|
||||||
|
@ -7,11 +7,11 @@ import java.util.*;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ModelRailwaySimulation {
|
public class ModelRailwaySimulation {
|
||||||
private List<Rail> rails = new ArrayList<>();
|
private final RailwayNetwork railNetwork = new RailwayNetwork();
|
||||||
private List<Engine> engines = new ArrayList<>();
|
private final List<Engine> engines = new ArrayList<>();
|
||||||
private List<TrainSet> trainSets = new ArrayList<>();
|
private final List<TrainSet> trainSets = new ArrayList<>();
|
||||||
private List<Coach> coaches = new ArrayList<>();
|
private final List<Coach> coaches = new ArrayList<>();
|
||||||
private List<Train> trains = new ArrayList<>();
|
private final List<Train> trains = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new track to the rail network of this simulation.
|
* Add a new track to the rail network of this simulation.
|
||||||
@ -20,32 +20,7 @@ public class ModelRailwaySimulation {
|
|||||||
* @return the positive identifier of the new track if successful, -1 otherwise
|
* @return the positive identifier of the new track if successful, -1 otherwise
|
||||||
*/
|
*/
|
||||||
public int addTrack(final Vector2D start, final Vector2D end) {
|
public int addTrack(final Vector2D start, final Vector2D end) {
|
||||||
if (start.distanceTo(end) == 0) {
|
return railNetwork.addTrack(start, end);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
long startPossibleConnections = rails.stream().filter((rail) -> rail.canConnectTo(start)).count();
|
|
||||||
long endPossibleConnections = rails.stream().filter((rail) -> rail.canConnectTo(end)).count();
|
|
||||||
if (startPossibleConnections == 2 || endPossibleConnections == 2) {
|
|
||||||
return -1; // TODO better error msg?
|
|
||||||
}
|
|
||||||
if (rails.isEmpty()) {
|
|
||||||
Track newTrack = new Track(start, end, 1);
|
|
||||||
rails.add(newTrack);
|
|
||||||
return newTrack.id;
|
|
||||||
} else {
|
|
||||||
for (Rail rail : rails) {
|
|
||||||
if (rail.canConnectTo(start) || rail.canConnectTo(end)) {
|
|
||||||
int id = getNextRailIdentifier();
|
|
||||||
if (id < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
Track newTrack = new Track(start, end, id);
|
|
||||||
rails.add(newTrack.id - 1, newTrack);
|
|
||||||
return newTrack.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,118 +31,28 @@ public class ModelRailwaySimulation {
|
|||||||
* @return the positive identifier of the switch if successful, -1 otherwise
|
* @return the positive identifier of the switch if successful, -1 otherwise
|
||||||
*/
|
*/
|
||||||
public int addSwitch(final Vector2D start, final Vector2D end1, final Vector2D end2) {
|
public int addSwitch(final Vector2D start, final Vector2D end1, final Vector2D end2) {
|
||||||
if (start.distanceTo(end1) == 0 || start.distanceTo(end2) == 0 || end1.distanceTo(end2) == 0) {
|
return railNetwork.addSwitch(start, end1, end2);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (rails.isEmpty()) {
|
|
||||||
Switch newSwitch = new Switch(start, end1, end2, 1);
|
|
||||||
rails.add(newSwitch);
|
|
||||||
return newSwitch.id;
|
|
||||||
} else {
|
|
||||||
long startPossibleConnections = rails.stream().filter((rail) -> rail.canConnectTo(start)).count();
|
|
||||||
long end1PossibleConnections = rails.stream().filter((rail) -> rail.canConnectTo(end1)).count();
|
|
||||||
long end2PossibleConnections = rails.stream().filter((rail) -> rail.canConnectTo(end2)).count();
|
|
||||||
if (startPossibleConnections == 2 || end1PossibleConnections == 2 || end2PossibleConnections == 2) {
|
|
||||||
return -1; // TODO better error msg?
|
|
||||||
}
|
|
||||||
for (Rail rail : rails) {
|
|
||||||
if (rail.canConnectTo(start) || rail.canConnectTo(end1) || rail.canConnectTo(end2)) {
|
|
||||||
int id = getNextRailIdentifier();
|
|
||||||
if (id < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
Switch newSwitch = new Switch(start, end1, end2, id);
|
|
||||||
rails.add(newSwitch.id - 1, newSwitch);
|
|
||||||
return newSwitch.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* positive if success, negative if fail
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private int getNextRailIdentifier() {
|
|
||||||
int id = 1;
|
|
||||||
for (Rail rail : rails) {
|
|
||||||
if (rail.id == id) {
|
|
||||||
id++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the specified rail from the rail network.
|
* Remove the specified rail from the rail network.
|
||||||
* @param id identifier of the rail to remove
|
* @param id identifier of the rail to remove
|
||||||
* @return true if rail could be successfully removed, false otherwise
|
* @return whether the rail could be successfully removed
|
||||||
*/
|
*/
|
||||||
public boolean removeRail(final int id) {
|
public boolean removeRail(final int id) {
|
||||||
if (rails.size() == 0) {
|
// check whether any trains are on this rail
|
||||||
return false;
|
if (trains.stream().anyMatch(train -> train.isOnRail(id))) {
|
||||||
} else if (rails.size() == 1) {
|
|
||||||
if (rails.get(0).id == id) {
|
|
||||||
rails.clear();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
return railNetwork.removeRail(id);
|
||||||
for (int i = 0; i < rails.size(); i++) {
|
|
||||||
Rail rail = rails.get(i);
|
|
||||||
if (rail.getIdentifier() == id) {
|
|
||||||
if (trains.stream().anyMatch((train) -> (train.isPlaced() && train.isPartiallyOn(rail)))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Set<Rail> connectedRails = new HashSet<>();
|
|
||||||
|
|
||||||
Rail otherRail = null;
|
|
||||||
for (int j = 0; j < rails.size(); j++) {
|
|
||||||
Rail anotherRail = rails.get(j);
|
|
||||||
if (anotherRail.getIdentifier() != id && rail.canConnectToRail(anotherRail)) {
|
|
||||||
otherRail = anotherRail;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedRails.add(otherRail);
|
|
||||||
Queue<Rail> toProcess = new LinkedList<>();
|
|
||||||
toProcess.add(otherRail);
|
|
||||||
|
|
||||||
while (!toProcess.isEmpty()) {
|
|
||||||
Rail connected = toProcess.poll();
|
|
||||||
|
|
||||||
for (Rail other : rails) {
|
|
||||||
if (other != rail && !connectedRails.contains(other) && other.canConnectToRail(connected)) {
|
|
||||||
connectedRails.add(other);
|
|
||||||
toProcess.offer(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connectedRails.size() == rails.size() - 1) {
|
|
||||||
rails.remove(i);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (rail.getIdentifier() > id) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a list of all rails in the network, specifying their identifier, start and end points, their length and
|
||||||
|
* their current configuration.
|
||||||
|
*/
|
||||||
public void printTracks() {
|
public void printTracks() {
|
||||||
if (rails.isEmpty()) {
|
railNetwork.printTracks();
|
||||||
Terminal.printLine("No track exists");
|
|
||||||
} else {
|
|
||||||
for (Rail rail : rails) {
|
|
||||||
Terminal.printLine(rail.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,14 +61,9 @@ public class ModelRailwaySimulation {
|
|||||||
* @param position position to set the switch to
|
* @param position position to set the switch to
|
||||||
* @return whether the switch could be set
|
* @return whether the switch could be set
|
||||||
*/
|
*/
|
||||||
public boolean setSwitch(int id, Vector2D position) {
|
public boolean setSwitch(final int id, final Vector2D position) {
|
||||||
// TODO Falls Gleiseweichen auf denen ein Zug bereitssteht, geschaltet werden, entgleist der daraufstehende Zug
|
// TODO Falls Gleiseweichen auf denen ein Zug bereitssteht, geschaltet werden, entgleist der daraufstehende Zug
|
||||||
for (Rail rail : rails) {
|
return railNetwork.setSwitch(id, position);
|
||||||
if (rail.getIdentifier() == id) {
|
|
||||||
return rail.switchTo(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -418,6 +298,10 @@ public class ModelRailwaySimulation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a train as ASCII art.
|
||||||
|
* @param id identifier of the train to show
|
||||||
|
*/
|
||||||
public void printTrain(int id) {
|
public void printTrain(int id) {
|
||||||
Train train = getTrain(id);
|
Train train = getTrain(id);
|
||||||
if (train != null) {
|
if (train != null) {
|
||||||
@ -431,86 +315,69 @@ public class ModelRailwaySimulation {
|
|||||||
* Put a train on the rail network.
|
* Put a train on the rail network.
|
||||||
* @param trainId identifier of the train to place
|
* @param trainId identifier of the train to place
|
||||||
* @param position where to place the train
|
* @param position where to place the train
|
||||||
* @param rawDirection direction in which the train should initially go
|
* @param direction direction in which the train should initially go
|
||||||
* @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 rawDirection) {
|
public boolean putTrain(final int trainId, final Vector2D position, final Vector2D direction) {
|
||||||
final Vector2D direction = rawDirection.normalized();
|
|
||||||
Train train = getTrain(trainId);
|
Train train = getTrain(trainId);
|
||||||
if (train == null) {
|
if (train == null || !train.isProperTrain()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!train.isProperTrain()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int length = train.getLength();
|
|
||||||
|
|
||||||
List<Vector2D> positions = new ArrayList<>();
|
boolean placed = train.placeOn(railNetwork, position, direction);
|
||||||
positions.add(position);
|
|
||||||
Vector2D positioningDirection = direction.negated();
|
|
||||||
Vector2D rollingStockPosition = position;
|
|
||||||
if (length > 10000) {
|
|
||||||
return false; // TODO: remove!
|
|
||||||
}
|
|
||||||
for (int i = 1; i <= length; i++) {
|
|
||||||
rollingStockPosition = move(rollingStockPosition, positioningDirection);
|
|
||||||
if (rollingStockPosition == null
|
|
||||||
|| (positions.contains(rollingStockPosition) && !positions.get(0).equals(rollingStockPosition))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
positions.add(rollingStockPosition);
|
|
||||||
}
|
|
||||||
train.storePositionAndDirection(positions, direction);
|
|
||||||
|
|
||||||
List<ArrayList<Train>> collisions = getStaticCollisions(false);
|
if (placed) {
|
||||||
|
List<HashSet<Train>> collisions = getStaticCollisions(false);
|
||||||
if (!collisions.isEmpty()) {
|
if (!collisions.isEmpty()) {
|
||||||
train.storePositionAndDirection(null, null);
|
train.storePositionDirectionBlocks(null, null, null);
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private ArrayList<ArrayList<Train>> getStaticCollisions(boolean removeTrains) {
|
private ArrayList<HashSet<Train>> getStaticCollisions(boolean removeTrains) {
|
||||||
ArrayList<ArrayList<Train>> collisions = new ArrayList<>();
|
if (trains.isEmpty()) {
|
||||||
for (Train train1 : trains) {
|
return new ArrayList<>();
|
||||||
if (!train1.isPlaced()) {
|
}
|
||||||
|
ArrayList<HashSet<Train>> collisions = new ArrayList<>();
|
||||||
|
int maxId = trains.get(trains.size() - 1).getIdentifier();
|
||||||
|
train: for (int id1 = 1; id1 <= maxId; id1++) {
|
||||||
|
Train train1 = getTrain(id1);
|
||||||
|
if (train1 == null || !train1.isPlaced()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ArrayList<Train> collision = new ArrayList<>();
|
HashSet<Train> collision = new HashSet<>();
|
||||||
for (Train train2 : trains) {
|
for (int id2 = id1 + 1; id2 <= maxId; id2++) {
|
||||||
if (!train2.isPlaced()) {
|
Train train2 = getTrain(id2);
|
||||||
|
if (train2 == null || !train2.isPlaced()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (train2.touches(train1)) {
|
|
||||||
|
if (train1.touches(train2)) {
|
||||||
collision.add(train2);
|
collision.add(train2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (collision.size() > 1) {
|
if (collision.size() >= 1) {
|
||||||
if (removeTrains) {
|
// check for existing collision
|
||||||
for (Train crashed : collision) {
|
for (HashSet<Train> otherCollision : collisions) {
|
||||||
crashed.removeFromRails();
|
if (otherCollision.stream().anyMatch(collision::contains)) {
|
||||||
|
otherCollision.addAll(collision);
|
||||||
|
continue train;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// else, create a new collision
|
||||||
|
collision.add(train1);
|
||||||
collisions.add(collision);
|
collisions.add(collision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Rail rail : rails) {
|
|
||||||
ArrayList<Train> containedTrains = new ArrayList<>();
|
|
||||||
for (Train train : trains) {
|
|
||||||
if (train.isPlaced() && train.isPartiallyOn(rail)) {
|
|
||||||
containedTrains.add(train);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (containedTrains.size() >= 2) {
|
|
||||||
containedTrains.sort(Comparator.comparingInt(Train::getIdentifier));
|
|
||||||
if (!collisions.contains(containedTrains)) {
|
|
||||||
if (removeTrains) {
|
if (removeTrains) {
|
||||||
for (Train crashed : containedTrains) {
|
for (HashSet<Train> collision : collisions) {
|
||||||
crashed.removeFromRails();
|
for (Train t : collision) {
|
||||||
}
|
t.removeFromRails();
|
||||||
}
|
|
||||||
collisions.add(containedTrains);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -522,8 +389,7 @@ public class ModelRailwaySimulation {
|
|||||||
Map<Train, Set<Rail>> occupiedRails = new HashMap<>();
|
Map<Train, Set<Rail>> occupiedRails = new HashMap<>();
|
||||||
for (Train train : trains) {
|
for (Train train : trains) {
|
||||||
if (train.isPlaced()) {
|
if (train.isPlaced()) {
|
||||||
Set<Rail> occupied = rails.stream().filter(train::isPartiallyOn).collect(Collectors.toSet());
|
occupiedRails.put(train, train.getOccupiedRails());
|
||||||
occupiedRails.put(train, occupied);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// perform step
|
// perform step
|
||||||
@ -534,7 +400,7 @@ public class ModelRailwaySimulation {
|
|||||||
}
|
}
|
||||||
Vector2D position = train.getFrontPosition();
|
Vector2D position = train.getFrontPosition();
|
||||||
Vector2D direction = train.getDirection();
|
Vector2D direction = train.getDirection();
|
||||||
Vector2D nextPosition = move(position, direction);
|
Vector2D nextPosition = railNetwork.move(position, direction);
|
||||||
if (nextPosition == null
|
if (nextPosition == null
|
||||||
|| (train.isOnPosition(nextPosition)
|
|| (train.isOnPosition(nextPosition)
|
||||||
&& !train.getBackPosition().equals(train.getFrontPosition()))) {
|
&& !train.getBackPosition().equals(train.getFrontPosition()))) {
|
||||||
@ -543,9 +409,9 @@ public class ModelRailwaySimulation {
|
|||||||
nextOccupiedRails.put(train, occupiedRails.get(train));
|
nextOccupiedRails.put(train, occupiedRails.get(train));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
train.moveTo(nextPosition);
|
train.moveTo(railNetwork, nextPosition);
|
||||||
train.setDirection(direction);
|
train.setDirection(direction);
|
||||||
nextOccupiedRails.put(train, rails.stream().filter(train::isPartiallyOn).collect(Collectors.toSet()));
|
nextOccupiedRails.put(train, train.getOccupiedRails());
|
||||||
}
|
}
|
||||||
// check for block collisions
|
// check for block collisions
|
||||||
for (Train train : trains) {
|
for (Train train : trains) {
|
||||||
@ -589,8 +455,7 @@ public class ModelRailwaySimulation {
|
|||||||
Map<Train, Set<Rail>> occupiedRails = new HashMap<>();
|
Map<Train, Set<Rail>> occupiedRails = new HashMap<>();
|
||||||
for (Train train : trains) {
|
for (Train train : trains) {
|
||||||
if (train.isPlaced()) {
|
if (train.isPlaced()) {
|
||||||
Set<Rail> occupied = rails.stream().filter(train::isPartiallyOn).collect(Collectors.toSet());
|
occupiedRails.put(train, train.getOccupiedRails());
|
||||||
occupiedRails.put(train, occupied);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// perform step
|
// perform step
|
||||||
@ -602,7 +467,7 @@ public class ModelRailwaySimulation {
|
|||||||
Vector2D front = train.getFrontPosition();
|
Vector2D front = train.getFrontPosition();
|
||||||
Vector2D position = train.getBackPosition();
|
Vector2D position = train.getBackPosition();
|
||||||
Vector2D direction = train.getBackDirection();
|
Vector2D direction = train.getBackDirection();
|
||||||
Vector2D nextPosition = move(position, direction);
|
Vector2D nextPosition = railNetwork.move(position, direction);
|
||||||
if (nextPosition == null
|
if (nextPosition == null
|
||||||
|| (train.isOnPosition(nextPosition) && !train.getFrontPosition().equals(nextPosition))) {
|
|| (train.isOnPosition(nextPosition) && !train.getFrontPosition().equals(nextPosition))) {
|
||||||
collisions.add(new HashSet<>(Arrays.asList(train)));
|
collisions.add(new HashSet<>(Arrays.asList(train)));
|
||||||
@ -610,9 +475,9 @@ public class ModelRailwaySimulation {
|
|||||||
nextOccupiedRails.put(train, occupiedRails.get(train));
|
nextOccupiedRails.put(train, occupiedRails.get(train));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
train.moveBackTo(nextPosition);
|
train.moveBackTo(railNetwork, nextPosition);
|
||||||
train.setDirection(front.subtract(train.getFrontPosition()));
|
train.setDirection(front.subtract(train.getFrontPosition()));
|
||||||
nextOccupiedRails.put(train, rails.stream().filter(train::isPartiallyOn).collect(Collectors.toSet()));
|
nextOccupiedRails.put(train, train.getOccupiedRails());
|
||||||
}
|
}
|
||||||
// check for block collisions
|
// check for block collisions
|
||||||
for (Train train : trains) {
|
for (Train train : trains) {
|
||||||
@ -648,68 +513,8 @@ public class ModelRailwaySimulation {
|
|||||||
return collisions;
|
return collisions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param position
|
|
||||||
* @param direction has to be (0,1) (0,-1) (1,0) (-1,0) will be modified if necessary
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Vector2D move(final Vector2D position, final Vector2D direction) {
|
|
||||||
Rail containingRail = findContainingRail(position);
|
|
||||||
if (containingRail != null) {
|
|
||||||
return position.add(direction);
|
|
||||||
}
|
|
||||||
Rail[] touchingRails = findTouchingRails(position);
|
|
||||||
if (touchingRails.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (touchingRails.length == 1) {
|
|
||||||
// at the end of a rail
|
|
||||||
// either derail or move backwards
|
|
||||||
Vector2D nextPosition = position.add(direction);
|
|
||||||
if (!touchingRails[0].contains(nextPosition)) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return nextPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vector2D nextPosition = position.add(direction);
|
|
||||||
if (touchingRails[0].contains(nextPosition) || touchingRails[0].connectsTo(nextPosition)) {
|
|
||||||
return nextPosition;
|
|
||||||
} else if (touchingRails[1].contains(nextPosition)) {
|
|
||||||
Vector2D nextDirection = touchingRails[1].getDirectionFrom(position);
|
|
||||||
direction.setX(nextDirection.getX());
|
|
||||||
direction.setY(nextDirection.getY());
|
|
||||||
return nextPosition;
|
|
||||||
}
|
|
||||||
Vector2D previousPosition = position.add(direction.negated());
|
|
||||||
Rail nextRail = (touchingRails[0].contains(previousPosition)
|
|
||||||
|| touchingRails[0].canConnectTo(previousPosition)) ? touchingRails[1] : touchingRails[0];
|
|
||||||
Vector2D nextDirection = nextRail.getDirectionFrom(position);
|
|
||||||
if (nextDirection != null) {
|
|
||||||
direction.setX(nextDirection.getX());
|
|
||||||
direction.setY(nextDirection.getY());
|
|
||||||
return position.add(direction);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Rail findContainingRail(final Vector2D position) {
|
|
||||||
for (Rail rail : rails) {
|
|
||||||
if (rail.contains(position)) {
|
|
||||||
return rail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Rail[] findTouchingRails(final Vector2D position) {
|
|
||||||
return rails.stream().filter((rail) -> rail.canConnectTo(position)).toArray(Rail[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void step(final short speed) {
|
public void step(final short speed) {
|
||||||
if (!rails.stream().allMatch(Rail::isReadyForTrains)) {
|
if (!railNetwork.isReadyForTrains()) {
|
||||||
Terminal.printError("rail tracks/switches not set up");
|
Terminal.printError("rail tracks/switches not set up");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
281
src/edu/kit/informatik/model/RailwayNetwork.java
Normal file
281
src/edu/kit/informatik/model/RailwayNetwork.java
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
package edu.kit.informatik.model;
|
||||||
|
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A rail network consisting of tracks and switches. Is only concerned with rails, does not process trains.
|
||||||
|
*
|
||||||
|
* @author Arne Keller
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
public class RailwayNetwork {
|
||||||
|
private List<Rail> rails = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new track to the rail network.
|
||||||
|
* @param start start position of the new track
|
||||||
|
* @param end end position of the new track
|
||||||
|
* @return the positive identifier of the new track if successful, -1 otherwise
|
||||||
|
*/
|
||||||
|
public int addTrack(final Vector2D start, final Vector2D end) {
|
||||||
|
if (start.distanceTo(end) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
long startPossibleConnections = rails.stream().filter((rail) -> rail.canConnectTo(start)).count();
|
||||||
|
long endPossibleConnections = rails.stream().filter((rail) -> rail.canConnectTo(end)).count();
|
||||||
|
if (startPossibleConnections == 2 || endPossibleConnections == 2) {
|
||||||
|
return -1; // TODO better error msg?
|
||||||
|
}
|
||||||
|
if (rails.isEmpty()) {
|
||||||
|
Track newTrack = new Track(start, end, 1);
|
||||||
|
rails.add(newTrack);
|
||||||
|
return newTrack.id;
|
||||||
|
} else {
|
||||||
|
for (Rail rail : rails) {
|
||||||
|
if (rail.canConnectTo(start) || rail.canConnectTo(end)) {
|
||||||
|
int id = getNextRailIdentifier();
|
||||||
|
if (id < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Track newTrack = new Track(start, end, id);
|
||||||
|
rails.add(newTrack.id - 1, newTrack);
|
||||||
|
return newTrack.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a switch to the rail network.
|
||||||
|
* @param start start point of the switch
|
||||||
|
* @param end1 end position 1 of the switch
|
||||||
|
* @param end2 end position 2 of the switch
|
||||||
|
* @return the positive identifier of the switch if successful, -1 otherwise
|
||||||
|
*/
|
||||||
|
public int addSwitch(final Vector2D start, final Vector2D end1, final Vector2D end2) {
|
||||||
|
if (start.distanceTo(end1) == 0 || start.distanceTo(end2) == 0 || end1.distanceTo(end2) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (rails.isEmpty()) {
|
||||||
|
Switch newSwitch = new Switch(start, end1, end2, 1);
|
||||||
|
rails.add(newSwitch);
|
||||||
|
return newSwitch.id;
|
||||||
|
} else {
|
||||||
|
long startPossibleConnections = rails.stream().filter((rail) -> rail.canConnectTo(start)).count();
|
||||||
|
long end1PossibleConnections = rails.stream().filter((rail) -> rail.canConnectTo(end1)).count();
|
||||||
|
long end2PossibleConnections = rails.stream().filter((rail) -> rail.canConnectTo(end2)).count();
|
||||||
|
if (startPossibleConnections == 2 || end1PossibleConnections == 2 || end2PossibleConnections == 2) {
|
||||||
|
return -1; // TODO better error msg?
|
||||||
|
}
|
||||||
|
for (Rail rail : rails) {
|
||||||
|
if (rail.canConnectTo(start) || rail.canConnectTo(end1) || rail.canConnectTo(end2)) {
|
||||||
|
int id = getNextRailIdentifier();
|
||||||
|
if (id < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Switch newSwitch = new Switch(start, end1, end2, id);
|
||||||
|
rails.add(newSwitch.id - 1, newSwitch);
|
||||||
|
return newSwitch.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified rail from the rail network.
|
||||||
|
* @param id identifier of the rail to remove
|
||||||
|
* @return whether the rail could be successfully removed
|
||||||
|
*/
|
||||||
|
public boolean removeRail(final int id) {
|
||||||
|
if (rails.size() == 0) {
|
||||||
|
return false;
|
||||||
|
} else if (rails.size() == 1) {
|
||||||
|
if (rails.get(0).id == id) {
|
||||||
|
rails.clear();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rail toRemove = getRail(id);
|
||||||
|
if (toRemove == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Set<Rail> connectedRails = new HashSet<>();
|
||||||
|
|
||||||
|
// locate one other rail: TODO use rail.connectedrails
|
||||||
|
Rail otherRail = null;
|
||||||
|
for (Rail anotherRail : rails) {
|
||||||
|
if (anotherRail.getIdentifier() != id && toRemove.canConnectToRail(anotherRail)) {
|
||||||
|
otherRail = anotherRail;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherRail == null) {
|
||||||
|
rails.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedRails.add(otherRail);
|
||||||
|
Queue<Rail> toProcess = new LinkedList<>();
|
||||||
|
toProcess.add(otherRail);
|
||||||
|
|
||||||
|
while (!toProcess.isEmpty()) {
|
||||||
|
Rail connected = toProcess.poll();
|
||||||
|
|
||||||
|
for (Rail other : rails) {
|
||||||
|
if (other != toRemove && !connectedRails.contains(other) && other.canConnectToRail(connected)) {
|
||||||
|
connectedRails.add(other);
|
||||||
|
toProcess.offer(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connectedRails.size() == rails.size() - 1) {
|
||||||
|
rails.remove(toRemove);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the setting of a switch in the rail network.
|
||||||
|
* @param id identifier of the switch
|
||||||
|
* @param position position to set the switch to
|
||||||
|
* @return whether the switch could be set
|
||||||
|
*/
|
||||||
|
public boolean setSwitch(final int id, final Vector2D position) {
|
||||||
|
Rail toSwitch = getRail(id);
|
||||||
|
if (toSwitch != null) {
|
||||||
|
return toSwitch.switchTo(position);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a list of all rails in the network, specifying their identifier, start and end points, their length and
|
||||||
|
* their current configuration.
|
||||||
|
*/
|
||||||
|
public void printTracks() {
|
||||||
|
if (rails.isEmpty()) {
|
||||||
|
Terminal.printLine("No track exists");
|
||||||
|
} else {
|
||||||
|
for (Rail rail : rails) {
|
||||||
|
Terminal.printLine(rail.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the next positive rail identifier, or -1 if none available
|
||||||
|
*/
|
||||||
|
private int getNextRailIdentifier() {
|
||||||
|
int id = 1;
|
||||||
|
for (Rail rail : rails) {
|
||||||
|
if (rail.id == id) {
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (id > 0) {
|
||||||
|
return id;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id identifier of the rail to find
|
||||||
|
* @return the specified rail, or null if not found
|
||||||
|
*/
|
||||||
|
private Rail getRail(final int id) {
|
||||||
|
for (Rail rail : rails) {
|
||||||
|
if (rail.getIdentifier() == id) {
|
||||||
|
return rail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
public Vector2D move(final Vector2D position, final Vector2D direction) {
|
||||||
|
Rail containingRail = findContainingRail(position);
|
||||||
|
if (containingRail != null) {
|
||||||
|
return position.add(direction);
|
||||||
|
}
|
||||||
|
Rail[] touchingRails = findTouchingRails(position);
|
||||||
|
if (touchingRails.length == 0) {
|
||||||
|
return null;
|
||||||
|
} else if (touchingRails.length == 1) {
|
||||||
|
// at the end of a rail
|
||||||
|
// either derail or move backwards
|
||||||
|
Vector2D nextPosition = position.add(direction);
|
||||||
|
if (!touchingRails[0].contains(nextPosition)) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return nextPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vector2D nextPosition = position.add(direction);
|
||||||
|
if (touchingRails[0].contains(nextPosition) || touchingRails[0].connectsTo(nextPosition)) {
|
||||||
|
return nextPosition;
|
||||||
|
} else if (touchingRails[1].contains(nextPosition)) {
|
||||||
|
Vector2D nextDirection = touchingRails[1].getDirectionFrom(position);
|
||||||
|
direction.setX(nextDirection.getX());
|
||||||
|
direction.setY(nextDirection.getY());
|
||||||
|
return nextPosition;
|
||||||
|
}
|
||||||
|
Vector2D previousPosition = position.add(direction.negated());
|
||||||
|
Rail nextRail = (touchingRails[0].contains(previousPosition)
|
||||||
|
|| touchingRails[0].canConnectTo(previousPosition)) ? touchingRails[1] : touchingRails[0];
|
||||||
|
Vector2D nextDirection = nextRail.getDirectionFrom(position);
|
||||||
|
if (nextDirection != null) {
|
||||||
|
direction.setX(nextDirection.getX());
|
||||||
|
direction.setY(nextDirection.getY());
|
||||||
|
return position.add(direction);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a rail that *contains* (not touch) this position.
|
||||||
|
* @param position the position to check
|
||||||
|
* @return the rail that contains the position, null if none found
|
||||||
|
*/
|
||||||
|
public Rail findContainingRail(final Vector2D position) {
|
||||||
|
for (Rail rail : rails) {
|
||||||
|
if (rail.contains(position)) {
|
||||||
|
return rail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all rails that *touch* (not contain) this position.
|
||||||
|
* @param position the position to check
|
||||||
|
* @return the rail(s) that touch this position
|
||||||
|
*/
|
||||||
|
public Rail[] findTouchingRails(final Vector2D position) {
|
||||||
|
return rails.stream().filter((rail) -> rail.canConnectTo(position)).toArray(Rail[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the rail network is ready for trains (all switches set, etc.).
|
||||||
|
* @return whether the rail network is ready
|
||||||
|
*/
|
||||||
|
public boolean isReadyForTrains() {
|
||||||
|
return rails.stream().allMatch(Rail::isReadyForTrains);
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,7 @@ package edu.kit.informatik.model;
|
|||||||
|
|
||||||
import edu.kit.informatik.Terminal;
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A train consisting of one or more rolling stock. Can be placed on a rail network.
|
* A train consisting of one or more rolling stock. Can be placed on a rail network.
|
||||||
@ -16,6 +15,7 @@ public final class Train {
|
|||||||
private final List<RollingStock> rollingStocks = new ArrayList<>();
|
private final List<RollingStock> rollingStocks = new ArrayList<>();
|
||||||
private List<Vector2D> position;
|
private List<Vector2D> position;
|
||||||
private Vector2D direction;
|
private Vector2D direction;
|
||||||
|
private Set<Rail> occupiedRails;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new train.
|
* Construct a new train.
|
||||||
@ -27,10 +27,17 @@ public final class Train {
|
|||||||
this.rollingStocks.add(rollingStock);
|
this.rollingStocks.add(rollingStock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the unique identifier of this train
|
||||||
|
*/
|
||||||
public int getIdentifier() {
|
public int getIdentifier() {
|
||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param rollingStock rolling stock to check
|
||||||
|
* @return whether the specified rolling stock is in this train
|
||||||
|
*/
|
||||||
public boolean contains(RollingStock rollingStock) {
|
public boolean contains(RollingStock rollingStock) {
|
||||||
return rollingStocks.contains(rollingStock);
|
return rollingStocks.contains(rollingStock);
|
||||||
}
|
}
|
||||||
@ -58,6 +65,9 @@ public final class Train {
|
|||||||
return stringBuilder.toString();
|
return stringBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print this train as ASCII art.
|
||||||
|
*/
|
||||||
public void print() {
|
public void print() {
|
||||||
List<StringBuilder> lines = new ArrayList<>();
|
List<StringBuilder> lines = new ArrayList<>();
|
||||||
for (RollingStock rollingStock : rollingStocks) {
|
for (RollingStock rollingStock : rollingStocks) {
|
||||||
@ -91,15 +101,88 @@ public final class Train {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isOnRail(final int id) {
|
||||||
|
return occupiedRails.stream().anyMatch(rail -> rail.getIdentifier() == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
public boolean placeOn(final RailwayNetwork railNetwork, final Vector2D position, final Vector2D rawDirection) {
|
||||||
|
Vector2D direction = rawDirection.normalized();
|
||||||
|
int length = getLength();
|
||||||
|
|
||||||
|
List<Vector2D> positions = new ArrayList<>();
|
||||||
|
positions.add(position);
|
||||||
|
Vector2D positioningDirection = direction.negated();
|
||||||
|
Vector2D rollingStockPosition = position;
|
||||||
|
if (length > 10000) {
|
||||||
|
return false; // TODO: remove!
|
||||||
|
}
|
||||||
|
for (int i = 1; i <= length; i++) {
|
||||||
|
rollingStockPosition = railNetwork.move(rollingStockPosition, positioningDirection);
|
||||||
|
if (rollingStockPosition == null
|
||||||
|
|| (positions.contains(rollingStockPosition) && !positions.get(0).equals(rollingStockPosition))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
positions.add(rollingStockPosition);
|
||||||
|
}
|
||||||
|
Set<Rail> occupiedRails = new HashSet<>();
|
||||||
|
for (int i = 0; i < positions.size(); i++) {
|
||||||
|
Vector2D point = positions.get(i);
|
||||||
|
Rail containingRail = railNetwork.findContainingRail(point);
|
||||||
|
if (containingRail != null) {
|
||||||
|
occupiedRails.add(containingRail);
|
||||||
|
} else if (i > 0) {
|
||||||
|
Rail[] touchingRails = railNetwork.findTouchingRails(point);
|
||||||
|
for (Rail rail : touchingRails) {
|
||||||
|
if (positions.stream().anyMatch(rail::connectsTo)) {
|
||||||
|
// ONLY add this rail if we actually occupy it fully
|
||||||
|
// note that this edge case only happens with rails of length one:
|
||||||
|
// otherwise at least one position will be contained in the rail (see above)
|
||||||
|
occupiedRails.add(rail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storePositionDirectionBlocks(positions, direction, occupiedRails);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return whether this train is placed on a rail network
|
||||||
|
*/
|
||||||
public boolean isPlaced() {
|
public boolean isPlaced() {
|
||||||
return position != null && direction != null;
|
return position != null && direction != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void storePositionAndDirection(final List<Vector2D> positions, final Vector2D direction) {
|
/**
|
||||||
|
*
|
||||||
|
* @param positions
|
||||||
|
* @param direction
|
||||||
|
* @param occupiedRails
|
||||||
|
*/
|
||||||
|
public void storePositionDirectionBlocks(final List<Vector2D> positions, final Vector2D direction,
|
||||||
|
final Set<Rail> occupiedRails) {
|
||||||
this.position = positions;
|
this.position = positions;
|
||||||
this.direction = direction;
|
this.direction = direction;
|
||||||
|
this.occupiedRails = occupiedRails;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean isProperTrain() {
|
public boolean isProperTrain() {
|
||||||
RollingStock first = rollingStocks.get(0);
|
RollingStock first = rollingStocks.get(0);
|
||||||
RollingStock last = rollingStocks.get(rollingStocks.size() - 1);
|
RollingStock last = rollingStocks.get(rollingStocks.size() - 1);
|
||||||
@ -109,11 +192,20 @@ public final class Train {
|
|||||||
|| (last instanceof Engine || last instanceof TrainSet);
|
|| (last instanceof Engine || last instanceof TrainSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param rail
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean isPartiallyOn(Rail rail) {
|
public boolean isPartiallyOn(Rail rail) {
|
||||||
return position.stream().anyMatch(rail::contains)
|
return position.stream().anyMatch(rail::contains)
|
||||||
|| position.stream().filter(rail::connectsTo).count() == 2;
|
|| position.stream().filter(rail::connectsTo).count() == 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Vector2D getFrontPosition() {
|
public Vector2D getFrontPosition() {
|
||||||
if (position != null) {
|
if (position != null) {
|
||||||
return position.get(0);
|
return position.get(0);
|
||||||
@ -122,6 +214,10 @@ public final class Train {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Vector2D getBackPosition() {
|
public Vector2D getBackPosition() {
|
||||||
if (position != null) {
|
if (position != null) {
|
||||||
return position.get(position.size() - 1);
|
return position.get(position.size() - 1);
|
||||||
@ -130,10 +226,18 @@ public final class Train {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Vector2D getDirection() {
|
public Vector2D getDirection() {
|
||||||
return direction;
|
return direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Vector2D getBackDirection() {
|
public Vector2D getBackDirection() {
|
||||||
if (position.size() == 1) {
|
if (position.size() == 1) {
|
||||||
return direction.negated();
|
return direction.negated();
|
||||||
@ -142,37 +246,125 @@ public final class Train {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveTo(Vector2D nextPosition) {
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Set<Rail> getOccupiedRails() {
|
||||||
|
// make sure caller can not modify internal state
|
||||||
|
return new HashSet<>(occupiedRails);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param railNetwork
|
||||||
|
* @param nextPosition
|
||||||
|
*/
|
||||||
|
public void moveTo(final RailwayNetwork railNetwork, final Vector2D nextPosition) {
|
||||||
position.add(0, nextPosition);
|
position.add(0, nextPosition);
|
||||||
position.remove(position.size() - 1);
|
Vector2D last = position.remove(position.size() - 1);
|
||||||
|
updateOccupiedRails(railNetwork, position.get(0), last, position.get(position.size() - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveBackTo(Vector2D backPosition) {
|
/**
|
||||||
position.remove(0);
|
*
|
||||||
|
* @param backPosition
|
||||||
|
*/
|
||||||
|
public void moveBackTo(final RailwayNetwork railNetwork, final Vector2D backPosition) {
|
||||||
|
Vector2D last = position.remove(0);
|
||||||
position.add(backPosition);
|
position.add(backPosition);
|
||||||
|
updateOccupiedRails(railNetwork, backPosition, last, position.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateOccupiedRails(final RailwayNetwork railNetwork, final Vector2D nextPosition,
|
||||||
|
final Vector2D lastPosition, final Vector2D secondToLastPosition) {
|
||||||
|
if (nextPosition.equals(secondToLastPosition)) {
|
||||||
|
// 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) {
|
||||||
|
// check whether we really leave rail
|
||||||
|
if (!leavingRail.contains(secondToLastPosition)) {
|
||||||
|
// we are really leaving this rail
|
||||||
|
occupiedRails.remove(leavingRail);
|
||||||
|
} // else: we are still on the rail
|
||||||
|
} else if (getLength() == 1) {
|
||||||
|
// we evidently just moved into another rail
|
||||||
|
occupiedRails.clear();
|
||||||
|
} // else: only touched rail
|
||||||
|
// update occupied rails, adding next rail
|
||||||
|
Rail nextRail = railNetwork.findContainingRail(nextPosition);
|
||||||
|
if (nextRail != null) {
|
||||||
|
occupiedRails.add(nextRail);
|
||||||
|
} else if (getLength() == 1) {
|
||||||
|
// we evidently just moved into another rail
|
||||||
|
Rail[] nextTouchingRails = railNetwork.findTouchingRails(nextPosition);
|
||||||
|
Rail[] alreadyTouchingRails = railNetwork.findTouchingRails(position.get(position.size() - 1));
|
||||||
|
if (nextTouchingRails[0] == alreadyTouchingRails[0]) {
|
||||||
|
occupiedRails.add(nextTouchingRails[0]);
|
||||||
|
} else if (nextTouchingRails.length == 2) {
|
||||||
|
if (nextTouchingRails[1] == alreadyTouchingRails[0]) {
|
||||||
|
occupiedRails.add(nextTouchingRails[1]);
|
||||||
|
} else if (alreadyTouchingRails.length == 2) {
|
||||||
|
if (alreadyTouchingRails[1] == nextTouchingRails[0]) {
|
||||||
|
occupiedRails.add(nextTouchingRails[0]);
|
||||||
|
} else if (alreadyTouchingRails[1] == nextTouchingRails[1]) {
|
||||||
|
occupiedRails.add(nextTouchingRails[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // else: only touching rail
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param newDirection
|
||||||
|
*/
|
||||||
public void setDirection(Vector2D newDirection) {
|
public void setDirection(Vector2D newDirection) {
|
||||||
direction = newDirection;
|
direction = newDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
public void removeFromRails() {
|
public void removeFromRails() {
|
||||||
position = null;
|
position = null;
|
||||||
direction = null;
|
direction = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param other
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean touches(Train other) {
|
public boolean touches(Train other) {
|
||||||
return other.isOnAnyPosition(position);
|
return other.isOnAnyPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param point
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean isOnPosition(Vector2D point) {
|
public boolean isOnPosition(Vector2D point) {
|
||||||
return position.contains(point);
|
return position.contains(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param positions
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean isOnAnyPosition(List<Vector2D> positions) {
|
public boolean isOnAnyPosition(List<Vector2D> positions) {
|
||||||
return position.stream().anyMatch(positions::contains);
|
return position.stream().anyMatch(positions::contains);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public int getLength() {
|
public int getLength() {
|
||||||
return rollingStocks.stream().mapToInt((RollingStock::getLength)).sum();
|
return rollingStocks.stream().mapToInt((RollingStock::getLength)).sum();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user