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.
5.1 KiB
5.1 KiB
Implementierungsstand & Reihenfolge
Stand: alle Phasen 1–7 implementiert, 67 Tests grün, End-to-End-Smoke-Test des Walking-Skeletons + YAML-Load erfolgreich.
Phasen-Überblick
flowchart TD
P1["Phase 1<br/>Domain-Fundament"]
P2["Phase 2<br/>Command-Schicht"]
P3["Phase 3<br/>Walking Skeleton<br/>(Konsole + handgebaute Welt)"]
P4["Phase 4<br/>YAML-Loading + Validator"]
P5["Phase 5<br/>Restliche Commands"]
P6["Phase 6<br/>NPCs end-to-end"]
P7["Phase 7<br/>Swing-GUI (Bonus)"]
P1 --> P2 --> P3 --> P4 --> P5 --> P6 --> P7
Checkliste Phase 1: Domain
Direction(model.Direction)Room(model.Room)Itemabstract (model.item.Item) mitabstract use(GameContext)Npc(model.Npc) inklusiveshell()-Factory undputReaction()NpcReaction(model.NpcReaction)GameIOinterface (io.GameIO)Player(model.Player)World(model.World)GameContext(game.GameContext)ReadableItem(model.item.ReadableItem)SwitchableItem(model.item.SwitchableItem)PlainItem(model.item.PlainItem)
Checkliste Phase 2: Commands
Commandinterface (command.Command)ParsedCommand(record)CommandRegistry(command.CommandRegistry)CommandParser(command.CommandParser) mit Filler-WordsLookCommandGoCommandInventoryCommand
Checkliste Phase 3: Walking Skeleton
ConsoleIOGame(Loop)App.main(lädt sofort über YAML; der Walking-Skeleton-Zustand mit hartkodierter Welt wurde übersprungen, weil YAML-Load und Loop schon zusammen funktionieren)- Probelauf:
look,go north,inventory(sieheGameTest,LookCommandTest)
Checkliste Phase 4: YAML-Loading
- DTOs:
GameDto,ItemDto,RoomDto,NpcDto,ReactionDto - Test-Fixtures unter
src/test/resources/world/ WorldLoader(Happy-Path)ReferenceResolverWorldValidator(eine Validierungsregel pro Test)- Echte Welt-YAMLs unter
src/main/resources/world/ App.mainläuft direkt gegen YAML-Load
Checkliste Phase 5: Restliche Commands
TakeCommandDropCommandUseCommandReadCommandExamineCommandHelpCommandQuitCommand
Checkliste Phase 6: NPCs
Npcvoll ausgebaut (greeting, reactions)NpcReactionTalkCommandGiveCommand- NPCs in
WorldLoaderintegriert - End-to-End-Test: Lampe geben → Schlüssel bekommen (
TalkGiveCommandTest)
Checkliste Phase 7: Swing-GUI
SwingIOmitLinkedBlockingQueue-BrückeAppGui.main- Game-Loop in Worker-Thread
Build & Run
mvn test # 67 Tests
mvn -DskipTests exec:java -Dexec.mainClass=thb.jeanluc.adventure.App # Konsole
mvn -DskipTests exec:java -Dexec.mainClass=thb.jeanluc.adventure.AppGui # Swing
Festgelegte Designentscheidungen
Nicht mehr offen, nicht nochmal diskutieren:
| Entscheidung | Wert |
|---|---|
| Item-Hierarchie | abstract Item + ReadableItem/SwitchableItem/PlainItem |
| Item-Package | model.item (Subpackage) |
| Switchable-State-Typ | boolean (kein Enum) |
| Switchable-Felder | nur state (Builder mappt YAML initialState); kein separates initialState-Feld am Domain-Objekt |
| use-Targets | argless use X, kein use X on Y |
| Item kennt Standort | nein, „dumme" Items |
| Hidden Items | nein |
| State→Raum-Beschreibung | nein im MVP |
| Room.description | final, immutable |
| Room.describe() | nicht auf Room, im LookCommand |
| Room.equals/hashCode | nicht überschreiben, Identity |
| Room-NPCs-Feld | von Anfang an drin |
| Bidirektionale Exits | manuell, kein Auto-Spiegeln |
| GameContext-Inhalt | minimal: World + Player + GameIO |
| IDs | lowercase snake_case slugs, kein UUID |
| ID-Regex | ^[a-z][a-z0-9_]*$ |
| YAML-Aufteilung | game.yaml, items.yaml, rooms.yaml, npcs.yaml |
| DTO ↔ Domain | getrennt, Resolver-Phase löst String-IDs zu Referenzen auf |
| Item-Type-Discriminator | YAML-Feld `type: plain |
| Codebase-Sprache | Englisch (Identifier, YAML, User-Strings) |
| Doku-Sprache | Deutsch (Prose), Englisch (Code-Beispiele) |
| Diagramme | Mermaid |
| Lombok-Inheritance | @SuperBuilder |
@Data |
vermeiden, einzelne Annotations bevorzugen |
| Quit-Wiring | QuitCommand.bind(Game) nach Registry-Aufbau |
| Help-Quelle | HelpCommand zieht aus CommandRegistry.distinctCommands() |
| GameIO-Methodennamen | readLine() / write(String) (Java-üblich, konsistent) |
| Lombok-Version | 1.18.42 (1.18.36 ist nicht Java-26-kompatibel) |
Offen / nicht im MVP
- Win-Condition: Spiel endet nur per
quit. Optionale Erweiterung: Bedingung ingame.yaml(winRoom,requiredItem). - Bedingte NPC-Reaktionen, NPC-Memory, Quests — bewusst ausgelassen (siehe
npcs.md). - Item-Aliases (z.B.
lamp↔oil_lamp) — YAGNI bis konkreter Bedarf. - Eingabehistorie in der GUI —
ArrayDequeist vorgesehen, nicht umgesetzt.