mirror of
https://gitlab.com/arnekeller/kit-programmieren-ws1920-final1.git
synced 2024-11-24 09:24:58 +00:00
Initial commit
This commit is contained in:
commit
aa547d3568
91
src/edu/kit/informatik/Coach.java
Normal file
91
src/edu/kit/informatik/Coach.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
public class Coach extends RollingStock {
|
||||||
|
private CoachType type;
|
||||||
|
private int identifier;
|
||||||
|
|
||||||
|
public Coach(final int identifier, final CoachType type, final int length, final boolean couplingFront, final boolean couplingBack) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.type = type;
|
||||||
|
super.length = length;
|
||||||
|
super.couplingFront = couplingFront;
|
||||||
|
super.couplingBack = couplingBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentifier() {
|
||||||
|
return String.format("W%d", identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canCoupleFrontTo(RollingStock rollingStock) {
|
||||||
|
// train-sets can ONLY connect to other matching train-sets, not to coaches.
|
||||||
|
return hasCouplingFront() && rollingStock.hasCouplingBack() && !(rollingStock instanceof TrainSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canCoupleToTrainSetSeries(String series) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumericalIdentifier() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoachType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String[] PASSENGER_TEXT = new String[] {
|
||||||
|
"____________________",
|
||||||
|
"| ___ ___ ___ ___ |",
|
||||||
|
"| |_| |_| |_| |_| |",
|
||||||
|
"|__________________|",
|
||||||
|
"|__________________|",
|
||||||
|
" (O) (O) "
|
||||||
|
};
|
||||||
|
private static final String[] FREIGHT_TEXT = new String[] {
|
||||||
|
"| |",
|
||||||
|
"| |",
|
||||||
|
"| |",
|
||||||
|
"|__________________|",
|
||||||
|
" (O) (O) "
|
||||||
|
};
|
||||||
|
private static final String[] SPECIAL_TEXT = new String[] {
|
||||||
|
" ____",
|
||||||
|
"/--------------| |",
|
||||||
|
"\\--------------| |",
|
||||||
|
" | | | |",
|
||||||
|
" _|_|__________| |",
|
||||||
|
"|_________________|",
|
||||||
|
" (O) (O) "
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] textRepresentation() {
|
||||||
|
switch (type) {
|
||||||
|
case PASSENGER:
|
||||||
|
return PASSENGER_TEXT;
|
||||||
|
case FREIGHT:
|
||||||
|
return FREIGHT_TEXT;
|
||||||
|
case SPECIAL:
|
||||||
|
return SPECIAL_TEXT;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String description() {
|
||||||
|
switch (type) {
|
||||||
|
case PASSENGER:
|
||||||
|
return "passenger coach";
|
||||||
|
case FREIGHT:
|
||||||
|
return "freight coach";
|
||||||
|
case SPECIAL:
|
||||||
|
return "special coach";
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
src/edu/kit/informatik/CoachType.java
Normal file
21
src/edu/kit/informatik/CoachType.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
public enum CoachType {
|
||||||
|
PASSENGER,
|
||||||
|
FREIGHT,
|
||||||
|
SPECIAL;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
switch (this) {
|
||||||
|
case PASSENGER:
|
||||||
|
return "p";
|
||||||
|
case FREIGHT:
|
||||||
|
return "f";
|
||||||
|
case SPECIAL:
|
||||||
|
return "s";
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
src/edu/kit/informatik/CommandLine.java
Normal file
44
src/edu/kit/informatik/CommandLine.java
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
import edu.kit.informatik.command.Command;
|
||||||
|
import edu.kit.informatik.command.CommandFactory;
|
||||||
|
|
||||||
|
public class CommandLine {
|
||||||
|
public static final String EXIT = "exit";
|
||||||
|
|
||||||
|
public static void startInteractive() {
|
||||||
|
ModelRailwaySimulation simulation = new ModelRailwaySimulation();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
final String input = Terminal.readLine();
|
||||||
|
if (input == null) {
|
||||||
|
break; // TODO remove
|
||||||
|
}
|
||||||
|
if (input.startsWith("#")) {
|
||||||
|
continue; // TODO remove
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.equals(EXIT)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Command command;
|
||||||
|
try {
|
||||||
|
//Terminal.printLine("> " + input);
|
||||||
|
command = CommandFactory.getCommand(input);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Terminal.printError("number too big");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (command != null) {
|
||||||
|
try {
|
||||||
|
command.apply(simulation);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Terminal.printError("number too big");
|
||||||
|
// this can happen when trying to add W2147483649 to a train or similar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else: error message already printed in parse function
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
src/edu/kit/informatik/DieselEngine.java
Normal file
35
src/edu/kit/informatik/DieselEngine.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
public class DieselEngine extends Engine {
|
||||||
|
public DieselEngine(final String series, final String name, final int length, final boolean couplingFront, final boolean couplingBack) {
|
||||||
|
super.name = name;
|
||||||
|
super.series = series;
|
||||||
|
super.length = length;
|
||||||
|
super.couplingFront = couplingFront;
|
||||||
|
super.couplingBack = couplingBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("d %s %s %d %b %b", series, name, length, couplingFront, couplingBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String[] DIESEL_ENGINE_TEXT = new String[] {
|
||||||
|
" _____________|____ ",
|
||||||
|
" /_| ____________ |_\\ ",
|
||||||
|
"/ |____________| \\",
|
||||||
|
"\\ /",
|
||||||
|
" \\__________________/ ",
|
||||||
|
" (O)(O) (O)(O) ",
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] textRepresentation() {
|
||||||
|
return DIESEL_ENGINE_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String description() {
|
||||||
|
return "diesel engine";
|
||||||
|
}
|
||||||
|
}
|
37
src/edu/kit/informatik/ElectricalEngine.java
Normal file
37
src/edu/kit/informatik/ElectricalEngine.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
public class ElectricalEngine extends Engine {
|
||||||
|
public ElectricalEngine(final String series, final String name, final int length, final boolean couplingFront, final boolean couplingBack) {
|
||||||
|
super.name = name;
|
||||||
|
super.series = series;
|
||||||
|
super.length = length;
|
||||||
|
super.couplingFront = couplingFront;
|
||||||
|
super.couplingBack = couplingBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("e %s %s %d %b %b", series, name, length, couplingFront, couplingBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String[] ELECTRICAL_ENGINE_TEXT = new String[] {
|
||||||
|
" ___ ",
|
||||||
|
" \\ ",
|
||||||
|
" _______________/__ ",
|
||||||
|
" /_| ____________ |_\\ ",
|
||||||
|
"/ |____________| \\",
|
||||||
|
"\\ /",
|
||||||
|
" \\__________________/ ",
|
||||||
|
" (O)(O) (O)(O) ",
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] textRepresentation() {
|
||||||
|
return ELECTRICAL_ENGINE_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String description() {
|
||||||
|
return "electrical engine";
|
||||||
|
}
|
||||||
|
}
|
26
src/edu/kit/informatik/Engine.java
Normal file
26
src/edu/kit/informatik/Engine.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
public abstract class Engine extends RollingStock {
|
||||||
|
protected String series;
|
||||||
|
protected String name;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentifier() {
|
||||||
|
return String.format("%s-%s", series, getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canCoupleFrontTo(RollingStock rollingStock) {
|
||||||
|
// train-sets can ONLY connect to other matching train-sets, not to engines.
|
||||||
|
return hasCouplingFront() && rollingStock.hasCouplingBack() && !(rollingStock instanceof TrainSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canCoupleToTrainSetSeries(String series) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
7
src/edu/kit/informatik/Main.java
Normal file
7
src/edu/kit/informatik/Main.java
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
CommandLine.startInteractive();
|
||||||
|
}
|
||||||
|
}
|
80
src/edu/kit/informatik/MainTest.java
Normal file
80
src/edu/kit/informatik/MainTest.java
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class MainTest {
|
||||||
|
@Test
|
||||||
|
void basics() throws IOException {
|
||||||
|
cmpInOut("basics_input.txt", "basics_output.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void exampleInteraction() throws IOException {
|
||||||
|
cmpInOut("example1input.txt", "example1ONLYoutput.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void limits() throws IOException {
|
||||||
|
cmpInOut("example2input.txt", "example2output.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void loopy() throws IOException {
|
||||||
|
cmpInOut("loopyinput.txt", "loopyoutput.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hitMeBabyOneMoreTime() throws IOException {
|
||||||
|
cmpInOut("stophittingyourself_input.txt", "stophittingyourself_output.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fuzz1() throws IOException {
|
||||||
|
cmpInOut("fuzz1_input.txt", "fuzz1_output.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fuzz2() throws IOException {
|
||||||
|
cmpInOut("fuzz2_input.txt", "fuzz2_output.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fuzz3() throws IOException {
|
||||||
|
cmpInOut("fuzz3_input.txt", "fuzz3_output.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fuzz4() throws IOException {
|
||||||
|
cmpInOut("fuzz4_input.txt", "fuzz4_output.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fuzz5() throws IOException {
|
||||||
|
cmpInOut("fuzz5_input.txt", "fuzz5_output.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fuzz6() throws IOException {
|
||||||
|
cmpInOut("fuzz6_input.txt", "fuzz6_output.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cmpInOut(String in, String out) throws IOException {
|
||||||
|
System.setIn(new ByteArrayInputStream(readFile(in)));
|
||||||
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
|
System.setOut(new PrintStream(output));
|
||||||
|
Terminal.reload();
|
||||||
|
Main.main(null);
|
||||||
|
String expected = new String(readFile(out));
|
||||||
|
assertEquals(expected, output.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] readFile(String name) throws IOException {
|
||||||
|
File file = new File(name);
|
||||||
|
return Files.readAllBytes(file.toPath());
|
||||||
|
}
|
||||||
|
}
|
775
src/edu/kit/informatik/ModelRailwaySimulation.java
Normal file
775
src/edu/kit/informatik/ModelRailwaySimulation.java
Normal file
@ -0,0 +1,775 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ModelRailwaySimulation {
|
||||||
|
private List<Rail> rails = new ArrayList<>();
|
||||||
|
private List<Engine> engines = new ArrayList<>();
|
||||||
|
private List<TrainSet> trainSets = new ArrayList<>();
|
||||||
|
private List<Coach> coaches = new ArrayList<>();
|
||||||
|
private List<Train> trains = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifier if success, -1 if fail
|
||||||
|
* @param start
|
||||||
|
* @param end
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int addTrack(final Point start, final Point 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* -1 if fail
|
||||||
|
* @param start
|
||||||
|
* @param end1
|
||||||
|
* @param end2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int addSwitch(final Point start, final Point end1, final Point 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* positive if success, negative if fail
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private int getNextRailIdentifier() {
|
||||||
|
int id = 1;
|
||||||
|
for (Rail rail : rails) {
|
||||||
|
if (rail.id == id) {
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true success, false fail
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printTracks() {
|
||||||
|
if (rails.isEmpty()) {
|
||||||
|
Terminal.printLine("No track exists");
|
||||||
|
} else {
|
||||||
|
for (Rail rail : rails) {
|
||||||
|
Terminal.printLine(rail.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true success, false fail
|
||||||
|
* @param id
|
||||||
|
* @param position
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean setSwitch(int id, Point position) {
|
||||||
|
// TODO Falls Gleiseweichen auf denen ein Zug bereitssteht, geschaltet werden, entgleist der daraufstehende Zug
|
||||||
|
for (Rail rail : rails) {
|
||||||
|
if (rail.getIdentifier() == id) {
|
||||||
|
return rail.switchTo(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true success, false fail
|
||||||
|
* @param newEngine
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean createEngine(final Engine newEngine) {
|
||||||
|
String id = newEngine.getIdentifier();
|
||||||
|
for (Engine engine : engines) {
|
||||||
|
if (engine.getIdentifier().equals(id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (TrainSet trainSet : trainSets) {
|
||||||
|
if (trainSet.getIdentifier().equals(id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
engines.add(newEngine);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printEngines() {
|
||||||
|
if (engines.isEmpty()) {
|
||||||
|
Terminal.printLine("No engine exists");
|
||||||
|
} else {
|
||||||
|
engines.sort(Comparator.comparing(Engine::getIdentifier));
|
||||||
|
engine: for (Engine engine : engines) {
|
||||||
|
for (Train train : trains) {
|
||||||
|
int id = train.getIdentifier();
|
||||||
|
if (train.contains(engine)) {
|
||||||
|
Terminal.printLine(String.format("%s %s", id, engine));
|
||||||
|
continue engine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Terminal.printLine(String.format("none %s", engine));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* positive success, -1 fail
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int createCoach(final CoachType coachType, final int length,
|
||||||
|
final boolean couplingFront, final boolean couplingBack) {
|
||||||
|
int id = getNextCoachIdentifier();
|
||||||
|
if (id < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Coach coach = new Coach(id, coachType, length, couplingFront, couplingBack);
|
||||||
|
coaches.add(id - 1, coach);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getNextCoachIdentifier() {
|
||||||
|
int id = 1;
|
||||||
|
for (Coach coach : coaches) {
|
||||||
|
if (coach.getNumericalIdentifier() == id) {
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printCoaches() {
|
||||||
|
if (coaches.isEmpty()) {
|
||||||
|
Terminal.printLine("No coach exists");
|
||||||
|
} else {
|
||||||
|
coach: for (Coach coach : coaches) {
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (train.contains(coach)) {
|
||||||
|
Terminal.printLine(String.format("%d %s %s %d %b %b",
|
||||||
|
coach.getNumericalIdentifier(), train.getIdentifier(), coach.getType(),
|
||||||
|
coach.getLength(), coach.hasCouplingFront(), coach.hasCouplingBack()));
|
||||||
|
continue coach;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Terminal.printLine(String.format("%d none %s %d %b %b", coach.getNumericalIdentifier(), coach.getType(),
|
||||||
|
coach.getLength(), coach.hasCouplingFront(), coach.hasCouplingBack()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true success, false fail
|
||||||
|
* @param newTrainSet
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean createTrainSet(final TrainSet newTrainSet) {
|
||||||
|
String id = newTrainSet.getIdentifier();
|
||||||
|
for (Engine engine : engines) {
|
||||||
|
if (engine.getIdentifier().equals(id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (TrainSet trainSet : trainSets) {
|
||||||
|
if (trainSet.getIdentifier().equals(id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trainSets.add(newTrainSet);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printTrainSets() {
|
||||||
|
if (trainSets.isEmpty()) {
|
||||||
|
Terminal.printLine("No train-set exists");
|
||||||
|
} else {
|
||||||
|
trainSets.sort(Comparator.comparing(TrainSet::getIdentifier));
|
||||||
|
trainset: for (TrainSet trainSet : trainSets) {
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (train.contains(trainSet)) {
|
||||||
|
Terminal.printLine(String.format("%s %s", train.getIdentifier(), trainSet));
|
||||||
|
continue trainset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Terminal.printLine(String.format("none %s", trainSet));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true success, false fail
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean deleteRollingStock(String id) {
|
||||||
|
RollingStock rollingStock = getRollingStock(id);
|
||||||
|
if (rollingStock == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (train.contains(rollingStock)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
engines.remove(rollingStock);
|
||||||
|
trainSets.remove(rollingStock);
|
||||||
|
coaches.remove(rollingStock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RollingStock getRollingStock(String id) {
|
||||||
|
if (id.matches("W\\+?\\d+")) {
|
||||||
|
int coachId = Integer.parseInt(id.substring(1));
|
||||||
|
for (Coach coach : coaches) {
|
||||||
|
if (coach.getNumericalIdentifier() == coachId) {
|
||||||
|
return coach;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (Engine engine : engines) {
|
||||||
|
if (engine.getIdentifier().equals(id)) {
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (TrainSet trainSet : trainSets) {
|
||||||
|
if (trainSet.getIdentifier().equals(id)) {
|
||||||
|
return trainSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addTrain(int trainId, String rollingStockId) {
|
||||||
|
RollingStock rollingStock = getRollingStock(rollingStockId);
|
||||||
|
if (rollingStock == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (train.contains(rollingStock)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Train train = getTrain(trainId);
|
||||||
|
if (train != null && train.isPlaced()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (train != null) {
|
||||||
|
return train.add(rollingStock);
|
||||||
|
}
|
||||||
|
int correctId = getNextTrainIdentifier();
|
||||||
|
if (trainId != correctId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Train newTrain = new Train(trainId, rollingStock);
|
||||||
|
trains.add(newTrain);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getNextTrainIdentifier() {
|
||||||
|
int id = 1;
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (train.getIdentifier() == id) {
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteTrain(int id) {
|
||||||
|
Train train = getTrain(id);
|
||||||
|
if (train != null) {
|
||||||
|
trains.remove(train);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Train getTrain(int id) {
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (train.getIdentifier() == id) {
|
||||||
|
return train;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printTrains() {
|
||||||
|
if (trains.isEmpty()) {
|
||||||
|
Terminal.printLine("No train exists"); // TODO not in fucking spec
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Train train : trains) {
|
||||||
|
Terminal.printLine(train);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printTrain(int id) {
|
||||||
|
Train train = getTrain(id);
|
||||||
|
if (train != null) {
|
||||||
|
train.print();
|
||||||
|
} else {
|
||||||
|
Terminal.printError("no such train");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true success, false fail
|
||||||
|
* @param trainId
|
||||||
|
* @param position
|
||||||
|
* @param rawDirection
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean putTrain(final int trainId, final Point position, final Point rawDirection) {
|
||||||
|
final Point direction = rawDirection.normalized();
|
||||||
|
Train train = getTrain(trainId);
|
||||||
|
if (train == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!train.isProperTrain()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int length = train.getLength();
|
||||||
|
|
||||||
|
List<Point> positions = new ArrayList<>();
|
||||||
|
positions.add(position);
|
||||||
|
Point positioningDirection = direction.negated();
|
||||||
|
Point 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);
|
||||||
|
}
|
||||||
|
/* TODO: await forum answer
|
||||||
|
if (!positions.get(0).subtract(positions.get(1)).equals(direction)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
train.storePositionAndDirection(positions, direction);
|
||||||
|
|
||||||
|
List<ArrayList<Train>> collisions = getStaticCollisions(false);
|
||||||
|
if (!collisions.isEmpty()) {
|
||||||
|
train.storePositionAndDirection(null, null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<ArrayList<Train>> getStaticCollisions(boolean removeTrains) {
|
||||||
|
ArrayList<ArrayList<Train>> collisions = new ArrayList<>();
|
||||||
|
for (Train train1 : trains) {
|
||||||
|
if (!train1.isPlaced()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ArrayList<Train> collision = new ArrayList<>();
|
||||||
|
for (Train train2 : trains) {
|
||||||
|
if (!train2.isPlaced()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (train2.touches(train1)) {
|
||||||
|
collision.add(train2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (collision.size() > 1) {
|
||||||
|
if (removeTrains) {
|
||||||
|
for (Train crashed : collision) {
|
||||||
|
crashed.removeFromRails();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
for (Train crashed : containedTrains) {
|
||||||
|
crashed.removeFromRails();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collisions.add(containedTrains);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collisions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<Set<Train>> getCollisionsOfOneStep() {
|
||||||
|
ArrayList<Set<Train>> collisions = new ArrayList<>();
|
||||||
|
// check touching trains
|
||||||
|
/*
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (!train.isPlaced()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Train otherTrain : trains) {
|
||||||
|
if (!otherTrain.isPlaced() || train == otherTrain) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (train.getFrontPosition().equals(otherTrain.getFrontPosition())) {
|
||||||
|
train.removeFromRails();
|
||||||
|
otherTrain.removeFromRails();
|
||||||
|
collisions.add(Arrays.asList(train, otherTrain));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Map<Train, Set<Rail>> occupiedRails = new HashMap<>();
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (train.isPlaced()) {
|
||||||
|
Set<Rail> occupied = rails.stream().filter(train::isPartiallyOn).collect(Collectors.toSet());
|
||||||
|
occupiedRails.put(train, occupied);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// perform step
|
||||||
|
Map<Train, Set<Rail>> nextOccupiedRails = new HashMap<>();
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (!train.isPlaced()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Point position = train.getFrontPosition();
|
||||||
|
Point direction = train.getDirection();
|
||||||
|
Point nextPosition = move(position, direction);
|
||||||
|
if (nextPosition == null
|
||||||
|
|| (train.isOnPosition(nextPosition)
|
||||||
|
&& !train.getBackPosition().equals(train.getFrontPosition()))) {
|
||||||
|
collisions.add(new HashSet<>(Arrays.asList(train)));
|
||||||
|
train.removeFromRails();
|
||||||
|
nextOccupiedRails.put(train, occupiedRails.get(train));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
train.moveTo(nextPosition);
|
||||||
|
train.setDirection(direction);
|
||||||
|
nextOccupiedRails.put(train, rails.stream().filter(train::isPartiallyOn).collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
// check for block collisions
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (!train.isPlaced() || collisions.stream().anyMatch((x) -> x.contains(train))) {
|
||||||
|
continue; // already included in collision
|
||||||
|
}
|
||||||
|
Set<Rail> occupiedByThisTrain = nextOccupiedRails.get(train);
|
||||||
|
trains.stream().filter((x) -> x != train && x.isPlaced()).forEach((otherTrain) -> {
|
||||||
|
Set<Rail> occupiedByOtherTrainPreviously = occupiedRails.get(otherTrain);
|
||||||
|
Set<Rail> occupiedByOtherTrain = nextOccupiedRails.get(otherTrain);
|
||||||
|
boolean anyIntersection = occupiedByOtherTrain.stream().anyMatch(occupiedByThisTrain::contains)
|
||||||
|
|| occupiedByOtherTrainPreviously.stream().anyMatch(occupiedByThisTrain::contains);
|
||||||
|
if (anyIntersection) {
|
||||||
|
train.removeFromRails();
|
||||||
|
// try to find/merge existing collisions
|
||||||
|
Set<Train> existingCollision = null;
|
||||||
|
for (Set<Train> collision : collisions) {
|
||||||
|
if (collision.contains(otherTrain)) {
|
||||||
|
if (existingCollision == null) {
|
||||||
|
existingCollision = collision;
|
||||||
|
collision.add(train);
|
||||||
|
} else {
|
||||||
|
existingCollision.addAll(collision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return collisions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<Set<Train>> getCollisionsOfOneReverseStep() {
|
||||||
|
ArrayList<Set<Train>> collisions = new ArrayList<>();
|
||||||
|
// check touching trains
|
||||||
|
/*
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (!train.isPlaced()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Train otherTrain : trains) {
|
||||||
|
if (!otherTrain.isPlaced() || train == otherTrain) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (train.getBackPosition().equals(otherTrain.getBackPosition())) {
|
||||||
|
train.removeFromRails();
|
||||||
|
otherTrain.removeFromRails();
|
||||||
|
collisions.add(new HashSet<>(Arrays.asList(train, otherTrain)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Map<Train, Set<Rail>> occupiedRails = new HashMap<>();
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (train.isPlaced()) {
|
||||||
|
Set<Rail> occupied = rails.stream().filter(train::isPartiallyOn).collect(Collectors.toSet());
|
||||||
|
occupiedRails.put(train, occupied);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// perform step
|
||||||
|
Map<Train, Set<Rail>> nextOccupiedRails = new HashMap<>();
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (!train.isPlaced()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Point front = train.getFrontPosition();
|
||||||
|
Point position = train.getBackPosition();
|
||||||
|
Point direction = train.getBackDirection();
|
||||||
|
Point nextPosition = move(position, direction);
|
||||||
|
if (nextPosition == null
|
||||||
|
|| (train.isOnPosition(nextPosition) && !train.getFrontPosition().equals(nextPosition))) {
|
||||||
|
collisions.add(new HashSet<>(Arrays.asList(train)));
|
||||||
|
train.removeFromRails();
|
||||||
|
nextOccupiedRails.put(train, occupiedRails.get(train));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
train.moveBackTo(nextPosition);
|
||||||
|
train.setDirection(front.subtract(train.getFrontPosition()));
|
||||||
|
nextOccupiedRails.put(train, rails.stream().filter(train::isPartiallyOn).collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
// check for block collisions
|
||||||
|
for (Train train : trains) {
|
||||||
|
if (!train.isPlaced() || collisions.stream().anyMatch((x) -> x.contains(train))) {
|
||||||
|
continue; // already included in collision
|
||||||
|
}
|
||||||
|
Set<Rail> occupiedByThisTrain = nextOccupiedRails.get(train);
|
||||||
|
trains.stream().filter((x) -> x != train && train.isPlaced()).forEach((otherTrain) -> {
|
||||||
|
Set<Rail> occupiedByOtherTrainPreviously = occupiedRails.get(otherTrain);
|
||||||
|
Set<Rail> occupiedByOtherTrain = nextOccupiedRails.get(otherTrain);
|
||||||
|
boolean anyIntersection = occupiedByOtherTrain.stream().anyMatch(occupiedByThisTrain::contains)
|
||||||
|
|| occupiedByOtherTrainPreviously.stream().anyMatch(occupiedByThisTrain::contains);
|
||||||
|
if (anyIntersection) {
|
||||||
|
train.removeFromRails();
|
||||||
|
// try to find/merge existing collisions
|
||||||
|
Set<Train> existingCollision = null;
|
||||||
|
for (Set<Train> collision : collisions) {
|
||||||
|
if (collision.contains(otherTrain)) {
|
||||||
|
if (existingCollision == null) {
|
||||||
|
existingCollision = collision;
|
||||||
|
collision.add(train);
|
||||||
|
} else {
|
||||||
|
existingCollision.addAll(collision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return collisions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param position
|
||||||
|
* @param direction has to be (0,1) (0,-1) (1,0) (-1,0) will be modified if necessary
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Point move(final Point position, final Point direction) {
|
||||||
|
Rail containingRail = findContainingRail(position);
|
||||||
|
if (containingRail != null) {
|
||||||
|
return position.moveBy(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
|
||||||
|
Point nextPosition = position.moveBy(direction);
|
||||||
|
if (!touchingRails[0].contains(nextPosition)) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return nextPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Point nextPosition = position.moveBy(direction);
|
||||||
|
if (touchingRails[0].contains(nextPosition) || touchingRails[0].connectsTo(nextPosition)) {
|
||||||
|
return nextPosition;
|
||||||
|
} else if (touchingRails[1].contains(nextPosition)) {
|
||||||
|
Point nextDirection = touchingRails[1].getDirectionFrom(position);
|
||||||
|
direction.x = nextDirection.x;
|
||||||
|
direction.y = nextDirection.y;
|
||||||
|
return nextPosition;
|
||||||
|
}
|
||||||
|
Point previousPosition = position.moveBy(direction.negated());
|
||||||
|
Rail nextRail = (touchingRails[0].contains(previousPosition)
|
||||||
|
|| touchingRails[0].canConnectTo(previousPosition)) ? touchingRails[1] : touchingRails[0];
|
||||||
|
Point nextDirection = nextRail.getDirectionFrom(position);
|
||||||
|
if (nextDirection != null) {
|
||||||
|
direction.x = nextDirection.x;
|
||||||
|
direction.y = nextDirection.y;
|
||||||
|
return position.moveBy(direction);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rail findContainingRail(final Point position) {
|
||||||
|
for (Rail rail : rails) {
|
||||||
|
if (rail.contains(position)) {
|
||||||
|
return rail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rail[] findTouchingRails(final Point position) {
|
||||||
|
return rails.stream().filter((rail) -> rail.canConnectTo(position)).toArray(Rail[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void step(final short speed) {
|
||||||
|
if (!rails.stream().allMatch(Rail::isReadyForTrains)) {
|
||||||
|
Terminal.printError("rail tracks/switches not set up");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (trains.stream().noneMatch(Train::isPlaced)) {
|
||||||
|
Terminal.printLine("OK");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Set<Train>> collisions = new ArrayList<>();
|
||||||
|
for (int i = 0; i < speed; i++) {
|
||||||
|
List<Set<Train>> newCollisions = getCollisionsOfOneStep();
|
||||||
|
collisions.addAll(newCollisions);
|
||||||
|
}
|
||||||
|
for (int i = 0; i > speed; i--) {
|
||||||
|
List<Set<Train>> newCollisions = getCollisionsOfOneReverseStep();
|
||||||
|
collisions.addAll(newCollisions);
|
||||||
|
}
|
||||||
|
train: for (Train train : trains) {
|
||||||
|
for (Set<Train> collisionSet : collisions) {
|
||||||
|
if (!collisionSet.contains(train)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<Train> collision = collisionSet.stream().sorted(Comparator.comparing(Train::getIdentifier))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (collision.indexOf(train) == 0) {
|
||||||
|
Terminal.printLine("Crash of train " + String.join(",",
|
||||||
|
collision.stream().map(
|
||||||
|
(x) -> Integer.toString(x.getIdentifier())).toArray(String[]::new)));
|
||||||
|
}
|
||||||
|
continue train;
|
||||||
|
}
|
||||||
|
if (train.isPlaced()) {
|
||||||
|
Terminal.printLine(String.format("Train %d at %s", train.getIdentifier(), train.getFrontPosition()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
src/edu/kit/informatik/Point.java
Normal file
83
src/edu/kit/informatik/Point.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class Point {
|
||||||
|
public int x;
|
||||||
|
public int y;
|
||||||
|
|
||||||
|
public Point(int x, int y) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* assumes good input like x,y
|
||||||
|
* @param input
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Point parse(final String input) {
|
||||||
|
String[] coordinates = input.split(",", 2);
|
||||||
|
int x = Integer.parseInt(coordinates[0]);
|
||||||
|
int y = Integer.parseInt(coordinates[1]);
|
||||||
|
return new Point(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("(%d,%d)", x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Taxicab distance to other point
|
||||||
|
* @param other
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int distanceTo(final Point other) {
|
||||||
|
return Math.abs(this.x - other.x) + Math.abs(this.y - other.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* normalize x and y *separately*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Point normalized() {
|
||||||
|
if (x >= 0 && x <= 1 && y >= 0 && y <= 1) {
|
||||||
|
return this;
|
||||||
|
} else if (x != 0 && y != 0) {
|
||||||
|
return new Point(x / Math.abs(x), y / Math.abs(y));
|
||||||
|
} else if (x != 0) {
|
||||||
|
return new Point(x / Math.abs(x), 0);
|
||||||
|
} else { // y != 0
|
||||||
|
return new Point(0, y / Math.abs(y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point negated() {
|
||||||
|
return new Point(-x, -y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point subtract(Point other) {
|
||||||
|
return new Point(x - other.x, y - other.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point moveBy(final Point movement) {
|
||||||
|
return new Point(x + movement.x, y + movement.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj != null && getClass().equals(obj.getClass())) {
|
||||||
|
final Point point = (Point) obj;
|
||||||
|
|
||||||
|
return x == point.x && y == point.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(x, y);
|
||||||
|
}
|
||||||
|
}
|
25
src/edu/kit/informatik/Rail.java
Normal file
25
src/edu/kit/informatik/Rail.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
public abstract class Rail {
|
||||||
|
protected int id;
|
||||||
|
|
||||||
|
public int getIdentifier() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
public abstract boolean connectsTo(Point point);
|
||||||
|
public abstract boolean canConnectTo(Point point);
|
||||||
|
public abstract boolean canConnectToRail(Rail rail);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true success, false fail
|
||||||
|
* @param position
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract boolean switchTo(Point position);
|
||||||
|
|
||||||
|
public abstract boolean isReadyForTrains();
|
||||||
|
|
||||||
|
public abstract boolean contains(Point position);
|
||||||
|
|
||||||
|
public abstract Point getDirectionFrom(Point position);
|
||||||
|
}
|
28
src/edu/kit/informatik/RollingStock.java
Normal file
28
src/edu/kit/informatik/RollingStock.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
public abstract class RollingStock {
|
||||||
|
protected int length;
|
||||||
|
protected boolean couplingFront;
|
||||||
|
protected boolean couplingBack;
|
||||||
|
|
||||||
|
public abstract String getIdentifier();
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasCouplingFront() {
|
||||||
|
return couplingFront;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasCouplingBack() {
|
||||||
|
return couplingBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean canCoupleFrontTo(RollingStock rollingStock);
|
||||||
|
public abstract boolean canCoupleToTrainSetSeries(String series);
|
||||||
|
|
||||||
|
public abstract String[] textRepresentation();
|
||||||
|
|
||||||
|
public abstract String description();
|
||||||
|
}
|
35
src/edu/kit/informatik/SteamEngine.java
Normal file
35
src/edu/kit/informatik/SteamEngine.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
public class SteamEngine extends Engine {
|
||||||
|
public SteamEngine(final String series, final String name, final int length, final boolean couplingFront, final boolean couplingBack) {
|
||||||
|
super.name = name;
|
||||||
|
super.series = series;
|
||||||
|
super.length = length;
|
||||||
|
super.couplingFront = couplingFront;
|
||||||
|
super.couplingBack = couplingBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("s %s %s %d %b %b", series, name, length, couplingFront, couplingBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String[] STEAM_ENGINE_TEXT = new String[] {
|
||||||
|
" ++ +------",
|
||||||
|
" || |+-+ | ",
|
||||||
|
" /---------|| | | ",
|
||||||
|
" + ======== +-+ | ",
|
||||||
|
" _|--/~\\------/~\\-+ ",
|
||||||
|
"//// \\_/ \\_/ "
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] textRepresentation() {
|
||||||
|
return STEAM_ENGINE_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String description() {
|
||||||
|
return "steam engine";
|
||||||
|
}
|
||||||
|
}
|
105
src/edu/kit/informatik/Switch.java
Normal file
105
src/edu/kit/informatik/Switch.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public final class Switch extends Rail {
|
||||||
|
public final Point start;
|
||||||
|
public final Point end1;
|
||||||
|
public final Point end2;
|
||||||
|
public Point selection;
|
||||||
|
|
||||||
|
public Switch(Point start, Point end1, Point end2, int id) {
|
||||||
|
this.start = start;
|
||||||
|
this.end1 = end1;
|
||||||
|
this.end2 = end2;
|
||||||
|
super.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canConnectTo(Point point) {
|
||||||
|
return point.equals(start) || point.equals(end1) || point.equals(end2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean connectsTo(Point point) {
|
||||||
|
return point.equals(start) || point.equals(selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canConnectToRail(Rail rail) {
|
||||||
|
return rail.canConnectTo(start) || rail.canConnectTo(end1) || rail.canConnectTo(end2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean switchTo(Point position) {
|
||||||
|
if (position.equals(end1) || position.equals(end2)) {
|
||||||
|
selection = new Point(position.x, position.y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReadyForTrains() {
|
||||||
|
return selection != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(final Point position) {
|
||||||
|
if (selection == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (start.x == selection.x && position.x == start.x) {
|
||||||
|
if (start.y < selection.y) {
|
||||||
|
return start.y < position.y && position.y < selection.y;
|
||||||
|
} else {
|
||||||
|
return start.y > position.y && position.y > selection.y;
|
||||||
|
}
|
||||||
|
} else if (start.y == selection.y && position.y == start.y) {
|
||||||
|
if (start.x < selection.x) {
|
||||||
|
return start.x < position.x && position.x < selection.x;
|
||||||
|
} else {
|
||||||
|
return start.x > position.x && position.x > selection.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point getDirectionFrom(Point position) {
|
||||||
|
if (selection == null) {
|
||||||
|
return null;
|
||||||
|
} else if (start.equals(position)) {
|
||||||
|
return new Point(selection.x - start.x, selection.y - start.y).normalized();
|
||||||
|
} else if (selection.equals(position)) {
|
||||||
|
return new Point(start.x - selection.x, start.y - selection.y).normalized();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (selection == null) {
|
||||||
|
return String.format("s %d %s -> %s,%s", getIdentifier(), start, end1, end2);
|
||||||
|
} else {
|
||||||
|
return String.format("s %d %s -> %s,%s %d", getIdentifier(), start, end1, end2, start.distanceTo(selection));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj != null && getClass().equals(obj.getClass())) {
|
||||||
|
final Switch otherSwitch = (Switch) obj;
|
||||||
|
|
||||||
|
return start.equals(otherSwitch.start) && end1.equals(otherSwitch.end1) && end2.equals(otherSwitch.end2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(start, end1, end2);
|
||||||
|
}
|
||||||
|
}
|
129
src/edu/kit/informatik/Terminal.java
Normal file
129
src/edu/kit/informatik/Terminal.java
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides some simple methods for input/output from and to a terminal as well as a method to read in
|
||||||
|
* files.
|
||||||
|
*
|
||||||
|
* <p><b>Never modify this class, never upload it to Praktomat.</b> This is only for your local use. If an assignment
|
||||||
|
* tells you to use this class for input and output never use System.out, System.err or System.in in the same
|
||||||
|
* assignment.
|
||||||
|
*
|
||||||
|
* @author ITI, VeriAlg Group
|
||||||
|
* @author IPD, SDQ Group
|
||||||
|
* @version 5.03, 2016/05/07
|
||||||
|
*/
|
||||||
|
public final class Terminal {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads text from the "standard" input stream, buffering characters so as to provide for the efficient reading
|
||||||
|
* of characters, arrays, and lines. This stream is already open and ready to supply input data and corresponds
|
||||||
|
* to keyboard input.
|
||||||
|
*/
|
||||||
|
private static BufferedReader IN = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
|
||||||
|
public static void reload() {
|
||||||
|
IN = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to avoid object generation.
|
||||||
|
*
|
||||||
|
* @deprecated Utility-class constructor.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
private Terminal() {
|
||||||
|
throw new AssertionError("Utility class constructor.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the given error-{@code message} with the prefix "{@code Error, }".
|
||||||
|
*
|
||||||
|
* <p>More specific, this method behaves exactly as if the following code got executed:
|
||||||
|
* <blockquote><pre>
|
||||||
|
* Terminal.printLine("Error, " + message);</pre>
|
||||||
|
* </blockquote>
|
||||||
|
*
|
||||||
|
* @param message the error message to be printed
|
||||||
|
* @see #printLine(Object)
|
||||||
|
*/
|
||||||
|
public static void printError(final String message) {
|
||||||
|
Terminal.printLine("Error, " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the string representation of an {@code Object} and then terminate the line.
|
||||||
|
*
|
||||||
|
* <p>If the argument is {@code null}, then the string {@code "null"} is printed, otherwise the object's string
|
||||||
|
* value {@code obj.toString()} is printed.
|
||||||
|
*
|
||||||
|
* @param object the {@code Object} to be printed
|
||||||
|
* @see String#valueOf(Object)
|
||||||
|
*/
|
||||||
|
public static void printLine(final Object object) {
|
||||||
|
System.out.println(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints an array of characters and then terminate the line.
|
||||||
|
*
|
||||||
|
* <p>If the argument is {@code null}, then a {@code NullPointerException} is thrown, otherwise the value of {@code
|
||||||
|
* new String(charArray)} is printed.
|
||||||
|
*
|
||||||
|
* @param charArray an array of chars to be printed
|
||||||
|
* @see String#valueOf(char[])
|
||||||
|
*/
|
||||||
|
public static void printLine(final char[] charArray) {
|
||||||
|
/*
|
||||||
|
* Note: This method's sole purpose is to ensure that the Terminal-class behaves exactly as
|
||||||
|
* System.out regarding output. (System.out.println(char[]) calls String.valueOf(char[])
|
||||||
|
* which itself returns 'new String(char[])' and is therefore the only method that behaves
|
||||||
|
* differently when passing the provided parameter to the System.out.println(Object)
|
||||||
|
* method.)
|
||||||
|
*/
|
||||||
|
System.out.println(charArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return
|
||||||
|
* ('\r'), or a carriage return followed immediately by a linefeed.
|
||||||
|
*
|
||||||
|
* @return a {@code String} containing the contents of the line, not including any line-termination characters, or
|
||||||
|
* {@code null} if the end of the stream has been reached
|
||||||
|
*/
|
||||||
|
public static String readLine() {
|
||||||
|
try {
|
||||||
|
return IN.readLine();
|
||||||
|
} catch (final IOException e) {
|
||||||
|
/*
|
||||||
|
* The IOException will not occur during tests executed by the praktomat, therefore the
|
||||||
|
* following RuntimeException does not have to get handled.
|
||||||
|
*/
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the file with the specified path and returns its content stored in a {@code String} array, whereas the
|
||||||
|
* first array field contains the file's first line, the second field contains the second line, and so on.
|
||||||
|
*
|
||||||
|
* @param path the path of the file to be read
|
||||||
|
* @return the content of the file stored in a {@code String} array
|
||||||
|
*/
|
||||||
|
public static String[] readFile(final String path) {
|
||||||
|
try (final BufferedReader reader = new BufferedReader(new FileReader(path))) {
|
||||||
|
return reader.lines().toArray(String[]::new);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
/*
|
||||||
|
* You can expect that the praktomat exclusively provides valid file-paths. Therefore
|
||||||
|
* there will no IOException occur while reading in files during the tests, the
|
||||||
|
* following RuntimeException does not have to get handled.
|
||||||
|
*/
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
90
src/edu/kit/informatik/Track.java
Normal file
90
src/edu/kit/informatik/Track.java
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public final class Track extends Rail {
|
||||||
|
public final Point start;
|
||||||
|
public final Point end;
|
||||||
|
|
||||||
|
public Track(final Point start, final Point end, final int id) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
super.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canConnectTo(Point point) {
|
||||||
|
return point.equals(start) || point.equals(end);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean connectsTo(Point point) {
|
||||||
|
return canConnectTo(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canConnectToRail(Rail rail) {
|
||||||
|
if (rail == null) {
|
||||||
|
System.out.println("hey");
|
||||||
|
}
|
||||||
|
return rail.canConnectTo(start) || rail.canConnectTo(end);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean switchTo(Point position) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReadyForTrains() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Point position) {
|
||||||
|
if (start.x == end.x && position.x == start.x) {
|
||||||
|
int dy0 = Math.abs(start.y - end.y);
|
||||||
|
int dy1 = Math.abs(start.y - position.y);
|
||||||
|
int dy2 = Math.abs(end.y - position.y);
|
||||||
|
return dy1 > 0 && dy2 > 0 && dy1 < dy0 && dy2 < dy0;
|
||||||
|
} else if (start.y == end.y && position.y == start.y) {
|
||||||
|
int dx0 = Math.abs(start.x - end.x);
|
||||||
|
int dx1 = Math.abs(start.x - position.x);
|
||||||
|
int dx2 = Math.abs(end.x - position.x);
|
||||||
|
return dx1 > 0 && dx2 > 0 && dx1 < dx0 && dx2 < dx0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point getDirectionFrom(Point position) {
|
||||||
|
if (start.equals(position)) {
|
||||||
|
return new Point(end.x - start.x, end.y - start.y).normalized();
|
||||||
|
} else if (end.equals(position)) {
|
||||||
|
return new Point(start.x - end.x, start.y - end.y).normalized();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("t %d %s -> %s %d", getIdentifier(), start, end, start.distanceTo(end));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj != null && getClass().equals(obj.getClass())) {
|
||||||
|
final Track track = (Track) obj;
|
||||||
|
|
||||||
|
return start.equals(track.start) && end.equals(track.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(start, end);
|
||||||
|
}
|
||||||
|
}
|
166
src/edu/kit/informatik/Train.java
Normal file
166
src/edu/kit/informatik/Train.java
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class Train {
|
||||||
|
private final int identifier; // start at 1
|
||||||
|
private final List<RollingStock> rollingStocks = new ArrayList<>();
|
||||||
|
private List<Point> position;
|
||||||
|
private Point direction;
|
||||||
|
|
||||||
|
public Train(final int identifier, final RollingStock rollingStock) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.rollingStocks.add(rollingStock);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIdentifier() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(RollingStock rollingStock) {
|
||||||
|
return rollingStocks.contains(rollingStock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true success, false fail
|
||||||
|
* @param rollingStock
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean add(RollingStock rollingStock) {
|
||||||
|
if (rollingStock.canCoupleFrontTo(rollingStocks.get(rollingStocks.size() - 1))) {
|
||||||
|
rollingStocks.add(rollingStock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder(Integer.toString(getIdentifier()));
|
||||||
|
for (RollingStock rollingStock : rollingStocks) {
|
||||||
|
stringBuilder.append(' ');
|
||||||
|
stringBuilder.append(rollingStock.getIdentifier());
|
||||||
|
}
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print() {
|
||||||
|
List<StringBuilder> lines = new ArrayList<>();
|
||||||
|
for (RollingStock rollingStock : rollingStocks) {
|
||||||
|
String[] text = rollingStock.textRepresentation();
|
||||||
|
for (StringBuilder line : lines) {
|
||||||
|
line.append(' ');
|
||||||
|
}
|
||||||
|
while (lines.size() < text.length) {
|
||||||
|
StringBuilder line = new StringBuilder();
|
||||||
|
if (!lines.isEmpty()) {
|
||||||
|
for (int i = 0; i < lines.get(0).length(); i++) {
|
||||||
|
line.append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lines.add(line);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < text.length; i++) {
|
||||||
|
lines.get(lines.size() - 1 - i).append(text[text.length - 1 - i]);
|
||||||
|
}
|
||||||
|
int finalLength = lines.get(lines.size() - 1).length();
|
||||||
|
for (StringBuilder line : lines) {
|
||||||
|
if (line.length() < finalLength) {
|
||||||
|
for (int i = 0; i < finalLength - line.length(); i++) {
|
||||||
|
line.append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (StringBuilder line : lines) {
|
||||||
|
Terminal.printLine(line.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPlaced() {
|
||||||
|
return position != null && direction != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void storePositionAndDirection(final List<Point> positions, final Point direction) {
|
||||||
|
this.position = positions;
|
||||||
|
this.direction = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isProperTrain() {
|
||||||
|
RollingStock first = rollingStocks.get(0);
|
||||||
|
RollingStock last = rollingStocks.get(rollingStocks.size() - 1);
|
||||||
|
// the first or last rolling stock HAVE TO BE an engine OR a train-set!
|
||||||
|
// therefore, no other rolling stock types should be allowed at all.
|
||||||
|
return (first instanceof Engine || first instanceof TrainSet)
|
||||||
|
|| (last instanceof Engine || last instanceof TrainSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPartiallyOn(Rail rail) {
|
||||||
|
return position.stream().anyMatch(rail::contains)
|
||||||
|
|| position.stream().filter(rail::connectsTo).count() == 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getFrontPosition() {
|
||||||
|
if (position != null) {
|
||||||
|
return position.get(0);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getBackPosition() {
|
||||||
|
if (position != null) {
|
||||||
|
return position.get(position.size() - 1);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getDirection() {
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getBackDirection() {
|
||||||
|
if (position.size() == 1) {
|
||||||
|
return direction.negated();
|
||||||
|
} else {
|
||||||
|
return position.get(position.size() - 1).subtract(position.get(position.size() - 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveTo(Point nextPosition) {
|
||||||
|
position.add(0, nextPosition);
|
||||||
|
position.remove(position.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveBackTo(Point backPosition) {
|
||||||
|
position.remove(0);
|
||||||
|
position.add(backPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirection(Point newDirection) {
|
||||||
|
direction = newDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFromRails() {
|
||||||
|
position = null;
|
||||||
|
direction = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean touches(Train other) {
|
||||||
|
return other.isOnAnyPosition(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOnPosition(Point point) {
|
||||||
|
return position.contains(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOnAnyPosition(List<Point> positions) {
|
||||||
|
return position.stream().anyMatch(positions::contains);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return rollingStocks.stream().mapToInt((RollingStock::getLength)).sum();
|
||||||
|
}
|
||||||
|
}
|
55
src/edu/kit/informatik/TrainSet.java
Normal file
55
src/edu/kit/informatik/TrainSet.java
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package edu.kit.informatik;
|
||||||
|
|
||||||
|
public class TrainSet extends RollingStock {
|
||||||
|
private String series;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public TrainSet(final String series, final String name, final int length, final boolean couplingFront, final boolean couplingBack) {
|
||||||
|
this.name = name;
|
||||||
|
this.series = series;
|
||||||
|
super.length = length;
|
||||||
|
super.couplingFront = couplingFront;
|
||||||
|
super.couplingBack = couplingBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentifier() {
|
||||||
|
return String.format("%s-%s", series, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("%s %s %d %b %b", series, name, length, couplingFront, couplingBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canCoupleFrontTo(RollingStock rollingStock) {
|
||||||
|
return hasCouplingFront() && rollingStock.hasCouplingBack() && rollingStock.canCoupleToTrainSetSeries(series);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canCoupleToTrainSetSeries(String series) {
|
||||||
|
return this.series.equals(series);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String[] TRAIN_SET_TEXT = new String[] {
|
||||||
|
" ++ ",
|
||||||
|
" || ",
|
||||||
|
"_________||_________",
|
||||||
|
"| ___ ___ ___ ___ |",
|
||||||
|
"| |_| |_| |_| |_| |",
|
||||||
|
"|__________________|",
|
||||||
|
"|__________________|",
|
||||||
|
" (O) (O) "
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] textRepresentation() {
|
||||||
|
return TRAIN_SET_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String description() {
|
||||||
|
return "train-set";
|
||||||
|
}
|
||||||
|
}
|
27
src/edu/kit/informatik/command/AddSwitch.java
Normal file
27
src/edu/kit/informatik/command/AddSwitch.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
import edu.kit.informatik.Point;
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
|
public class AddSwitch extends Command {
|
||||||
|
private final Point start;
|
||||||
|
private final Point end1;
|
||||||
|
private final Point end2;
|
||||||
|
|
||||||
|
public AddSwitch(final Point start, final Point end1, final Point end2) {
|
||||||
|
this.start = start;
|
||||||
|
this.end1 = end1;
|
||||||
|
this.end2 = end2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
int id = simulation.addSwitch(start, end1, end2);
|
||||||
|
if (id == -1) {
|
||||||
|
Terminal.printError("switch not connected to existing rails");
|
||||||
|
} else {
|
||||||
|
Terminal.printLine(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
src/edu/kit/informatik/command/AddTrack.java
Normal file
29
src/edu/kit/informatik/command/AddTrack.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
import edu.kit.informatik.Point;
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
|
public class AddTrack extends Command {
|
||||||
|
private Point start;
|
||||||
|
private Point end;
|
||||||
|
|
||||||
|
public AddTrack(final Point start, final Point end) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
if (start.equals(end)) {
|
||||||
|
Terminal.printError("track has length 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int id = simulation.addTrack(start, end);
|
||||||
|
if (id == -1) {
|
||||||
|
Terminal.printError("track is not connected to other tracks");
|
||||||
|
} else {
|
||||||
|
Terminal.printLine(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/edu/kit/informatik/command/AddTrain.java
Normal file
26
src/edu/kit/informatik/command/AddTrain.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
import edu.kit.informatik.RollingStock;
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
|
public class AddTrain extends Command {
|
||||||
|
private final int trainId;
|
||||||
|
private final String rollingStockId;
|
||||||
|
|
||||||
|
public AddTrain(final int trainId, final String rollingStockId) {
|
||||||
|
this.trainId = trainId;
|
||||||
|
this.rollingStockId = rollingStockId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
if (simulation.addTrain(trainId, rollingStockId)) {
|
||||||
|
RollingStock rollingStock = simulation.getRollingStock(rollingStockId);
|
||||||
|
Terminal.printLine(String.format("%s %s added to train %d",
|
||||||
|
rollingStock.description(), rollingStock.getIdentifier(), trainId));
|
||||||
|
} else {
|
||||||
|
Terminal.printError("could not modify train");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/edu/kit/informatik/command/Command.java
Normal file
14
src/edu/kit/informatik/command/Command.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic command that can be applied to a simulation.
|
||||||
|
* Commands are implemented as separate classes to avoid god enums :)
|
||||||
|
*
|
||||||
|
* @author Arne Keller
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
public abstract class Command {
|
||||||
|
public abstract void apply(ModelRailwaySimulation simulation);
|
||||||
|
}
|
249
src/edu/kit/informatik/command/CommandFactory.java
Normal file
249
src/edu/kit/informatik/command/CommandFactory.java
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.CoachType;
|
||||||
|
import edu.kit.informatik.Point;
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class CommandFactory {
|
||||||
|
public static final String ADD_TRACK = "add track";
|
||||||
|
public static final Pattern ADD_TRACK_ARGUMENTS
|
||||||
|
= Pattern.compile(" \\(([+-]?\\d+,[+-]?\\d+)\\) -> \\(([+-]?\\d+,[+-]?\\d+)\\)");
|
||||||
|
public static final String ADD_SWITCH = "add switch";
|
||||||
|
public static final Pattern ADD_SWITCH_ARGUMENTS
|
||||||
|
= Pattern.compile(" \\(([+-]?\\d+,[+-]?\\d+)\\) -> \\(([+-]?\\d+,[+-]?\\d+)\\),\\(([+-]?\\d+,[+-]?\\d+)\\)");
|
||||||
|
public static final String DELETE_TRACK = "delete track";
|
||||||
|
public static final String LIST_TRACKS = "list tracks";
|
||||||
|
public static final String SET_SWITCH = "set switch";
|
||||||
|
public static final Pattern SET_SWITCH_ARGUMENTS
|
||||||
|
= Pattern.compile(" \\+?(\\d+) position \\(([+-]?\\d+,[+-]?\\d+)\\)");
|
||||||
|
public static final String CREATE_ENGINE = "create engine";
|
||||||
|
public static final Pattern CREATE_ENGINE_ARGUMENTS
|
||||||
|
= Pattern.compile(" (electrical|diesel|steam) (\\w+) (\\w+) \\+?(\\d+) (true|false) (true|false)");
|
||||||
|
public static final String LIST_ENGINES = "list engines";
|
||||||
|
public static final String CREATE_COACH = "create coach";
|
||||||
|
public static final Pattern CREATE_COACH_ARGUMENTS
|
||||||
|
= Pattern.compile(" (passenger|freight|special) \\+?(\\d+) (true|false) (true|false)");
|
||||||
|
public static final String LIST_COACHES = "list coaches";
|
||||||
|
public static final String CREATE_TRAIN_SET = "create train-set";
|
||||||
|
public static final Pattern CREATE_TRAIN_SET_ARGUMENTS
|
||||||
|
= Pattern.compile(" (\\w+) (\\w+) \\+?(\\d+) (true|false) (true|false)");
|
||||||
|
public static final String LIST_TRAIN_SETS = "list train-sets";
|
||||||
|
public static final String DELETE_ROLLING_STOCK = "delete rolling stock";
|
||||||
|
public static final Pattern DELETE_ROLLING_STOCK_ARGUMENT
|
||||||
|
= Pattern.compile(" (\\w+(-\\w*)?)");
|
||||||
|
public static final String ADD_TRAIN = "add train";
|
||||||
|
public static final Pattern ADD_TRAIN_ARGUMENTS
|
||||||
|
= Pattern.compile(" \\+?(\\d+) ((\\w+-\\w+)|(W\\+?\\d+))");
|
||||||
|
public static final String DELETE_TRAIN = "delete train";
|
||||||
|
public static final String LIST_TRAINS = "list trains";
|
||||||
|
public static final String SHOW_TRAIN = "show train";
|
||||||
|
public static final String PUT_TRAIN = "put train";
|
||||||
|
public static final Pattern PUT_TRAIN_ARGUMENTS
|
||||||
|
= Pattern.compile(" \\+?(\\d+) at \\(([+-]?\\d+,[+-]?\\d+)\\) in direction ([+-]?\\d+),([+-]?\\d+)");
|
||||||
|
public static final String STEP = "step";
|
||||||
|
public static final String POSITIVE_NUMBER = " \\+?\\d+";
|
||||||
|
|
||||||
|
public static Command getCommand(final String command) {
|
||||||
|
if (command.startsWith(ADD_TRACK)) {
|
||||||
|
String arguments = command.substring(ADD_TRACK.length());
|
||||||
|
Matcher matcher = ADD_TRACK_ARGUMENTS.matcher(arguments);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
Terminal.printError("invalid add track argument syntax");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Point start = Point.parse(matcher.group(1));
|
||||||
|
Point end = Point.parse(matcher.group(2));
|
||||||
|
if (start.x == end.x || start.y == end.y) {
|
||||||
|
return new AddTrack(start, end);
|
||||||
|
} else {
|
||||||
|
Terminal.printError("invalid track segment: not a straight line");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else if (command.startsWith(ADD_SWITCH)) {
|
||||||
|
String arguments = command.substring(ADD_SWITCH.length());
|
||||||
|
Matcher matcher = ADD_SWITCH_ARGUMENTS.matcher(arguments);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
Terminal.printError("invalid add switch argument syntax");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Point start = Point.parse(matcher.group(1));
|
||||||
|
Point end1 = Point.parse(matcher.group(2));
|
||||||
|
Point end2 = Point.parse(matcher.group(3));
|
||||||
|
if ((start.x == end1.x || start.y == end1.y) && (start.x == end2.x || start.y == end2.y)) {
|
||||||
|
return new AddSwitch(start, end1, end2);
|
||||||
|
} else {
|
||||||
|
Terminal.printError("invalid switch: not consisting of straight lines");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else if (command.startsWith(DELETE_TRACK)) {
|
||||||
|
String argument = command.substring(DELETE_TRACK.length());
|
||||||
|
if (!argument.matches(POSITIVE_NUMBER)) {
|
||||||
|
Terminal.printError("invalid/missing delete track argument");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int id = Integer.parseInt(argument.substring(1));
|
||||||
|
return new DeleteTrack(id);
|
||||||
|
} else if (command.startsWith(LIST_TRACKS)) {
|
||||||
|
if (command.length() > LIST_TRACKS.length()) {
|
||||||
|
Terminal.printError("too many arguments for list tracks");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ListTracks();
|
||||||
|
} else if (command.startsWith(SET_SWITCH)) {
|
||||||
|
String arguments = command.substring(SET_SWITCH.length());
|
||||||
|
Matcher matcher = SET_SWITCH_ARGUMENTS.matcher(arguments);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
Terminal.printError("invalid set switch argument syntax");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int id = Integer.parseInt(matcher.group(1));
|
||||||
|
Point point = Point.parse(matcher.group(2));
|
||||||
|
return new SetSwitch(id, point);
|
||||||
|
} else if (command.startsWith(CREATE_ENGINE)) {
|
||||||
|
String arguments = command.substring(CREATE_ENGINE.length());
|
||||||
|
Matcher matcher = CREATE_ENGINE_ARGUMENTS.matcher(arguments);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
Terminal.printError("invalid create engine argument syntax");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String type = matcher.group(1);
|
||||||
|
String series = matcher.group(2);
|
||||||
|
if (series.startsWith("W")) {
|
||||||
|
Terminal.printError("invalid engine class/series");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String name = matcher.group(3);
|
||||||
|
int length = Integer.parseInt(matcher.group(4));
|
||||||
|
boolean couplingFront = Boolean.parseBoolean(matcher.group(5));
|
||||||
|
boolean couplingBack = Boolean.parseBoolean(matcher.group(6));
|
||||||
|
return new CreateEngine(type, series, name, length, couplingFront, couplingBack);
|
||||||
|
} else if (command.startsWith(LIST_ENGINES)) {
|
||||||
|
if (command.length() > LIST_ENGINES.length()) {
|
||||||
|
Terminal.printError("too many list engines arguments");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ListEngines();
|
||||||
|
} else if (command.startsWith(CREATE_COACH)) {
|
||||||
|
String arguments = command.substring(CREATE_COACH.length());
|
||||||
|
Matcher matcher = CREATE_COACH_ARGUMENTS.matcher(arguments);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
Terminal.printError("invalid create coach arguments");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int length = Integer.parseInt(matcher.group(2));
|
||||||
|
boolean couplingFront = Boolean.parseBoolean(matcher.group(3));
|
||||||
|
boolean couplingBack = Boolean.parseBoolean(matcher.group(4));
|
||||||
|
switch (matcher.group(1)) {
|
||||||
|
case "passenger":
|
||||||
|
return new CreateCoach(CoachType.PASSENGER, length, couplingFront, couplingBack);
|
||||||
|
case "freight":
|
||||||
|
return new CreateCoach(CoachType.FREIGHT, length, couplingFront, couplingBack);
|
||||||
|
case "special":
|
||||||
|
return new CreateCoach(CoachType.SPECIAL, length, couplingFront, couplingBack);
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("regex matched unmatchable argument");
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (command.startsWith(LIST_COACHES)) {
|
||||||
|
if (command.length() > LIST_COACHES.length()) {
|
||||||
|
Terminal.printError("too many list coaches arguments");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ListCoaches();
|
||||||
|
} else if (command.startsWith(CREATE_TRAIN_SET)) {
|
||||||
|
String arguments = command.substring(CREATE_TRAIN_SET.length());
|
||||||
|
Matcher matcher = CREATE_TRAIN_SET_ARGUMENTS.matcher(arguments);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
Terminal.printError("invalid create train-set arguments");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String series = matcher.group(1);
|
||||||
|
if (series.startsWith("W")) {
|
||||||
|
Terminal.printError("invalid train-set class/series");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String name = matcher.group(2);
|
||||||
|
int length = Integer.parseInt(matcher.group(3));
|
||||||
|
boolean couplingFront = Boolean.parseBoolean(matcher.group(4));
|
||||||
|
boolean couplingBack = Boolean.parseBoolean(matcher.group(5));
|
||||||
|
return new CreateTrainSet(series, name, length, couplingFront, couplingBack);
|
||||||
|
} else if (command.startsWith(LIST_TRAIN_SETS)) {
|
||||||
|
if (command.length() > LIST_TRAIN_SETS.length()) {
|
||||||
|
Terminal.printError("too many list train-sets arguments");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ListTrainSets();
|
||||||
|
} else if (command.startsWith(DELETE_ROLLING_STOCK)) {
|
||||||
|
String argument = command.substring(DELETE_ROLLING_STOCK.length());
|
||||||
|
Matcher matcher = DELETE_ROLLING_STOCK_ARGUMENT.matcher(argument);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
Terminal.printLine("invalid delete rolling stock argument");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String id = matcher.group(1);
|
||||||
|
return new DeleteRollingStock(id);
|
||||||
|
} else if (command.startsWith(ADD_TRAIN)) {
|
||||||
|
String arguments = command.substring(ADD_TRAIN.length());
|
||||||
|
Matcher matcher = ADD_TRAIN_ARGUMENTS.matcher(arguments);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
Terminal.printError("invalid add train arguments");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int trainId = Integer.parseInt(matcher.group(1));
|
||||||
|
String rollingStockId = matcher.group(2);
|
||||||
|
return new AddTrain(trainId, rollingStockId);
|
||||||
|
} else if (command.startsWith(DELETE_TRAIN)) {
|
||||||
|
String argument = command.substring(DELETE_TRAIN.length());
|
||||||
|
if (!argument.matches(POSITIVE_NUMBER)) {
|
||||||
|
Terminal.printError("invalid delete train argument");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int id = Integer.parseInt(argument.substring(1));
|
||||||
|
return new DeleteTrain(id);
|
||||||
|
} else if (command.startsWith(LIST_TRAINS)) {
|
||||||
|
if (command.length() > LIST_TRAINS.length()) {
|
||||||
|
Terminal.printError("too many list trains arguments");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ListTrains();
|
||||||
|
} else if (command.startsWith(SHOW_TRAIN)) {
|
||||||
|
String argument = command.substring(SHOW_TRAIN.length());
|
||||||
|
if (!argument.matches(POSITIVE_NUMBER)) {
|
||||||
|
Terminal.printError("invalid show train argument");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int id = Integer.parseInt(argument.substring(1));
|
||||||
|
return new ShowTrain(id);
|
||||||
|
} else if (command.startsWith(PUT_TRAIN)) {
|
||||||
|
String arguments = command.substring(PUT_TRAIN.length());
|
||||||
|
Matcher matcher = PUT_TRAIN_ARGUMENTS.matcher(arguments);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
Terminal.printError("invalid put train arguments");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int id = Integer.parseInt(matcher.group(1));
|
||||||
|
Point point = Point.parse(matcher.group(2));
|
||||||
|
int x = Integer.parseInt(matcher.group(3));
|
||||||
|
int y = Integer.parseInt(matcher.group(4));
|
||||||
|
if (x != 0 && y != 0) {
|
||||||
|
Terminal.printError("invalid train direction");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new PutTrain(id, point, x, y);
|
||||||
|
} else if (command.startsWith(STEP)) {
|
||||||
|
String argument = command.substring(STEP.length());
|
||||||
|
if (!argument.matches(" [+-]?\\d+")) {
|
||||||
|
Terminal.printError("invalid step argument");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
short speed = Short.parseShort(argument.substring(1));
|
||||||
|
return new Step(speed);
|
||||||
|
} else {
|
||||||
|
Terminal.printError("unknown command");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
src/edu/kit/informatik/command/CreateCoach.java
Normal file
29
src/edu/kit/informatik/command/CreateCoach.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.CoachType;
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
|
public class CreateCoach extends Command {
|
||||||
|
private final CoachType type;
|
||||||
|
private final int length;
|
||||||
|
private final boolean couplingFront;
|
||||||
|
private final boolean couplingBack;
|
||||||
|
|
||||||
|
public CreateCoach(final CoachType type, final int length, final boolean couplingFront, final boolean couplingBack) {
|
||||||
|
this.type = type;
|
||||||
|
this.length = length;
|
||||||
|
this.couplingFront = couplingFront;
|
||||||
|
this.couplingBack = couplingBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
int id = simulation.createCoach(type, length, couplingFront, couplingBack);
|
||||||
|
if (id == -1) {
|
||||||
|
Terminal.printError("could not add coach");
|
||||||
|
} else {
|
||||||
|
Terminal.printLine(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
src/edu/kit/informatik/command/CreateEngine.java
Normal file
45
src/edu/kit/informatik/command/CreateEngine.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.*;
|
||||||
|
|
||||||
|
public class CreateEngine extends Command {
|
||||||
|
private final String type;
|
||||||
|
private final String series;
|
||||||
|
private final String name;
|
||||||
|
private final int length;
|
||||||
|
private final boolean couplingFront;
|
||||||
|
private final boolean couplingBack;
|
||||||
|
|
||||||
|
public CreateEngine(final String type, final String series, final String name, final int length, final boolean couplingFront, final boolean couplingBack) {
|
||||||
|
this.type = type;
|
||||||
|
this.series = series;
|
||||||
|
this.name = name;
|
||||||
|
this.length = length;
|
||||||
|
this.couplingFront = couplingFront;
|
||||||
|
this.couplingBack = couplingBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(final ModelRailwaySimulation simulation) {
|
||||||
|
final Engine engine;
|
||||||
|
switch (type) {
|
||||||
|
case "electrical":
|
||||||
|
engine = new ElectricalEngine(series, name, length, couplingFront, couplingBack);
|
||||||
|
break;
|
||||||
|
case "steam":
|
||||||
|
engine = new SteamEngine(series, name, length, couplingFront, couplingBack);
|
||||||
|
break;
|
||||||
|
case "diesel":
|
||||||
|
engine = new DieselEngine(series, name, length, couplingFront, couplingBack);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Terminal.printError("invalid engine type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (simulation.createEngine(engine)) {
|
||||||
|
Terminal.printLine(engine.getIdentifier());
|
||||||
|
} else {
|
||||||
|
Terminal.printLine("could not create engine");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
src/edu/kit/informatik/command/CreateTrainSet.java
Normal file
31
src/edu/kit/informatik/command/CreateTrainSet.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
import edu.kit.informatik.TrainSet;
|
||||||
|
|
||||||
|
public class CreateTrainSet extends Command {
|
||||||
|
private final String series;
|
||||||
|
private final String name;
|
||||||
|
private final int length;
|
||||||
|
private final boolean couplingFront;
|
||||||
|
private final boolean couplingBack;
|
||||||
|
|
||||||
|
public CreateTrainSet(final String series, final String name, final int length, final boolean couplingFront, final boolean couplingBack) {
|
||||||
|
this.series = series;
|
||||||
|
this.name = name;
|
||||||
|
this.length = length;
|
||||||
|
this.couplingFront = couplingFront;
|
||||||
|
this.couplingBack = couplingBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
TrainSet trainSet = new TrainSet(series, name, length, couplingFront, couplingBack);
|
||||||
|
if (simulation.createTrainSet(trainSet)) {
|
||||||
|
Terminal.printLine(trainSet.getIdentifier());
|
||||||
|
} else {
|
||||||
|
Terminal.printError("could not add train-set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
src/edu/kit/informatik/command/DeleteRollingStock.java
Normal file
21
src/edu/kit/informatik/command/DeleteRollingStock.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
|
public class DeleteRollingStock extends Command {
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
public DeleteRollingStock(final String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
if (simulation.deleteRollingStock(id)) {
|
||||||
|
Terminal.printLine("OK");
|
||||||
|
} else {
|
||||||
|
Terminal.printError("could not delete rolling stock");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
src/edu/kit/informatik/command/DeleteTrack.java
Normal file
21
src/edu/kit/informatik/command/DeleteTrack.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
|
public class DeleteTrack extends Command {
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
public DeleteTrack(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
if (simulation.removeRail(id)) {
|
||||||
|
Terminal.printLine("OK");
|
||||||
|
} else {
|
||||||
|
Terminal.printError("could not delete rail segment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
src/edu/kit/informatik/command/DeleteTrain.java
Normal file
21
src/edu/kit/informatik/command/DeleteTrain.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
|
public class DeleteTrain extends Command {
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
public DeleteTrain(final int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
if (simulation.deleteTrain(id)) {
|
||||||
|
Terminal.printLine("OK");
|
||||||
|
} else {
|
||||||
|
Terminal.printError("could not remove train");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/edu/kit/informatik/command/ListCoaches.java
Normal file
10
src/edu/kit/informatik/command/ListCoaches.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
|
||||||
|
public class ListCoaches extends Command {
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
simulation.printCoaches();
|
||||||
|
}
|
||||||
|
}
|
10
src/edu/kit/informatik/command/ListCoachesCommand.java
Normal file
10
src/edu/kit/informatik/command/ListCoachesCommand.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
|
||||||
|
public class ListCoachesCommand extends Command {
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
10
src/edu/kit/informatik/command/ListEngines.java
Normal file
10
src/edu/kit/informatik/command/ListEngines.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
|
||||||
|
public class ListEngines extends Command {
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
simulation.printEngines();
|
||||||
|
}
|
||||||
|
}
|
10
src/edu/kit/informatik/command/ListTracks.java
Normal file
10
src/edu/kit/informatik/command/ListTracks.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
|
||||||
|
public class ListTracks extends Command {
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
simulation.printTracks();
|
||||||
|
}
|
||||||
|
}
|
10
src/edu/kit/informatik/command/ListTrainSets.java
Normal file
10
src/edu/kit/informatik/command/ListTrainSets.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
|
||||||
|
public class ListTrainSets extends Command {
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
simulation.printTrainSets();
|
||||||
|
}
|
||||||
|
}
|
10
src/edu/kit/informatik/command/ListTrains.java
Normal file
10
src/edu/kit/informatik/command/ListTrains.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
|
||||||
|
public class ListTrains extends Command {
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
simulation.printTrains();
|
||||||
|
}
|
||||||
|
}
|
28
src/edu/kit/informatik/command/PutTrain.java
Normal file
28
src/edu/kit/informatik/command/PutTrain.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
import edu.kit.informatik.Point;
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
|
public class PutTrain extends Command {
|
||||||
|
private final int id;
|
||||||
|
private final Point point;
|
||||||
|
private final int x;
|
||||||
|
private final int y;
|
||||||
|
|
||||||
|
public PutTrain(final int id, final Point point, final int x, final int y) {
|
||||||
|
this.id = id;
|
||||||
|
this.point = point;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
if (simulation.putTrain(id, point, new Point(x, y))) {
|
||||||
|
Terminal.printLine("OK");
|
||||||
|
} else {
|
||||||
|
Terminal.printError("could not place train");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
src/edu/kit/informatik/command/SetSwitch.java
Normal file
24
src/edu/kit/informatik/command/SetSwitch.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
import edu.kit.informatik.Point;
|
||||||
|
import edu.kit.informatik.Terminal;
|
||||||
|
|
||||||
|
public class SetSwitch extends Command {
|
||||||
|
private final int id;
|
||||||
|
private final Point point;
|
||||||
|
|
||||||
|
public SetSwitch(final int id, final Point point) {
|
||||||
|
this.id = id;
|
||||||
|
this.point = point;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(final ModelRailwaySimulation simulation) {
|
||||||
|
if (simulation.setSwitch(id, point)) {
|
||||||
|
Terminal.printLine("OK");
|
||||||
|
} else {
|
||||||
|
Terminal.printError("could not set switch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/edu/kit/informatik/command/ShowTrain.java
Normal file
16
src/edu/kit/informatik/command/ShowTrain.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
|
||||||
|
public class ShowTrain extends Command {
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
public ShowTrain(final int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(final ModelRailwaySimulation simulation) {
|
||||||
|
simulation.printTrain(id);
|
||||||
|
}
|
||||||
|
}
|
16
src/edu/kit/informatik/command/Step.java
Normal file
16
src/edu/kit/informatik/command/Step.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package edu.kit.informatik.command;
|
||||||
|
|
||||||
|
import edu.kit.informatik.ModelRailwaySimulation;
|
||||||
|
|
||||||
|
public class Step extends Command {
|
||||||
|
private final short speed;
|
||||||
|
|
||||||
|
public Step(final short speed) {
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(ModelRailwaySimulation simulation) {
|
||||||
|
simulation.step(speed);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user