From 73fc6eab68e27f9c3791ee8970798856664b0743 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Tue, 14 Jul 2026 12:38:45 +0200 Subject: [PATCH] feat(command): accept German command and direction aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The assignment's examples are German ("Gehe nach Norden", "Nimm Brief", "Lies Brief", "Benutze Schaufel") but every verb was English-only, so none of them parsed. - Register German aliases alongside the English ones (gehe, nimm, lies, benutze, lege, gib, rede, schau, karte, inventar, hilfe, beenden) - Direction.fromString accepts norden/sueden/süden/osten/westen and the n/s/e/w shorthands; YAML exits keep the canonical English names - Treat "nach", "den", "die", "das" as filler words so "Gehe nach Norden" parses --- .../main/java/thb/jeanluc/adventure/App.java | 53 ++++++++++++------- .../adventure/command/CommandParser.java | 3 +- .../jeanluc/adventure/model/Direction.java | 35 +++++++++++- .../adventure/command/GermanAliasTest.java | 47 ++++++++++++++++ 4 files changed, 118 insertions(+), 20 deletions(-) create mode 100644 Semesterprojekt/src/test/java/thb/jeanluc/adventure/command/GermanAliasTest.java diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/App.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/App.java index 2cf6312..3c509ab 100644 --- a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/App.java +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/App.java @@ -47,10 +47,15 @@ import java.util.List; @Slf4j public final class App { + /** Utility class; not instantiable. */ private App() { } - /** Standard JVM entry point. @param args ignored */ + /** + * Standard JVM entry point. + * + * @param args ignored + */ public static void main(String[] args) { GameIO io = new ConsoleIO(); try { @@ -62,12 +67,22 @@ public final class App { } } - /** Runs the menu shell on the given IO until the player quits. */ + /** + * Runs the menu shell on the given IO until the player quits. + * + * @param io frontend the menu and the game are rendered on + */ public static void run(GameIO io) { run(io, new SaveService(), new SettingsStore()); } - /** Runs the menu shell with injectable persistence (for testing). */ + /** + * Runs the menu shell with injectable persistence (for testing). + * + * @param io frontend the menu and the game are rendered on + * @param saves save-slot backend + * @param settingsStore settings backend + */ static void run(GameIO io, SaveService saves, SettingsStore settingsStore) { Settings settings = settingsStore.load(); SettingsMenu.apply(settings, io); @@ -112,27 +127,29 @@ public final class App { } }); + // German aliases mirror the examples in the assignment ("Gehe nach + // Norden", "Nimm Brief", "Lies Brief", "Benutze Schaufel"). CommandRegistry registry = new CommandRegistry(); - registry.register(new GoCommand(), "go", "move", "walk"); - registry.register(new LookCommand(), "look", "l"); - registry.register(new InventoryCommand(), "inventory", "inv", "i"); - registry.register(new TakeCommand(), "take", "pick", "get"); - registry.register(new DropCommand(), "drop", "put"); - registry.register(new UseCommand(), "use"); - registry.register(new ReadCommand(), "read"); - registry.register(new ExamineCommand(), "examine", "x", "inspect"); - registry.register(new MapCommand(), "map", "m"); - registry.register(new QuestsCommand(), "quests", "log", "journal"); - registry.register(new TalkCommand(), "talk", "speak"); - registry.register(new GiveCommand(), "give"); - registry.register(new SaveCommand(saves), "save"); + registry.register(new GoCommand(), "go", "move", "walk", "gehe", "geh"); + registry.register(new LookCommand(), "look", "l", "umsehen", "schau"); + registry.register(new InventoryCommand(), "inventory", "inv", "i", "inventar"); + registry.register(new TakeCommand(), "take", "pick", "get", "nimm", "nehme"); + registry.register(new DropCommand(), "drop", "put", "lege", "ablegen"); + registry.register(new UseCommand(), "use", "benutze", "benutz"); + registry.register(new ReadCommand(), "read", "lies", "lese"); + registry.register(new ExamineCommand(), "examine", "x", "inspect", "untersuche"); + registry.register(new MapCommand(), "map", "m", "karte"); + registry.register(new QuestsCommand(), "quests", "log", "journal", "aufgaben"); + registry.register(new TalkCommand(), "talk", "speak", "rede", "sprich"); + registry.register(new GiveCommand(), "give", "gib"); + registry.register(new SaveCommand(saves), "save", "speichern"); Game game = new Game(ctx, registry, new CommandParser()); MenuCommand menu = new MenuCommand(saves); menu.bind(game); - registry.register(menu, "menu", "quit", "exit"); - registry.register(new HelpCommand(registry), "help", "?"); + registry.register(menu, "menu", "quit", "exit", "beenden"); + registry.register(new HelpCommand(registry), "help", "?", "hilfe"); if (withTutorial) { Tutorial tutorial = new TutorialLoader().load(); diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/command/CommandParser.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/command/CommandParser.java index 8e931eb..c70e2fd 100644 --- a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/command/CommandParser.java +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/command/CommandParser.java @@ -16,7 +16,8 @@ public class CommandParser { * small — when adding more, watch out for words that might be valid * item ids ({@code key}, {@code lamp}, etc.). */ - private static final Set FILLERS = Set.of("to", "with", "at", "the", "a", "an", "on"); + private static final Set FILLERS = + Set.of("to", "with", "at", "the", "a", "an", "on", "nach", "den", "die", "das"); /** * Parses an input line into a verb and its arguments. diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/model/Direction.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/model/Direction.java index d03d703..c61157b 100644 --- a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/model/Direction.java +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/model/Direction.java @@ -1,5 +1,7 @@ package thb.jeanluc.adventure.model; +import java.util.Map; + /** * Compass directions used for navigating between rooms. * Each direction has an opposite, which is used when describing @@ -7,9 +9,13 @@ package thb.jeanluc.adventure.model; * entering the next room from the SOUTH). */ public enum Direction { + /** Towards the top of the map; opposite of {@link #SOUTH}. */ NORTH, + /** Towards the bottom of the map; opposite of {@link #NORTH}. */ SOUTH, + /** Towards the right of the map; opposite of {@link #WEST}. */ EAST, + /** Towards the left of the map; opposite of {@link #EAST}. */ WEST; /** @@ -38,13 +44,40 @@ public enum Direction { if (s == null) { throw new IllegalArgumentException("Direction must not be null"); } + String key = s.trim().toLowerCase(); + Direction alias = ALIASES.get(key); + if (alias != null) { + return alias; + } try { - return Direction.valueOf(s.trim().toUpperCase()); + return Direction.valueOf(key.toUpperCase()); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Unknown direction: '" + s + "'"); } } + /** + * Alternative spellings accepted from player input: single-letter + * shorthands and the German direction names used in the assignment's + * examples ("Gehe nach Norden"). YAML exits still use the canonical + * English names. + */ + private static final Map ALIASES = Map.ofEntries( + Map.entry("n", NORTH), + Map.entry("s", SOUTH), + Map.entry("e", EAST), + Map.entry("w", WEST), + Map.entry("norden", NORTH), + Map.entry("sueden", SOUTH), + Map.entry("süden", SOUTH), + Map.entry("osten", EAST), + Map.entry("westen", WEST), + Map.entry("nord", NORTH), + Map.entry("sued", SOUTH), + Map.entry("süd", SOUTH), + Map.entry("ost", EAST), + Map.entry("west", WEST)); + /** * Returns the human-readable lowercase label, suitable for display * to the player (e.g. "north"). Intentionally not a toString override diff --git a/Semesterprojekt/src/test/java/thb/jeanluc/adventure/command/GermanAliasTest.java b/Semesterprojekt/src/test/java/thb/jeanluc/adventure/command/GermanAliasTest.java new file mode 100644 index 0000000..bb8e9a7 --- /dev/null +++ b/Semesterprojekt/src/test/java/thb/jeanluc/adventure/command/GermanAliasTest.java @@ -0,0 +1,47 @@ +package thb.jeanluc.adventure.command; + +import org.junit.jupiter.api.Test; +import thb.jeanluc.adventure.model.Direction; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * The assignment's examples are German ("Gehe nach Norden", "Nimm Brief"), so + * those inputs must parse. English stays the canonical form used in YAML. + */ +class GermanAliasTest { + + private final CommandParser parser = new CommandParser(); + + @Test + void parse_gehNachNorden_yieldsGoNorth() { + ParsedCommand c = parser.parse("Gehe nach Norden"); + + assertThat(c.verb()).isEqualTo("gehe"); + assertThat(c.args()).containsExactly("norden"); + assertThat(Direction.fromString(c.args().getFirst())).isEqualTo(Direction.NORTH); + } + + @Test + void parse_nimmBrief_yieldsTakeWithItemArg() { + ParsedCommand c = parser.parse("Nimm Brief"); + + assertThat(c.verb()).isEqualTo("nimm"); + assertThat(c.args()).containsExactly("brief"); + } + + @Test + void fromString_withGermanDirectionNames_resolves() { + assertThat(Direction.fromString("norden")).isEqualTo(Direction.NORTH); + assertThat(Direction.fromString("sueden")).isEqualTo(Direction.SOUTH); + assertThat(Direction.fromString("süden")).isEqualTo(Direction.SOUTH); + assertThat(Direction.fromString("osten")).isEqualTo(Direction.EAST); + assertThat(Direction.fromString("westen")).isEqualTo(Direction.WEST); + } + + @Test + void fromString_withEnglishNames_stillResolves() { + assertThat(Direction.fromString("north")).isEqualTo(Direction.NORTH); + assertThat(Direction.fromString("n")).isEqualTo(Direction.NORTH); + } +}