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:
@@ -1,78 +1,89 @@
|
|||||||
# Haunted Manor – Textadventure
|
# Haunted Manor – Textadventure
|
||||||
|
|
||||||
Semesterprojekt im Modul Programmierung 2 (Algorithmen und Datenstrukturen,
|
Semesterprojekt im Modul Algorithmen und Datenstrukturen (2. Semester).
|
||||||
2. Semester). Ein textbasiertes Adventure in Java: Der Spieler navigiert durch
|
Ein textbasiertes Adventure in Java: Der Spieler navigiert durch die Räume eines
|
||||||
Räume eines Spukhauses, sammelt Gegenstände, interagiert mit NPCs und löst so
|
Spukhauses, sammelt Gegenstände, spricht mit NPCs, löst Rätsel und findet einen
|
||||||
das Spiel.
|
Weg hinaus.
|
||||||
|
|
||||||
Die Spielwelt ist vollständig datengetrieben – Räume, Gegenstände und NPCs
|
Die Spielwelt ist vollständig datengetrieben – Räume, Gegenstände, NPCs, Quests
|
||||||
werden aus YAML-Dateien geladen, nicht im Code festverdrahtet.
|
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
|
Es gibt **zwei Wege**, das Spiel zu starten. Wenn Sie nur spielen wollen, nehmen
|
||||||
genutzte Sprachfeature ist `List.getFirst()` (SequencedCollection, Java 21).
|
Sie Weg A – dafür wird kein Maven benötigt.
|
||||||
Neuere JDKs (22–25) 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.
|
|
||||||
|
|
||||||
## Schnellstart ohne Maven
|
### Voraussetzung
|
||||||
|
|
||||||
Im Ordner [`release/`](release/) liegen zwei fertig gebaute, eigenständige
|
**Java 21 oder neuer** (LTS). Gebaut wird gegen `maven.compiler.release=21`;
|
||||||
JARs mit allen Abhängigkeiten – je eine pro Frontend. Sie brauchen nur Java 21+:
|
das neueste genutzte Sprachfeature ist `List.getFirst()` (SequencedCollection,
|
||||||
|
Java 21). Neuere JDKs (22–25) funktionieren ebenfalls.
|
||||||
|
|
||||||
|
Prüfen mit:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
java -jar release/HauntedManor-Console.jar # Konsolen-Version (~5 MB, ohne Audio)
|
java -version
|
||||||
java -jar release/HauntedManor-GUI.jar # Swing-GUI (~17 MB, mit Musik)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Die Konsolen-JAR enthält weder die Musikdateien noch die OGG-Bibliotheken –
|
### Weg A – fertige JARs starten (ohne Maven)
|
||||||
der Textmodus spielt keine Musik, daher werden sie dort weggelassen.
|
|
||||||
|
|
||||||
## Bauen und Testen
|
Im Ordner [`release/`](release/) liegen zwei eigenständige JARs, die alle
|
||||||
|
Abhängigkeiten bereits enthalten. Es wird **nur Java** gebraucht, kein Maven,
|
||||||
Mit dem Wrapper (empfohlen, keine Maven-Installation nötig) – unter Windows
|
keine Internetverbindung:
|
||||||
`mvnw.cmd` statt `./mvnw`:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./mvnw clean test # alle Tests ausführen (259 Tests)
|
java -jar release/HauntedManor-Console.jar # Konsolen-Version (~5 MB)
|
||||||
./mvnw clean package # baut beide JARs nach release/ (Console + GUI)
|
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
|
```bash
|
||||||
./mvnw exec:java@run # Konsolen-Version (thb.jeanluc.adventure.App)
|
./mvnw clean test # alle 259 Tests ausführen
|
||||||
./mvnw exec:java@gui # Swing-GUI (thb.jeanluc.adventure.AppGui)
|
./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.
|
`./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
|
Speicherstände und Einstellungen legt das Spiel in einem Ordner `saves/` neben
|
||||||
Aufgabenstellung (`Gehe nach Norden`, `Nimm Brief`, `Lies Brief`,
|
dem Arbeitsverzeichnis an, aus dem es gestartet wurde.
|
||||||
`Benutze Schaufel`) laufen also direkt. Item-IDs bleiben englisch (`letter`,
|
|
||||||
`shovel`), Himmelsrichtungen verstehen beide Sprachen (`north` / `norden`).
|
---
|
||||||
|
|
||||||
|
## 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 |
|
| Befehl | Aliase | Deutsch | Wirkung |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `go <richtung>` | `move`, `walk` | `gehe`, `geh` | In eine Himmelsrichtung gehen |
|
| `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 |
|
| `look` | `l` | `schau`, `umsehen` | Aktuellen Raum beschreiben |
|
||||||
| `map` | `m` | `karte` | Karte der erkundeten Räume anzeigen |
|
| `map` | `m` | `karte` | Karte der erkundeten Räume anzeigen |
|
||||||
| `quests` | `log`, `journal` | `aufgaben` | Aktive und erledigte Quests 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 |
|
| `examine <item>` | `x`, `inspect` | `untersuche` | Gegenstand genauer ansehen |
|
||||||
| `talk <npc>` | `speak` | `rede`, `sprich` | Mit einem NPC sprechen |
|
| `talk <npc>` | `speak` | `rede`, `sprich` | Mit einem NPC sprechen |
|
||||||
| `give <item> <npc>` | | `gib` | NPC einen Gegenstand geben |
|
| `give <item> <npc>` | | `gib` | NPC einen Gegenstand geben |
|
||||||
|
| `save` | | `speichern` | Spielstand speichern |
|
||||||
| `help` | `?` | `hilfe` | Befehlsübersicht anzeigen |
|
| `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
|
## Wo die Aufgabenstellung umgesetzt ist
|
||||||
|
|
||||||
Kurzwegweiser zu den geforderten Punkten:
|
| Anforderung | Wo im Code | Umsetzung |
|
||||||
|
|
||||||
| Anforderung | Wo | Details |
|
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **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. |
|
| **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). Richtung dann O(1) per `EnumMap`-Lookup. |
|
| **`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 Items**. Inventar = `LinkedHashMap<String, Item>`. Item-Hierarchie: `PlainItem`, `ReadableItem`, `SwitchableItem`. |
|
| **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` – inkl. `letter` („Brief") und `shovel` („Schaufel") aus den Beispielen. |
|
| **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. |
|
||||||
| **Datenstrukturwahl** (bewertungsrelevant) | [`docs/data-structures.md`](docs/data-structures.md) | Begründung je Anwendungsfall + Tabelle „Bewusst NICHT gewählt". |
|
| **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 Spielerzustand **reagieren** (`talk`, `give`). |
|
| **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 (s. Hinweis unten). |
|
| **Swing-GUI** (Bonus) | [`io/SwingIO.java`](src/main/java/thb/jeanluc/adventure/io/SwingIO.java) | `JTextField` für die Eingabe (siehe Hinweis unten). |
|
||||||
| **Javadoc** | überall | An Klassen, Methoden und Instanzvariablen. |
|
| **Javadoc** | gesamtes `src/main/java` | An Klassen, Methoden und Instanzvariablen. |
|
||||||
|
|
||||||
**Hinweis zur GUI:** Die Aufgabe nennt `JTextField` + `JTextArea`. Die Eingabe ist ein
|
**Hinweis zur GUI:** Die Aufgabe nennt `JTextField` **und** `JTextArea`. Die
|
||||||
`JTextField` wie gefordert; für die **Ausgabe** wird bewusst ein `JTextPane` statt einer
|
Eingabe ist wie gefordert ein `JTextField`. Für die **Ausgabe** wird bewusst ein
|
||||||
`JTextArea` verwendet. Grund: `JTextArea` kann nur unformatierten Text darstellen, während
|
`JTextPane` statt einer `JTextArea` verwendet: `JTextArea` kann ausschließlich
|
||||||
das Spiel farbige/gestylte Ausgabe (`StyledText` → `StyledDocument`) rendert – Raumnamen,
|
unformatierten Text darstellen, das Spiel rendert aber farbig gestylte Ausgabe
|
||||||
Items und Hinweise sind farblich unterschieden. `JTextPane` ist dafür die passende
|
(`StyledText` → `StyledDocument`), damit Raumnamen, Gegenstände und Hinweise
|
||||||
Swing-Komponente und funktional eine Obermenge von `JTextArea`.
|
optisch unterscheidbar sind. `JTextPane` ist dafür die passende Swing-Komponente
|
||||||
|
und funktional eine Obermenge von `JTextArea`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Projektstruktur
|
## Projektstruktur
|
||||||
|
|
||||||
```
|
```
|
||||||
Semesterprojekt/
|
Semesterprojekt/
|
||||||
├── src/main/java/thb/jeanluc/adventure/
|
├── src/main/java/thb/jeanluc/adventure/
|
||||||
│ ├── App.java - Einstiegspunkt Konsole
|
│ ├── App.java – Einstiegspunkt Konsole
|
||||||
│ ├── AppGui.java - Einstiegspunkt Swing-GUI
|
│ ├── AppGui.java – Einstiegspunkt Swing-GUI
|
||||||
│ ├── command/ - Befehlsparser, Registry + impl/ (15 Kommandos)
|
│ ├── model/ – Domänenmodell: Room, Player, Npc, item/ …
|
||||||
│ ├── game/ - Spielschleife, Engines, Light, Pathfinder, MapLayout
|
│ ├── command/ – Parser, Registry + impl/ (15 Kommandos)
|
||||||
│ ├── io/ - GameIO-Abstraktion: ConsoleIO, SwingIO + text/ (Styling)
|
│ ├── game/ – Spielschleife, Engines, Light, Pathfinder, MapLayout
|
||||||
│ ├── loader/ - YAML-Laden: dto/, Factories, Resolver, Validator
|
│ ├── io/ – GameIO-Abstraktion: ConsoleIO, SwingIO + text/
|
||||||
│ ├── menu/ - Hauptmenü und Einstellungen
|
│ ├── loader/ – YAML-Laden: dto/, Factories, Resolver, Validator
|
||||||
│ ├── model/ - Domänenmodell: Room, World, Player, Npc, item/
|
│ ├── save/ – Speicherstände und Einstellungen (JSON)
|
||||||
│ └── save/ - Speicherstände und Settings (JSON)
|
│ └── menu/ – Hauptmenü und Einstellungen
|
||||||
├── src/main/resources/world/
|
├── src/main/resources/world/
|
||||||
│ ├── game.yaml - Metadaten (Titel, Startraum, Begrüßung)
|
│ ├── game.yaml – Metadaten (Titel, Startraum, Begrüßung)
|
||||||
│ ├── rooms.yaml - Räume mit Ausgängen, Items, NPCs
|
│ ├── rooms.yaml – Räume mit Ausgängen, Gegenständen, NPCs
|
||||||
│ ├── items.yaml - Gegenstände
|
│ ├── items.yaml – Gegenstände
|
||||||
│ ├── npcs.yaml - NPCs und ihre Reaktionen
|
│ ├── npcs.yaml – NPCs und ihre Reaktionen
|
||||||
│ ├── quests.yaml - Quests und Stages
|
│ ├── quests.yaml – Quests und ihre Stufen
|
||||||
│ ├── endings.yaml - Spielenden
|
│ ├── endings.yaml – Spielenden
|
||||||
│ └── combinations.yaml - Item-Kombinationen (`use X on Y`)
|
│ └── combinations.yaml – Gegenstands-Kombinationen (`use X on Y`)
|
||||||
└── docs/ - Design- und Architekturdokumentation
|
├── src/test/java/ – 259 Tests (JUnit 5 + AssertJ)
|
||||||
|
├── release/ – fertig gebaute JARs (Console + GUI)
|
||||||
|
└── docs/ – Design- und Architekturdokumentation
|
||||||
```
|
```
|
||||||
|
|
||||||
## Technologie-Stack
|
## Technologie-Stack
|
||||||
@@ -140,12 +160,12 @@ Semesterprojekt/
|
|||||||
- **Java 21 (LTS)**
|
- **Java 21 (LTS)**
|
||||||
- **Jackson** (YAML) für das Laden der Spielwelt
|
- **Jackson** (YAML) für das Laden der Spielwelt
|
||||||
- **Lombok** zur Reduktion von Boilerplate
|
- **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
|
- **SLF4J + Logback** für Logging
|
||||||
- **Swing** für die GUI (Bonus)
|
- **Swing** für die GUI (Bonus)
|
||||||
|
|
||||||
## Dokumentation
|
## Dokumentation
|
||||||
|
|
||||||
Ausführliche Design- und Architekturdokumentation liegt unter
|
Ausführliche Design- und Architekturdokumentation liegt unter
|
||||||
[`docs/`](docs/README.md): Package-Struktur, Datenstrukturen, Item-Modell,
|
[`docs/`](docs/README.md): Package-Struktur, Wahl der Datenstrukturen,
|
||||||
YAML-Schemas, Lade-Ablauf, Befehle und NPC-Modell.
|
Item-Modell, Befehle, NPC-Modell, YAML-Schemas und Lade-Ablauf.
|
||||||
|
|||||||
Reference in New Issue
Block a user