# Datenstrukturen Bewusste Wahl jeder Collection — der Dozent bewertet das laut Aufgabenstellung explizit. ## Übersicht | Verwendung | Struktur | Komplexität Lookup | |---|---|---| | Ausgänge eines Raums | `EnumMap` | O(1) | | Alle Räume der Welt | `HashMap` | O(1) | | Item-Registry (global) | `HashMap` | O(1) | | NPC-Registry (global) | `HashMap` | O(1) | | Items in einem Raum | `LinkedHashMap` | O(1) | | NPCs in einem Raum | `LinkedHashMap` | O(1) | | Spieler-Inventar | `LinkedHashMap` | O(1) | | Befehlsregistry | `HashMap` | O(1) | | NPC-Reaktionen | `HashMap` | O(1) | | Besuchte Räume (für die Karte) | `LinkedHashSet` | O(1) + Besuchsreihenfolge | | BFS-Queue (Pathfinder, MapLayout) | `ArrayDeque` | O(1) FIFO | | BFS-Pfadrekonstruktion | `LinkedList` | O(1) `addFirst` | | GUI-Eingabebrücke (EDT → Worker) | `LinkedBlockingQueue` | blockierend, unbegrenzt | ## Begründungen im Detail ### `EnumMap` für Raum-Ausgänge - **Direction** ist Enum (`NORTH`, `SOUTH`, `EAST`, `WEST`) - `EnumMap` ist array-backed, kein Hashing nötig → schneller und kompakter als `HashMap` - Iteration in Enum-Deklarationsreihenfolge (stabil) ### `HashMap` für die Welt - Lookup über `id` beim Auflösen von Exits - Reihenfolge irrelevant (keine Anzeige der gesamten Welt) - Standardwahl wenn nur Lookup gebraucht wird ### `LinkedHashMap` für Inventar & Raum-Items Zwei Anforderungen gleichzeitig: 1. **O(1) Lookup** beim `take letter` / `read letter` 2. **Stabile Anzeigereihenfolge** beim `inventory` Eine plain `HashMap` würde Punkt 2 verletzen (Items springen scheinbar zufällig zwischen Ausgaben). Eine `ArrayList` würde Punkt 1 auf O(n) drücken und Duplikat-Prüfung verlangen. Entscheidung "keine Stapel" (1 Item pro id) macht das Map-basierte Modell sauber. ### `HashMap` für Befehle - O(1)-Dispatch - Aliase durch Mehrfach-Registrierung (`put("go", goCmd); put("move", goCmd);`) - Entspricht dem expliziten Tipp aus der Aufgabenstellung - Vermeidet wachsendes `switch`-Statement ### `ArrayDeque` als BFS-Queue - `Pathfinder` (Auto-Travel `go to `) und `MapLayout` (Karten-Layout) sind beides Breitensuchen → brauchen eine **FIFO-Queue** - `ArrayDeque` ist die Standardwahl dafür: O(1) an beiden Enden, keine Node-Allokation wie bei `LinkedList`, bessere Cache-Lokalität ### `LinkedList` für die Pfadrekonstruktion Die eine Stelle, an der `LinkedList` die richtige Wahl ist (`Pathfinder`): Nach der BFS läuft man über `cameFrom` **rückwärts** vom Ziel zum Start und will den Pfad in Vorwärtsreihenfolge. `addFirst()` ist bei `LinkedList` O(1) — bei `ArrayList` wäre `add(0, x)` O(n), weil alles verschoben werden müsste. ## Bewusst NICHT gewählt | Struktur | Warum nicht | |---|---| | `ArrayList` für Inventar | O(n)-Lookup, Duplikat-Handling nötig | | `HashMap` für Inventar | Anzeige-Reihenfolge instabil | | `TreeMap` irgendwo | Keine sortierte Iteration nötig, O(log n) ohne Nutzen | | `LinkedList` als Queue | dafür ist `ArrayDeque` besser (s.o.) — als `addFirst`-Liste in der Pfadrekonstruktion aber sehr wohl genutzt | | `Vector` / `Hashtable` | Legacy, synchronisiert (nicht gebraucht), langsamer | | `Map` für Exits in Domain | Direction sollte Enum sein, nicht String | ## Threading Single-threaded: Game-Loop liest, dispatcht, schreibt — keine parallelen Mutationen. **Ausnahme:** Bei Swing-GUI läuft Input über den Event-Dispatch-Thread, der Game-Loop in einem Worker-Thread. Als Brücke dient eine `LinkedBlockingQueue` (`SwingIO`): Der `JTextField`-ActionListener (EDT) legt die Zeile ab, der Worker blockiert in `take()`. Unbegrenzt statt `ArrayBlockingQueue`, weil es keine sinnvolle Obergrenze für getippte Zeilen gibt und ein volles `offer()` Eingaben verlieren würde — siehe [architecture.md](architecture.md).