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.
74 lines
3.1 KiB
Markdown
74 lines
3.1 KiB
Markdown
# 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).
|