docs(readme): restructure around the two ways to run the game

The README buried the "just run it" path below the Maven section and left out
several commands the game actually supports.

- Split the quick start into Weg A (prebuilt jars, Java only, works offline) and
  Weg B (Maven wrapper: test, package, exec:java@run / @gui)
- State the Java 21 prerequisite up front, with how to check it
- Note that the console version runs headless while the GUI needs a desktop, and
  where saves/ is written
- Document the missing commands: 'go to <raum>', 'save'/'speichern', and the
  skippable tutorial
- Add the scope up front (14 rooms, 19 items, 3 NPCs, 259 tests)

All commands and links in the file were executed/resolved before committing.
This commit is contained in:
2026-07-14 12:55:19 +02:00
parent c205d1f49b
commit d7f91c2e47

View File

@@ -1,78 +1,89 @@
# Haunted Manor Textadventure
Semesterprojekt im Modul Programmierung 2 (Algorithmen und Datenstrukturen,
2. Semester). Ein textbasiertes Adventure in Java: Der Spieler navigiert durch
Räume eines Spukhauses, sammelt Gegenstände, interagiert mit NPCs und löst so
das Spiel.
Semesterprojekt im Modul Algorithmen und Datenstrukturen (2. Semester).
Ein textbasiertes Adventure in Java: Der Spieler navigiert durch die Räume eines
Spukhauses, sammelt Gegenstände, spricht mit NPCs, löst Rätsel und findet einen
Weg hinaus.
Die Spielwelt ist vollständig datengetrieben Räume, Gegenstände und NPCs
werden aus YAML-Dateien geladen, nicht im Code festverdrahtet.
Die Spielwelt ist vollständig datengetrieben Räume, Gegenstände, NPCs, Quests
und Enden werden aus YAML-Dateien geladen, nicht im Code festverdrahtet.
## Features
**Umfang:** 14 Räume, 19 Gegenstände, 3 NPCs, 259 Tests.
- **Navigation** durch beliebig viele Räume in den Himmelsrichtungen
- **Inventar** mit Aufnehmen (`take`) und Ablegen (`drop`) von Gegenständen
- **Item-Hierarchie**: einfache, lesbare (`read`) und schaltbare (`use`) Gegenstände
- **NPCs** mit Gesprächen (`talk`) und Geschenk-Reaktionen (`give`)
- **Zwei Frontends**: klassische Konsole und Swing-GUI (Bonus)
- **Datengetriebene Welt** aus YAML inkl. Referenzauflösung und Validierung beim Laden
---
## Voraussetzungen
## Schnellstart
- **Java 21+** (LTS). Gebaut wird gegen `maven.compiler.release=21`; das neueste
genutzte Sprachfeature ist `List.getFirst()` (SequencedCollection, Java 21).
Neuere JDKs (2225) funktionieren ebenfalls.
- Maven 3.9+ **oder** der mitgelieferte Maven Wrapper (`./mvnw`) damit ist
keine separate Maven-Installation nötig; der Wrapper lädt die passende
Maven-Version beim ersten Aufruf selbst herunter.
Es gibt **zwei Wege**, das Spiel zu starten. Wenn Sie nur spielen wollen, nehmen
Sie Weg A dafür wird kein Maven benötigt.
## Schnellstart ohne Maven
### Voraussetzung
Im Ordner [`release/`](release/) liegen zwei fertig gebaute, eigenständige
JARs mit allen Abhängigkeiten je eine pro Frontend. Sie brauchen nur Java 21+:
**Java 21 oder neuer** (LTS). Gebaut wird gegen `maven.compiler.release=21`;
das neueste genutzte Sprachfeature ist `List.getFirst()` (SequencedCollection,
Java 21). Neuere JDKs (2225) funktionieren ebenfalls.
Prüfen mit:
```bash
java -jar release/HauntedManor-Console.jar # Konsolen-Version (~5 MB, ohne Audio)
java -jar release/HauntedManor-GUI.jar # Swing-GUI (~17 MB, mit Musik)
java -version
```
Die Konsolen-JAR enthält weder die Musikdateien noch die OGG-Bibliotheken
der Textmodus spielt keine Musik, daher werden sie dort weggelassen.
### Weg A fertige JARs starten (ohne Maven)
## Bauen und Testen
Mit dem Wrapper (empfohlen, keine Maven-Installation nötig) unter Windows
`mvnw.cmd` statt `./mvnw`:
Im Ordner [`release/`](release/) liegen zwei eigenständige JARs, die alle
Abhängigkeiten bereits enthalten. Es wird **nur Java** gebraucht, kein Maven,
keine Internetverbindung:
```bash
./mvnw clean test # alle Tests ausführen (259 Tests)
./mvnw clean package # baut beide JARs nach release/ (Console + GUI)
java -jar release/HauntedManor-Console.jar # Konsolen-Version (~5 MB)
java -jar release/HauntedManor-GUI.jar # Swing-GUI (~17 MB)
```
Ein systemweit installiertes `mvn` funktioniert identisch (`mvn clean test` …).
- Die **Konsolen-Version** läuft in jedem Terminal, auch ohne grafische
Oberfläche.
- Die **GUI-Version** (Bonus) braucht einen Desktop und spielt zusätzlich
Hintergrundmusik. Die Konsolen-JAR enthält weder die Musikdateien noch die
OGG-Bibliotheken im Textmodus gibt es keine Musik, daher sind sie dort
weggelassen.
## Spielen
### Weg B mit Maven bauen und starten
Über die im `pom.xml` konfigurierten Run-Profile des `exec-maven-plugin`:
Der mitgelieferte **Maven Wrapper** (`./mvnw`) lädt die passende Maven-Version
beim ersten Aufruf selbst herunter eine separate Maven-Installation ist nicht
nötig. Unter Windows `mvnw.cmd` statt `./mvnw` verwenden. Ein systemweit
installiertes `mvn` funktioniert identisch.
```bash
./mvnw exec:java@run # Konsolen-Version (thb.jeanluc.adventure.App)
./mvnw exec:java@gui # Swing-GUI (thb.jeanluc.adventure.AppGui)
./mvnw clean test # alle 259 Tests ausführen
./mvnw clean package # baut beide JARs neu nach release/
./mvnw exec:java@run # Konsolen-Version starten (thb.jeanluc.adventure.App)
./mvnw exec:java@gui # Swing-GUI starten (thb.jeanluc.adventure.AppGui)
```
`./mvnw exec:java` ohne Profil startet ebenfalls die Konsolen-Version.
Alternativ direkt aus der gebauten JAR (siehe [Schnellstart](#schnellstart-ohne-maven)).
### Befehle im Spiel
> **Hinweis:** Der erste Maven-Aufruf lädt die Abhängigkeiten (Jackson, Lombok,
> JUnit, Logback) aus dem Internet. Wer offline ist, nimmt Weg A.
Befehle funktionieren auf **Englisch und Deutsch** die deutschen Beispiele der
Aufgabenstellung (`Gehe nach Norden`, `Nimm Brief`, `Lies Brief`,
`Benutze Schaufel`) laufen also direkt. Item-IDs bleiben englisch (`letter`,
`shovel`), Himmelsrichtungen verstehen beide Sprachen (`north` / `norden`).
Speicherstände und Einstellungen legt das Spiel in einem Ordner `saves/` neben
dem Arbeitsverzeichnis an, aus dem es gestartet wurde.
---
## Befehle im Spiel
Befehle funktionieren auf **Englisch und Deutsch** die deutschen Beispiele aus
der Aufgabenstellung (`Gehe nach Norden`, `Nimm Brief`, `Lies Brief`,
`Benutze Schaufel`) laufen also direkt. Gegenstands-IDs bleiben englisch
(`letter`, `shovel`), Himmelsrichtungen verstehen beide Sprachen
(`north` / `norden`).
| Befehl | Aliase | Deutsch | Wirkung |
|---|---|---|---|
| `go <richtung>` | `move`, `walk` | `gehe`, `geh` | In eine Himmelsrichtung gehen |
| `go to <raum>` | | | Automatisch zu einem bekannten Raum laufen |
| `look` | `l` | `schau`, `umsehen` | Aktuellen Raum beschreiben |
| `map` | `m` | `karte` | Karte der erkundeten Räume anzeigen |
| `quests` | `log`, `journal` | `aufgaben` | Aktive und erledigte Quests anzeigen |
@@ -85,54 +96,63 @@ Aufgabenstellung (`Gehe nach Norden`, `Nimm Brief`, `Lies Brief`,
| `examine <item>` | `x`, `inspect` | `untersuche` | Gegenstand genauer ansehen |
| `talk <npc>` | `speak` | `rede`, `sprich` | Mit einem NPC sprechen |
| `give <item> <npc>` | | `gib` | NPC einen Gegenstand geben |
| `save` | | `speichern` | Spielstand speichern |
| `help` | `?` | `hilfe` | Befehlsübersicht anzeigen |
| `quit` | `exit` | `beenden` | Spiel beenden |
| `quit` | `exit` | `beenden` | Speichern und zurück ins Hauptmenü |
Zu Beginn führt ein kurzes, überspringbares Tutorial (`skip`) durch die
wichtigsten Befehle.
---
## Wo die Aufgabenstellung umgesetzt ist
Kurzwegweiser zu den geforderten Punkten:
| Anforderung | Wo | Details |
| Anforderung | Wo im Code | Umsetzung |
|---|---|---|
| **Raum-Klasse + Navigation**, mind. 4 Räume | [`model/Room.java`](src/main/java/thb/jeanluc/adventure/model/Room.java), [`model/Direction.java`](src/main/java/thb/jeanluc/adventure/model/Direction.java) | **14 Räume**. `Room` hält direkte Referenzen auf Nachbarräume in einer `EnumMap<Direction, Room>` ein echter Objektgraph, keine String-IDs. |
| **`gehen`-Befehl** (Tipp: switch/if-else/HashMap) | [`command/CommandRegistry.java`](src/main/java/thb/jeanluc/adventure/command/CommandRegistry.java), [`command/impl/GoCommand.java`](src/main/java/thb/jeanluc/adventure/command/impl/GoCommand.java) | Dispatch über `HashMap<String, Command>` (O(1), Aliase = mehrere Keys auf dieselbe Instanz). Richtung dann O(1) per `EnumMap`-Lookup. |
| **Gegenstände + Inventar**, mind. 3 Items | [`model/Player.java`](src/main/java/thb/jeanluc/adventure/model/Player.java), [`model/item/`](src/main/java/thb/jeanluc/adventure/model/item/) | **19 Items**. Inventar = `LinkedHashMap<String, Item>`. Item-Hierarchie: `PlainItem`, `ReadableItem`, `SwitchableItem`. |
| **Aufnehmen / Ablegen / Benutzen / Lesen** | [`command/impl/`](src/main/java/thb/jeanluc/adventure/command/impl/) | `TakeCommand`, `DropCommand`, `UseCommand`, `ReadCommand` inkl. `letter` („Brief") und `shovel` („Schaufel") aus den Beispielen. |
| **Datenstrukturwahl** (bewertungsrelevant) | [`docs/data-structures.md`](docs/data-structures.md) | Begründung je Anwendungsfall + Tabelle „Bewusst NICHT gewählt". |
| **NPCs** (Bonus) | [`model/Npc.java`](src/main/java/thb/jeanluc/adventure/model/Npc.java) | 3 NPCs, die auf Spielerzustand **reagieren** (`talk`, `give`). |
| **Swing-GUI** (Bonus) | [`io/SwingIO.java`](src/main/java/thb/jeanluc/adventure/io/SwingIO.java) | `JTextField` für die Eingabe (s. Hinweis unten). |
| **Javadoc** | überall | An Klassen, Methoden und Instanzvariablen. |
| **Raum-Klasse + Navigation**, mind. 4 Räume | [`model/Room.java`](src/main/java/thb/jeanluc/adventure/model/Room.java), [`model/Direction.java`](src/main/java/thb/jeanluc/adventure/model/Direction.java) | **14 Räume.** `Room` hält direkte Referenzen auf seine Nachbarräume in einer `EnumMap<Direction, Room>` ein echter Objektgraph, keine String-IDs. |
| **`gehen`-Befehl** (Tipp: switch / if-else / HashMap) | [`command/CommandRegistry.java`](src/main/java/thb/jeanluc/adventure/command/CommandRegistry.java), [`command/impl/GoCommand.java`](src/main/java/thb/jeanluc/adventure/command/impl/GoCommand.java) | Dispatch über `HashMap<String, Command>` (O(1); Aliase = mehrere Keys auf dieselbe Instanz, statt eines wachsenden `switch`). Die Richtung danach O(1) per `EnumMap`-Lookup. |
| **Gegenstände + Inventar**, mind. 3 Items | [`model/Player.java`](src/main/java/thb/jeanluc/adventure/model/Player.java), [`model/item/`](src/main/java/thb/jeanluc/adventure/model/item/) | **19 Gegenstände.** Inventar = `LinkedHashMap<String, Item>` (O(1)-Zugriff *und* stabile Anzeigereihenfolge). Hierarchie: `PlainItem`, `ReadableItem`, `SwitchableItem`. |
| **Aufnehmen / Ablegen / Benutzen / Lesen** | [`command/impl/`](src/main/java/thb/jeanluc/adventure/command/impl/) | `TakeCommand`, `DropCommand`, `UseCommand`, `ReadCommand` inklusive `letter` („Brief") und `shovel` („Schaufel") aus den Beispielen der Aufgabenstellung. |
| **Wahl der Datenstrukturen** | [`docs/data-structures.md`](docs/data-structures.md) | Begründung je Anwendungsfall, plus Tabelle „Bewusst NICHT gewählt". |
| **NPCs** (Bonus) | [`model/Npc.java`](src/main/java/thb/jeanluc/adventure/model/Npc.java) | 3 NPCs, die auf den Spielerzustand **reagieren** (`talk`, `give`). |
| **Swing-GUI** (Bonus) | [`io/SwingIO.java`](src/main/java/thb/jeanluc/adventure/io/SwingIO.java) | `JTextField` für die Eingabe (siehe Hinweis unten). |
| **Javadoc** | gesamtes `src/main/java` | An Klassen, Methoden und Instanzvariablen. |
**Hinweis zur GUI:** Die Aufgabe nennt `JTextField` + `JTextArea`. Die Eingabe ist ein
`JTextField` wie gefordert; für die **Ausgabe** wird bewusst ein `JTextPane` statt einer
`JTextArea` verwendet. Grund: `JTextArea` kann nur unformatierten Text darstellen, während
das Spiel farbige/gestylte Ausgabe (`StyledText``StyledDocument`) rendert Raumnamen,
Items und Hinweise sind farblich unterschieden. `JTextPane` ist dafür die passende
Swing-Komponente und funktional eine Obermenge von `JTextArea`.
**Hinweis zur GUI:** Die Aufgabe nennt `JTextField` **und** `JTextArea`. Die
Eingabe ist wie gefordert ein `JTextField`. Für die **Ausgabe** wird bewusst ein
`JTextPane` statt einer `JTextArea` verwendet: `JTextArea` kann ausschließlich
unformatierten Text darstellen, das Spiel rendert aber farbig gestylte Ausgabe
(`StyledText``StyledDocument`), damit Raumnamen, Gegenstände und Hinweise
optisch unterscheidbar sind. `JTextPane` ist dafür die passende Swing-Komponente
und funktional eine Obermenge von `JTextArea`.
---
## Projektstruktur
```
Semesterprojekt/
├── src/main/java/thb/jeanluc/adventure/
│ ├── App.java - Einstiegspunkt Konsole
│ ├── AppGui.java - Einstiegspunkt Swing-GUI
│ ├── command/ - Befehlsparser, Registry + impl/ (15 Kommandos)
│ ├── game/ - Spielschleife, Engines, Light, Pathfinder, MapLayout
│ ├── io/ - GameIO-Abstraktion: ConsoleIO, SwingIO + text/ (Styling)
│ ├── loader/ - YAML-Laden: dto/, Factories, Resolver, Validator
│ ├── menu/ - Hauptmenü und Einstellungen
│ ├── model/ - Domänenmodell: Room, World, Player, Npc, item/
│ └── save/ - Speicherstände und Settings (JSON)
│ ├── App.java Einstiegspunkt Konsole
│ ├── AppGui.java Einstiegspunkt Swing-GUI
│ ├── model/ Domänenmodell: Room, Player, Npc, item/ …
│ ├── command/ Parser, Registry + impl/ (15 Kommandos)
│ ├── game/ Spielschleife, Engines, Light, Pathfinder, MapLayout
│ ├── io/ GameIO-Abstraktion: ConsoleIO, SwingIO + text/
│ ├── loader/ YAML-Laden: dto/, Factories, Resolver, Validator
│ ├── save/ Speicherstände und Einstellungen (JSON)
│ └── menu/ Hauptmenü und Einstellungen
├── src/main/resources/world/
│ ├── game.yaml - Metadaten (Titel, Startraum, Begrüßung)
│ ├── rooms.yaml - Räume mit Ausgängen, Items, NPCs
│ ├── items.yaml - Gegenstände
│ ├── npcs.yaml - NPCs und ihre Reaktionen
│ ├── quests.yaml - Quests und Stages
│ ├── endings.yaml - Spielenden
│ └── combinations.yaml - Item-Kombinationen (`use X on Y`)
── docs/ - Design- und Architekturdokumentation
│ ├── game.yaml Metadaten (Titel, Startraum, Begrüßung)
│ ├── rooms.yaml Räume mit Ausgängen, Gegenständen, NPCs
│ ├── items.yaml Gegenstände
│ ├── npcs.yaml NPCs und ihre Reaktionen
│ ├── quests.yaml Quests und ihre Stufen
│ ├── endings.yaml Spielenden
│ └── combinations.yaml Gegenstands-Kombinationen (`use X on Y`)
── src/test/java/ 259 Tests (JUnit 5 + AssertJ)
├── release/ fertig gebaute JARs (Console + GUI)
└── docs/ Design- und Architekturdokumentation
```
## Technologie-Stack
@@ -140,12 +160,12 @@ Semesterprojekt/
- **Java 21 (LTS)**
- **Jackson** (YAML) für das Laden der Spielwelt
- **Lombok** zur Reduktion von Boilerplate
- **JUnit 5 + AssertJ + Mockito** für Tests
- **JUnit 5 + AssertJ + Mockito** für die Tests
- **SLF4J + Logback** für Logging
- **Swing** für die GUI (Bonus)
## Dokumentation
Ausführliche Design- und Architekturdokumentation liegt unter
[`docs/`](docs/README.md): Package-Struktur, Datenstrukturen, Item-Modell,
YAML-Schemas, Lade-Ablauf, Befehle und NPC-Modell.
[`docs/`](docs/README.md): Package-Struktur, Wahl der Datenstrukturen,
Item-Modell, Befehle, NPC-Modell, YAML-Schemas und Lade-Ablauf.