Ich verstehe im Moment noch nicht wie momentan die putTrain Methode genau strukturiert sein muss. Gerade fühlt es sich so an, als habe man einen Kasten aus Legosteinen und keins passt auf den Anderen genau drauf
/*
TODO:
- Check if there is even a track at the point <point>.
- If it is a switch at point <point> then check if it's switched to this track.
- Check if no other train is already on the required track(s) - note the length of the train
- Check if directionVector fits with direction of track
*/
public void putTrain(Train train, Point point, Point directionVector) throws LogicException {
...
long trainLength = train.getLength();
}
Track headOfTracks = findTrack(point, directionVector);
if (track == null) { throw ... } // kein passendes Gleis vorhanden
List<Track> requiredTracks = getRequiredTracks(headOfTracks, train, point, directionVector);
assertThatNoTrainIsAssigned(requiredTracks);
assignTrainToTracks(train, requiredTracks);
Das kann ich Dir so nicht sagen - ich hab den Code nicht hier, sondern mach das alles aus dem Kopf. Schmeiß' den Debugger an (oder bau entsprechende Ausgaben ein) und geh es Schritt für Schritt durch.Warum funktioniert es dann bei mir noch nicht?
Track headOfTracks = findTrack(point, directionVector).get();
List<Track> requiredTracks = getRequiredTracks(headOfTracks, point, directionVector, trainLength);
requiredTracks.forEach(required -> required.setCurrentTrain(train));
trainsOnTrack.put(directionVector, train);
Ich meine bezüglich der Fehlermeldung "Error, directions do not match". Ist das mit setCurrentTrain so in Ordnung?Ja, die Prüfung, ob kein Zug draufsteht, fehlt vor den letzten beiden Zeilen noch.
assignTrainTracks(train, requiredTracks);
Methode noch etwas anderes als requiredTracks.forEach(required -> required.setCurrentTrain(train));
trainsOnTrack.put(directionVector, train);
while (length > 0) {
...
if (!getConnection(passed, currentTrack).isPresent()) {
throw new ...("no connection track found");
}
currentTrack = getConnection(passed, currentTrack).get();
}
add track (1,1) -> (5,1)
1
add track (10,10) -> (10,11)
add switch (5,1) -> (8,1),(5,3)
2
add track (10,1) -> (8,1)
3
add switch (10,-3) -> (10,1),(12,-3)
4
add track (10,-3) -> (1,-3)
5
add track (1,-3) -> (1,1)
6
add track (5,3) -> (10,3)
7
add track (10,3) -> (12,3)
8
add switch (12,3) -> (12,-3),(14,3)
9
add track (14,-1) -> (14,3)
10
create engine steam T3 Emma 1 false true
T3-Emma
create coach passenger 1 true true
1
create coach passenger 1 true true
2
add train 1 T3-Emma
steam engine T3-Emma added to train 1
add train 1 W1
passenger coach W1 added to train 1
add train 1 W2
passenger coach W2 added to train 1
set switch 4 position (10,1)
OK
step 1
Expected error-message.
set switch 2 position (8,1)
OK
set switch 9 position (12,-3)
OK
step 1
Line 1 is missing: 'OK'
put train 1 at (1,1) in direction 1,0
Error, directions do not match
Line 1: expected 'OK', but got 'Error, directions do not match'
Point passed = currentTrack.getPassedPoint(direction);
wird erneut aufgerufen. Allerdings sieht der Ablauf jetzt so aus, wobei offensichtlich die Exception geworfen wird, da sich keine Koordinaten/Komponenten der Punkte/Vektoren gleichen.Ach, die Länge wird falsch berechnet... Wir berechnen Distanzen zwischen Punkten, d. h. zwischen (1,1) und (1,1) ist ein Abstand von 0 und ziehen daher von der Länge 0 ab. Tatsächlich hat auf dem einen Punkt eine Lok Platz. Gleichzeitig müssen wir aufpassen, dass wir die Punkte bei Anschlussgleisen nicht doppelt zählen.Beim Debuggen ist mir folgendes aufgefallen: beim ersten Durchgang (length = 1) funktioniert die Methode einwandfrei. Jetzt wird length dekrementiert undPoint passed = currentTrack.getPassedPoint(direction);
wird erneut aufgerufen.
length -= position.distanceTo(passed);
if (currentTack == startTack) length--;
private List<RawTrack> getRequiredTracks(RawTrack startTrack, CartesianPoint startPoint, CartesianPoint direction, int trainLength) {
RawTrack currentTrack = startTrack;
CartesianPoint position = startPoint;
List<RawTrack> requiredTracks = new ArrayList<>();
int length = trainLength;
while (length > 0) {
if (requiredTracks.contains(currentTrack)) {
//Exception, da dieser schon verwendet wird
}
requiredTracks.add(currentTrack);
CartesianPoint passed = currentTrack.getPassedPoint(direction);
length = length - position.distanceTo(passed);
position = passed;
if (!getConnection(passed, currentTrack).isPresent()) {
//Exception, weil kein Punkt gefunden
}
currentTrack = getConnection(passed, currentTrack).get();
}
return requiredTracks;
}
currentTrack = getConnection(passed, currentTrack).get();
direction = currentTrack.getDirectionTo(passed);
Ja, das entspricht meiner groben Skizze. Es geht einfach noch um Details wie z. B. die beiden Änderung von eben oder zusätzliche Abfragen wie z. B. evtl. noch erforderliche Längenprüfungen. So kann es z. B. noch notwendig sein,Ist das der richtige Ansatz?
position = passed;
if (!getConnection(passed, currentTrack).isPresent()) {
//Exception, weil kein Punkt gefunden
}
currentTrack = getConnection(passed, currentTrack).get();
public List<RawTrack> getRequiredTracks(RawTrack startTrack, CartesianPoint startPoint, CartesianPoint direction, int trainLength) {
RawTrack currentTrack = startTrack;
CartesianPoint position = startPoint;
List<RawTrack> requiredTracks = new ArrayList<>();
int length = trainLength;
outerloop:while (length > 0) {
if (requiredTracks.contains(currentTrack)) {
break outerloop;
//Exception, da dieser schon verwendet wird
}
requiredTracks.add(currentTrack);
CartesianPoint passed = currentTrack.getPassedPoint(direction);
length = length - position.distanceTo(passed);
position = passed;
Terminal.printLine(edgesReadyForDriving);
if (getConnection(passed, currentTrack).equals(currentTrack)) { //Wirft NullPointerException???
break outerloop;
//Exception, weil kein Punkt gefunden
}
currentTrack = getConnection(passed, currentTrack);
}
return requiredTracks;
}
private RawTrack getConnection(CartesianPoint point, RawTrack track) {
for (RawTrack tr : edgesReadyForDriving.get(point)) {
if (!tr.equals(track)) {
return tr;
}
}
return null;
}
railManager.addTrack(1, 1, 5, 1); //x1,y1,x2,y2 //track0
railManager.addTrack(5, 1, 8, 1); //das ist track1
CartesianPoint point1 = new CartesianPoint(6,1);
CartesianPoint direction = new CartesianPoint(1,0);
Terminal.printLine(railManager.getRequiredTracks(railManager.getTrack(1), point1, direction, 3));
[t 2 (5,1) -> (8,1) 3]
, also track1. add track (1,1) -> (5,1)
add track (5,1) -> (8,1)
put train 1 at (6,1) in direction 1,0 (Zug der Länge 3)
Error, train cannot be positioned
private List<Track> getRequiredTracks(Track startTrack, Point startPoint, Point direction, long trainLength) {
Track currentTrack = startTrack;
Point position = startPoint;
List<Track> requiredTracks = new ArrayList<>();
long length = trainLength;
Point dir = direction;
while (length > 0) {
if (currentTrack == null || requiredTracks.contains(currentTrack)) {
throw new ...("train cannot be positioned");
}
requiredTracks.add(currentTrack);
Point passed = currentTrack.getPassedPoint(dir);
length -= position.distanceTo(passed);
if (currentTrack == startTrack) {
length--;
}
position = passed;
if (getConnection(passed, currentTrack) == null) {
// Throw exception
}
currentTrack = getConnection(passed, currentTrack);
dir = currentTrack.getDirectionTo(passed);
}
// Wird i. d. F. gar nicht erst ausgeführt
Terminal.printLine(requiredTracks);
return requiredTracks;
}
dir
korrekt eingebaut?Wenn das erst in der zweiten Iteration passiert, dann musst Du Dir die erste anschauen: dort wird geprüft, ob getConnection() null liefert, falls ja -> Exception.Es wird doch currentTrack zu requiredTracks hinzugefügt und in der nächsten Iteration geschaut, ob currentTrack in requiredTracks enthalten ist -> Exception. Was ist hier falsch...?
private Track getConnection(Point point, Track track) {
for (Track tr : edges.get(point)) {
if (!tr.equals(track)) {
return tr;
}
}
return null;
}
Error, train cannot be positioned
lag an:Point dir = direction;
...
dir = currentTrack.getDirectionTo(passed);
Den Teil habe ich vorerst entfernt. Ist etwas falsch daran? Eventuell habe ich es falsch umgesetzt.Und noch was fällt mir gerade auf: die Richtung muss sich ebenfalls ändern, da das Anschlussgleis nicht der Fahrtrichtung der Lok entsprechen muss...
Nach
muss noch die richtige Richtung gesetzt werden:Java:currentTrack = getConnection(passed, currentTrack).get();
wobei currentTrack.getDirectionTo() den Richtungsvektor des Tracks in Richtung passed liefern muss.Java:direction = currentTrack.getDirectionTo(passed);
Error, no connection track found
if (getConnection(passed, currentTrack) == null) {
throw new ...("no connection track found");
}
Die Zeile muss drin bleiben aber getDirectionTo wird halt falsch implementiert sein. Wie sieht die Methode denn aus?Den Teil habe ich vorerst entfernt. Ist etwas falsch daran?
public Point getDirectionTo(Point vector) {
return new Point((int) Math.signum(vector.getFirstComponent()), (int) Math.signum(vector.getSecondComponent()));
}
currentTrack kann an der Stelle nicht null sein, den check kannst Du Dir sparen.dir = currentTrack != null ? currentTrack.getDirectionTo(passed) : null;
Ich dachte, toDirection() gibt den normierten Vektor zurück... Dem entsprechend hätte nun Track#getDirectionTo den (normierten) Richtungsvektor des Tracks angegeben, wenn zum angegebenen Endpunkt gefahren wird. Wenn dir Methode getDirectionTo schon existiert, dann muss die hier natürlich umbenannt werden.In der Methode requiredTracks(), denn getDirectionTo() normiert den Vektor doch nur?
private List<RawTrack> getRequiredTracks(RawTrack startTrack, CartesianPoint startPoint, CartesianPoint direction, long trainLength) {
RawTrack currentTrack = startTrack;
CartesianPoint position = startPoint;
List<RawTrack> requiredTracks = new ArrayList<>();
long length = trainLength;
CartesianPoint dir = direction;
while (length > 0) {
if (currentTrack == null || requiredTracks.contains(currentTrack)) {
// throw new ...("train cannot be positioned");
}
requiredTracks.add(currentTrack);
CartesianPoint passed = currentTrack.getPassedPoint(dir);
length -= position.distanceTo(passed);
if (currentTrack == startTrack) {
length--;
}
position = passed;
if (getConnection(passed, currentTrack) == null) {
// Throw exception
}
currentTrack = getConnection(passed, currentTrack);
// Bestimmt die Richtung in den der Zug gelegt wird mittels dem passedPoint
dir = currentTrack.getDirectionTo(passed);
}
}
Der ist ja das Problem Fahr mal um eine Kurve, dann fährt die Lok z. B. nach rechts, während die Waggons noch nach oben fahren. getDirectionTo liefert sozusagen die Fahrtrichtung der Waggons auf dem Gleis.Also spielt in diesem Fall der Richtungsvektor in dem der Zug fährt (drivingDirection) in diesem Fall keine Rolle
//Normieren vom Fahrtektor
public CartesianPoint getDrivingDirectionNormed(int x, int y) {
return new CartesianPoint((int)Math.signum(x), (int)Math.signum(y));
}
private Track getConnection(Point point, Track track) {
for (Track tr : edges.get(point)) {
if (!tr.equals(track)) {
return tr;
}
}
return null;
}
Wenn track das aktuelle Gleis ist, dann kann die Methode nicht das selbe Gleis zurückgeben: siehe if.Die Methode gibt das aktuelle Gleis aus und nicht das, welches sich am Anschlusspunkt befindet.
Dem entsprechend hätte nun Track#getDirectionTo den (normierten) Richtungsvektor des Tracks angegeben, wenn zum angegebenen Endpunkt gefahren wird
public Point getDirectionTo(Point passed) {
if (passed == switchedTo) {
} else {
}
}
Warum zeigt mir meine IDE dann fälschlicherweise "Method invocation 'getDrivingDirection' may produce 'NullPointerException'" an?currentTrack kann an der Stelle nicht null sein, den check kannst Du Dir sparen.
Das ist nicht fälschlicherweise, sondern ein Hinweis der IDE. Wenn Du z. B. null übergibst, bekommst Du eine NPE, wenn die Methode null zurückliefert, bekommst Du wg. equals eine NPE.Warum zeigt mir meine IDE dann fälschlicherweise "Method invocation 'getDrivingDirection' may produce 'NullPointerException'" an?