2024ft
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
19
src/j2024/FT/SampleMaze.java
Normal file
19
src/j2024/FT/SampleMaze.java
Normal 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
6
src/j2024/FT/State.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package j2024.FT;
|
||||
|
||||
public interface State {
|
||||
public void step();
|
||||
public boolean hasNext();
|
||||
}
|
||||
Reference in New Issue
Block a user