semesterprojekt: implement full text adventure (phases 1-7)

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.
This commit is contained in:
2026-05-25 21:37:59 +02:00
parent 9b6528d800
commit 83643a192f
85 changed files with 4453 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
package thb.jeanluc.adventure.game;
import lombok.RequiredArgsConstructor;
import thb.jeanluc.adventure.command.Command;
import thb.jeanluc.adventure.command.CommandParser;
import thb.jeanluc.adventure.command.CommandRegistry;
import thb.jeanluc.adventure.command.ParsedCommand;
import java.util.Optional;
/**
* The main game loop. Reads a line, parses it, dispatches the matching
* command, and writes the result — until {@link #stop()} flips the
* {@link #running} flag (typically by the quit command or EOF on input).
*/
@RequiredArgsConstructor
public class Game {
/** Game context shared with every command. */
private final GameContext ctx;
/** Command lookup table. */
private final CommandRegistry registry;
/** Tokenising parser for player input. */
private final CommandParser parser;
/** Loop flag. Flipped to false by {@link #stop()}. */
private boolean running = true;
/**
* Runs the loop until {@link #stop()} is called or input is exhausted.
*/
public void run() {
while (running) {
String input = ctx.getIo().readLine();
if (input == null) {
break;
}
ParsedCommand parsed = parser.parse(input);
if (parsed.verb().isEmpty()) {
continue;
}
Optional<Command> cmd = registry.find(parsed.verb());
if (cmd.isEmpty()) {
ctx.getIo().write("I don't understand '" + parsed.verb() + "'. Type 'help'.");
} else {
cmd.get().execute(ctx, parsed.args());
}
}
}
/**
* Signals the loop to terminate after the current iteration.
*/
public void stop() {
running = false;
}
}

View File

@@ -0,0 +1,26 @@
package thb.jeanluc.adventure.game;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import thb.jeanluc.adventure.io.GameIO;
import thb.jeanluc.adventure.model.Player;
import thb.jeanluc.adventure.model.World;
/**
* Bundle of everything a command needs to do its work: the world, the
* player, and the IO channel. Passing this single object keeps command
* signatures small and consistent.
*/
@Getter
@RequiredArgsConstructor
public class GameContext {
/** Loaded world (rooms, items, npcs). */
private final World world;
/** The player avatar. */
private final Player player;
/** IO channel for reading input and writing output. */
private final GameIO io;
}