semesterprojekt: implement full text adventure (phases 1-7)

Walking skeleton through Swing GUI: YAML-driven world (4 rooms,
4 items, 1 NPC), HashMap command dispatch with parser, three-tier
item hierarchy (readable / switchable / plain), and end-to-end
NPC give/receive flow. 67 tests green.
This commit is contained in:
2026-05-25 21:37:59 +02:00
parent 9b6528d800
commit 83643a192f
85 changed files with 4453 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
# Datenstrukturen
Bewusste Wahl jeder Collection — der Dozent bewertet das laut Aufgabenstellung explizit.
## Übersicht
| Verwendung | Struktur | Komplexität Lookup |
|---|---|---|
| Ausgänge eines Raums | `EnumMap<Direction, Room>` | O(1) |
| Alle Räume der Welt | `HashMap<String, Room>` | O(1) |
| Item-Registry (global) | `HashMap<String, Item>` | O(1) |
| NPC-Registry (global) | `HashMap<String, Npc>` | O(1) |
| Items in einem Raum | `LinkedHashMap<String, Item>` | O(1) |
| NPCs in einem Raum | `LinkedHashMap<String, Npc>` | O(1) |
| Spieler-Inventar | `LinkedHashMap<String, Item>` | O(1) |
| Befehlsregistry | `HashMap<String, Command>` | O(1) |
| NPC-Reaktionen | `HashMap<String, NpcReaction>` | O(1) |
| Eingabehistorie (optional) | `ArrayDeque<String>` | O(1) Front/Back |
## Begründungen im Detail
### `EnumMap<Direction, Room>` für Raum-Ausgänge
- **Direction** ist Enum (`NORTH`, `SOUTH`, `EAST`, `WEST`, evtl. `UP`, `DOWN`)
- `EnumMap` ist array-backed, kein Hashing nötig → schneller und kompakter als `HashMap`
- Iteration in Enum-Deklarationsreihenfolge (stabil)
### `HashMap<String, Room>` 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<String, Item>` 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<Item>` 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<String, Command>` 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<String>` für Historie (optional)
- Falls Up-Arrow in der GUI gewünscht oder Befehlsverlauf
- `ArrayDeque` ist `LinkedList` praktisch immer überlegen (bessere Cache-Lokalität, weniger Overhead)
- Beidseitige O(1)-Operationen
## Bewusst NICHT gewählt
| Struktur | Warum nicht |
|---|---|
| `ArrayList<Item>` für Inventar | O(n)-Lookup, Duplikat-Handling nötig |
| `HashMap<String, Item>` für Inventar | Anzeige-Reihenfolge instabil |
| `TreeMap` irgendwo | Keine sortierte Iteration nötig, O(log n) ohne Nutzen |
| `LinkedList` | `ArrayDeque` ist fast immer besser |
| `Vector` / `Hashtable` | Legacy, synchronisiert (nicht gebraucht), langsamer |
| `Map<String, String>` 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. Hier kommt `BlockingQueue<String>` (`ArrayBlockingQueue` reicht) als Brücke ins Spiel — siehe [architecture.md](architecture.md).