2024ft
This commit is contained in:
@@ -1,54 +1,236 @@
|
|||||||
import java.util.ArrayList;
|
package j2024.FT;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
public class AriadneIterator implements Iterator<Room>{
|
public class AriadneIterator implements Iterator<Room> {
|
||||||
private Room entry;
|
|
||||||
private Stack<Room> ariadnesThread;
|
|
||||||
private List<Room> visited;
|
|
||||||
|
|
||||||
private State currentstate;
|
private final Room entry;
|
||||||
|
private Stack<Room> ariadnesThread;
|
||||||
|
private Set<Room> visited;
|
||||||
|
private State currentState;
|
||||||
|
|
||||||
public AriadneIterator(Room entry) {
|
public AriadneIterator(Room entry) {
|
||||||
this.entry = entry;
|
this.entry = entry;
|
||||||
|
this.ariadnesThread = new Stack<>();
|
||||||
|
this.visited = new HashSet<>();
|
||||||
|
this.currentState = new Starting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Iterator interface
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
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
|
@Override
|
||||||
public Room next() {
|
public Room next() {
|
||||||
|
if (!hasNext()) {
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
}
|
||||||
|
step();
|
||||||
return ariadnesThread.peek();
|
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();
|
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<>();
|
// Konkreter Zustand: Starting
|
||||||
ariadnesThread.push(entry);
|
// ---------------------------------------------------------------
|
||||||
visited = new ArrayList<>();
|
|
||||||
visited.add(entry);
|
|
||||||
currentstate = new 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 {
|
private class Starting implements State {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void step() {
|
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 true; // Es gibt noch mindestens den Eingang zurückzugeben
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// 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() {
|
||||||
|
// Iteration beendet – nichts zu tun
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -56,17 +238,4 @@ public class AriadneIterator implements Iterator<Room>{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Accomplished implements State {
|
|
||||||
@Override
|
|
||||||
public void step() {
|
|
||||||
stepRetreating();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
return !ariadnesThread.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,24 @@
|
|||||||
|
package j2024.FT;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class CreateSmallMazeTest {
|
public class AriadneIteratorTest {
|
||||||
|
|
||||||
Room entry = CreateSmallMaze.createSmallMaze();
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSmallMaze() {
|
public void testSmallMaze() {
|
||||||
|
Room entry = SampleMaze.createSmallMaze();
|
||||||
|
|
||||||
AriadneIterator iter = new AriadneIterator(entry);
|
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("a2", iter.next().getName());
|
||||||
assertEquals("b2", iter.next().getName());
|
assertEquals("b2", iter.next().getName());
|
||||||
assertEquals("b1", iter.next().getName());
|
assertEquals("b1", iter.next().getName());
|
||||||
assertEquals("b2", iter.next().getName());
|
assertEquals("b2", iter.next().getName());
|
||||||
assertEquals("a2", 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.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class Room {
|
public class Room {
|
||||||
private String name;
|
private final String name;
|
||||||
private boolean minotaur;
|
private boolean minotaur;
|
||||||
|
|
||||||
private Set<Room> reachable;
|
private Set<Room> reachable;
|
||||||
@@ -17,12 +19,20 @@ public class Room {
|
|||||||
minotaur = v;
|
minotaur = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addReachable(Room room) {
|
public void addReachable(Room room) {
|
||||||
reachable.add(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