This commit is contained in:
2026-05-12 15:50:32 +02:00
parent 14702200e9
commit 05f883fdf1
6 changed files with 249 additions and 60 deletions

View File

@@ -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<Room>{
private Room entry;
private Stack<Room> ariadnesThread;
private List<Room> visited;
public class AriadneIterator implements Iterator<Room> {
private State currentstate;
private final Room entry;
private Stack<Room> ariadnesThread;
private Set<Room> 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;
}
}
}
}

View File

@@ -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());
}
}
}

View File

@@ -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;
}
}

View File

@@ -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<Room> 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<Room> getReachable() {
return reachable;
}
}

View File

@@ -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;
}
}

6
src/j2024/FT/State.java Normal file
View File

@@ -0,0 +1,6 @@
package j2024.FT;
public interface State {
public void step();
public boolean hasNext();
}