feat(io,command): map command + GameIO setMap/showMap, console ASCII

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 21:02:17 +02:00
parent 9ce939167c
commit fcf8083b7c
5 changed files with 87 additions and 0 deletions

View File

@@ -10,6 +10,7 @@ import thb.jeanluc.adventure.command.impl.GoCommand;
import thb.jeanluc.adventure.command.impl.HelpCommand;
import thb.jeanluc.adventure.command.impl.InventoryCommand;
import thb.jeanluc.adventure.command.impl.LookCommand;
import thb.jeanluc.adventure.command.impl.MapCommand;
import thb.jeanluc.adventure.command.impl.QuitCommand;
import thb.jeanluc.adventure.command.impl.ReadCommand;
import thb.jeanluc.adventure.command.impl.TakeCommand;
@@ -68,6 +69,7 @@ public final class App {
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 TalkCommand(), "talk", "speak");
registry.register(new GiveCommand(), "give");
registry.register(new HelpCommand(registry), "help", "?");

View File

@@ -0,0 +1,26 @@
package thb.jeanluc.adventure.command.impl;
import thb.jeanluc.adventure.command.Command;
import thb.jeanluc.adventure.game.GameContext;
import thb.jeanluc.adventure.io.text.MapView;
import thb.jeanluc.adventure.map.MapLayout;
import java.util.List;
/** Shows the fog-of-war map of explored rooms. Usage: {@code map}. */
public class MapCommand implements Command {
@Override
public void execute(GameContext ctx, List<String> args) {
MapView view = MapLayout.compute(
ctx.getWorld(),
ctx.getPlayer().getVisitedRoomIds(),
ctx.getPlayer().getCurrentRoom());
ctx.getIo().showMap(view);
}
@Override
public String help() {
return "map - show the map of explored rooms";
}
}

View File

@@ -1,6 +1,8 @@
package thb.jeanluc.adventure.io;
import thb.jeanluc.adventure.io.text.AsciiMap;
import thb.jeanluc.adventure.io.text.Hud;
import thb.jeanluc.adventure.io.text.MapView;
import thb.jeanluc.adventure.io.text.RoomView;
import thb.jeanluc.adventure.io.text.Span;
import thb.jeanluc.adventure.io.text.Style;
@@ -100,6 +102,11 @@ public class ConsoleIO implements GameIO {
out.println(paint(Style.DIM, line));
}
@Override
public void showMap(MapView view) {
print(AsciiMap.render(view, glyphs != GlyphMode.ASCII));
}
private String section(String label, List<String> xs, Style st) {
StringBuilder sb = new StringBuilder(" ").append(paint(Style.DIM, label)).append(" ");
for (int i = 0; i < xs.size(); i++) {

View File

@@ -1,6 +1,8 @@
package thb.jeanluc.adventure.io;
import thb.jeanluc.adventure.io.text.AsciiMap;
import thb.jeanluc.adventure.io.text.Hud;
import thb.jeanluc.adventure.io.text.MapView;
import thb.jeanluc.adventure.io.text.Renderings;
import thb.jeanluc.adventure.io.text.RoomView;
import thb.jeanluc.adventure.io.text.StyledText;
@@ -32,4 +34,14 @@ public interface GameIO {
default void setHud(Hud hud) {
// no-op
}
/** Per-turn push of the current map. GUI repaints its panel; console ignores. */
default void setMap(MapView view) {
// no-op
}
/** On-demand map (the 'map' command). Default renders ASCII (Unicode frames). */
default void showMap(MapView view) {
print(AsciiMap.render(view, true));
}
}

View File

@@ -0,0 +1,40 @@
package thb.jeanluc.adventure.command.impl;
import org.junit.jupiter.api.Test;
import thb.jeanluc.adventure.game.GameContext;
import thb.jeanluc.adventure.io.TestIO;
import thb.jeanluc.adventure.model.Direction;
import thb.jeanluc.adventure.model.Player;
import thb.jeanluc.adventure.model.Room;
import thb.jeanluc.adventure.model.World;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
class MapCommandTest {
@Test
void map_showsVisitedRoomAndKnownNeighbour() {
Room kitchen = new Room("kitchen", "Kitchen", "d");
Room hallway = new Room("hallway", "Hallway", "d");
kitchen.addExit(Direction.NORTH, hallway);
hallway.addExit(Direction.SOUTH, kitchen);
Map<String, Room> rooms = new LinkedHashMap<>();
rooms.put("kitchen", kitchen);
rooms.put("hallway", hallway);
World world = new World(rooms, Map.of(), Map.of(), "t", "w");
Player player = new Player(kitchen, 0); // visited = {kitchen}; hallway is a KNOWN stub
TestIO io = new TestIO();
GameContext ctx = new GameContext(world, player, io);
new MapCommand().execute(ctx, List.of());
String out = io.allOutput();
assertThat(out).contains("Kitchen"); // current room name appears on the map
assertThat(out).contains("?"); // unexplored neighbour stub
}
}