diff --git a/src/j2024/FT/AriadneIterator.java b/src/j2024/FT/AriadneIterator.java index e12e23b..88e409f 100644 --- a/src/j2024/FT/AriadneIterator.java +++ b/src/j2024/FT/AriadneIterator.java @@ -1,72 +1,241 @@ -import java.util.ArrayList; +package j2024.FT; + +import java.util.HashSet; import java.util.Iterator; -import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; import java.util.Stack; -public class AriadneIterator implements Iterator{ - private Room entry; - private Stack ariadnesThread; - private List visited; +public class AriadneIterator implements Iterator { - private State currentstate; + private final Room entry; + private Stack ariadnesThread; + private Set visited; + private State currentState; public AriadneIterator(Room entry) { this.entry = entry; + this.ariadnesThread = new Stack<>(); + this.visited = new HashSet<>(); + this.currentState = new Starting(); } - + // --------------------------------------------------------------- + // Iterator interface + // --------------------------------------------------------------- + @Override public boolean hasNext() { - return cs.hasNext(); + return currentState.hasNext(); } + /** + * Laut Spezifikation: ruft zuerst step() auf, + * gibt dann die aktuelle Position (letzter Eintrag in ariadnesThread) zurück. + */ @Override public Room next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + step(); return ariadnesThread.peek(); } - public void stepRetreating() { + // --------------------------------------------------------------- + // Private Hilfsmethoden (werden von den Zuständen genutzt) + // --------------------------------------------------------------- + + /** + * Delegiert step() an den aktuellen Zustand. + */ + private void step() { + currentState.step(); + } + + /** + * Theseus betritt das Labyrinth am Eingang: + * Eingang auf den Faden legen und als besucht markieren. + * Achtung: currentState wird hier NICHT verändert – das obliegt dem Starting-Zustand. + */ + private void init() { + ariadnesThread.push(entry); + visited.add(entry); + } + + /** + * Liefert true, wenn Theseus den Raum mit dem Minotaurus erreicht hat. + */ + private boolean foundMinotaur() { + return ariadnesThread.peek().hasMinotaur(); + } + + /** + * Tiefensuche (depth-first): Betritt den ersten noch nicht besuchten Nachbarn. + * Gibt es keinen solchen Nachbarn (Sackgasse), wird per Backtracking ein Schritt + * zurückgegangen (pop), ohne einen neuen Raum zu betreten. + * + * Hinweis: next() gibt anschließend ariadnesThread.peek() zurück, + * also entweder den neu betretenen Raum oder den Raum nach dem Backtrack. + */ + private void seekingStep() { + Room current = ariadnesThread.peek(); + for (Room neighbor : current.getReachable()) { + if (!visited.contains(neighbor)) { + // Unbesuchten Nachbarn betreten + ariadnesThread.push(neighbor); + visited.add(neighbor); + return; + } + } + // Sackgasse → Backtracking: einen Schritt zurück + retreatingStep(); + } + + /** + * Theseus geht entlang des Ariadnefadens einen Schritt zurück. + */ + private void retreatingStep() { ariadnesThread.pop(); } - - public boolean hasMinotaur() { - return ariadnesThread.peek().getMinotaur(); + + /** + * Liefert den nächsten noch nicht besuchten Nachbarn des aktuellen Raums, + * oder null wenn keiner existiert. + */ + private Room nextForward() { + Room current = ariadnesThread.peek(); + for (Room neighbor : current.getReachable()) { + if (!visited.contains(neighbor)) { + return neighbor; + } + } + return null; } - public void step() { - currentstate.step(); + // --------------------------------------------------------------- + // State Pattern – Interface + // --------------------------------------------------------------- + + /** + * Das Interface wird von AriadneIterator intern definiert. + * (Laut Aufgabe muss der Code für das Interface nicht hingeschrieben werden – + * hier dennoch vollständig angegeben.) + */ + private interface State { + void step(); + boolean hasNext(); } - public void init() { - ariadnesThread = new Stack<>(); - ariadnesThread.push(entry); - visited = new ArrayList<>(); - visited.add(entry); - currentstate = new Starting(); - } + // --------------------------------------------------------------- + // Konkreter Zustand: Starting + // --------------------------------------------------------------- + /** + * Startzustand: Theseus hat das Labyrinth noch nicht betreten. + * Beim ersten step()-Aufruf wird init() aufgerufen und in den + * nächsten Zustand gewechselt. + */ private class Starting implements State { + @Override public void step() { - init(); + init(); // Eingang betreten, Faden anbinden + if (foundMinotaur()) { + // Minotaurus steht direkt am Eingang + currentState = new MissionAccomplished(); + } else { + currentState = new SeekingMinotaur(); + } + } + + /** + * Die Iteration hat noch nicht begonnen → es gibt noch Elemente. + */ + @Override + public boolean hasNext() { + return true; + } + } + + // --------------------------------------------------------------- + // Konkreter Zustand: SeekingMinotaur + // --------------------------------------------------------------- + + /** + * Suchzustand: Theseus durchsucht das Labyrinth per Tiefensuche. + * Dieser Zustand muss laut Aufgabe NICHT vollständig realisiert werden, + * wird hier aber der Vollständigkeit halber angegeben. + */ + private class SeekingMinotaur implements State { + + @Override + public void step() { + seekingStep(); + // Nach dem Schritt prüfen, ob Minotaurus gefunden wurde + if (!ariadnesThread.empty() && foundMinotaur()) { + currentState = new MissionAccomplished(); + } + } + + /** + * Solange Theseus sucht, gibt es immer noch weitere Elemente + * (das Labyrinth hat garantiert einen Weg zum Minotaurus). + */ + @Override + public boolean hasNext() { + return true; + } + } + + // --------------------------------------------------------------- + // Konkreter Zustand: MissionAccomplished + // --------------------------------------------------------------- + + /** + * Rückweg-Zustand: Der Minotaurus wurde besiegt; Theseus folgt dem + * Ariadnefaden zurück zum Eingang. + * + * Übergang zu Finished: Sobald step() den Ariadnefaden auf den alleinigen + * Eingangsraum reduziert hat, wechselt der Zustand auf Finished – + * next() gibt dann noch den Eingang zurück (peek), danach ist + * hasNext() == false. + */ + private class MissionAccomplished implements State { + + @Override + public void step() { + retreatingStep(); + // Sind wir wieder am Eingang angekommen? + if (ariadnesThread.size() == 1 && ariadnesThread.peek() == entry) { + currentState = new Finished(); + } } @Override public boolean hasNext() { - return false; + return true; // Es gibt noch mindestens den Eingang zurückzugeben } } - private class Accomplished implements State { + // --------------------------------------------------------------- + // Konkreter Zustand: Finished + // --------------------------------------------------------------- + + /** + * Endzustand: Theseus ist wieder am Eingang, die Iteration ist abgeschlossen. + * hasNext() liefert false; step() ist eine No-Op. + */ + private class Finished implements State { + @Override public void step() { - stepRetreating(); + // Iteration beendet – nichts zu tun } + @Override public boolean hasNext() { - return !ariadnesThread.empty(); + return false; } } - - -} +} \ No newline at end of file diff --git a/src/j2024/FT/CreateSmallMazeTest.java b/src/j2024/FT/AriadneIteratorTest.java similarity index 67% rename from src/j2024/FT/CreateSmallMazeTest.java rename to src/j2024/FT/AriadneIteratorTest.java index d4e34dd..e111852 100644 --- a/src/j2024/FT/CreateSmallMazeTest.java +++ b/src/j2024/FT/AriadneIteratorTest.java @@ -1,23 +1,24 @@ +package j2024.FT; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import org.junit.Test; -public class CreateSmallMazeTest { - - Room entry = CreateSmallMaze.createSmallMaze(); +public class AriadneIteratorTest { @Test public void testSmallMaze() { + Room entry = SampleMaze.createSmallMaze(); + AriadneIterator iter = new AriadneIterator(entry); - // Erstes next ruft nur init() auf sodass wir nun mit dem Iterator arbeiten können - iter.next(); - - assertEquals("a2", iter.next().getName()); assertEquals("b2", iter.next().getName()); assertEquals("b1", iter.next().getName()); assertEquals("b2", iter.next().getName()); assertEquals("a2", iter.next().getName()); + + assertFalse(iter.hasNext()); } -} +} \ No newline at end of file diff --git a/src/j2024/FT/CreateSmallMaze.java b/src/j2024/FT/CreateSmallMaze.java deleted file mode 100644 index 7e609cd..0000000 --- a/src/j2024/FT/CreateSmallMaze.java +++ /dev/null @@ -1,16 +0,0 @@ -public class CreateSmallMaze { - - - public static Room createSmallMaze() { - Room a = new Room("a2"); - Room b = new Room("b2"); - b.addReachable(a); - a = new Room("b1"); - a.setMinotaur(true); - a.addReachable(b); - b = new Room("a1"); - b.addReachable(a); - - return b; - } -} diff --git a/src/j2024/FT/Room.java b/src/j2024/FT/Room.java index ee6ea7d..47ab12c 100644 --- a/src/j2024/FT/Room.java +++ b/src/j2024/FT/Room.java @@ -1,8 +1,10 @@ +package j2024.FT; + import java.util.HashSet; import java.util.Set; public class Room { - private String name; + private final String name; private boolean minotaur; private Set reachable; @@ -17,12 +19,20 @@ public class Room { minotaur = v; } - public void setName(String name) { - this.name = name; - } - public void addReachable(Room room) { reachable.add(room); - room.addReachable(this); + room.getReachable().add(this); + } + + public String getName() { + return name; + } + + public boolean hasMinotaur() { + return minotaur; + } + + public Set getReachable() { + return reachable; } } diff --git a/src/j2024/FT/SampleMaze.java b/src/j2024/FT/SampleMaze.java new file mode 100644 index 0000000..e5d2d88 --- /dev/null +++ b/src/j2024/FT/SampleMaze.java @@ -0,0 +1,19 @@ +package j2024.FT; + +public class SampleMaze { + + public static Room createSmallMaze() { + Room a1 = new Room("a1"); + Room b1 = new Room("b1"); + Room a2 = new Room("a2"); + Room b2 = new Room("b2"); + + b1.setMinotaur(true); + + a2.addReachable(b2); + b2.addReachable(b1); + b1.addReachable(a1); + + return a2; + } +} \ No newline at end of file diff --git a/src/j2024/FT/State.java b/src/j2024/FT/State.java new file mode 100644 index 0000000..a6ac363 --- /dev/null +++ b/src/j2024/FT/State.java @@ -0,0 +1,6 @@ +package j2024.FT; + +public interface State { + public void step(); + public boolean hasNext(); +}