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.
3.1 KiB
3.1 KiB
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) EnumMapist array-backed, kein Hashing nötig → schneller und kompakter alsHashMap- Iteration in Enum-Deklarationsreihenfolge (stabil)
HashMap<String, Room> für die Welt
- Lookup über
idbeim 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:
- O(1) Lookup beim
take letter/read letter - 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
ArrayDequeistLinkedListpraktisch 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.