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:
@@ -10,6 +10,7 @@ import thb.jeanluc.adventure.command.impl.GoCommand;
|
|||||||
import thb.jeanluc.adventure.command.impl.HelpCommand;
|
import thb.jeanluc.adventure.command.impl.HelpCommand;
|
||||||
import thb.jeanluc.adventure.command.impl.InventoryCommand;
|
import thb.jeanluc.adventure.command.impl.InventoryCommand;
|
||||||
import thb.jeanluc.adventure.command.impl.LookCommand;
|
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.QuitCommand;
|
||||||
import thb.jeanluc.adventure.command.impl.ReadCommand;
|
import thb.jeanluc.adventure.command.impl.ReadCommand;
|
||||||
import thb.jeanluc.adventure.command.impl.TakeCommand;
|
import thb.jeanluc.adventure.command.impl.TakeCommand;
|
||||||
@@ -68,6 +69,7 @@ public final class App {
|
|||||||
registry.register(new UseCommand(), "use");
|
registry.register(new UseCommand(), "use");
|
||||||
registry.register(new ReadCommand(), "read");
|
registry.register(new ReadCommand(), "read");
|
||||||
registry.register(new ExamineCommand(), "examine", "x", "inspect");
|
registry.register(new ExamineCommand(), "examine", "x", "inspect");
|
||||||
|
registry.register(new MapCommand(), "map", "m");
|
||||||
registry.register(new TalkCommand(), "talk", "speak");
|
registry.register(new TalkCommand(), "talk", "speak");
|
||||||
registry.register(new GiveCommand(), "give");
|
registry.register(new GiveCommand(), "give");
|
||||||
registry.register(new HelpCommand(registry), "help", "?");
|
registry.register(new HelpCommand(registry), "help", "?");
|
||||||
|
|||||||
@@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package thb.jeanluc.adventure.io;
|
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.Hud;
|
||||||
|
import thb.jeanluc.adventure.io.text.MapView;
|
||||||
import thb.jeanluc.adventure.io.text.RoomView;
|
import thb.jeanluc.adventure.io.text.RoomView;
|
||||||
import thb.jeanluc.adventure.io.text.Span;
|
import thb.jeanluc.adventure.io.text.Span;
|
||||||
import thb.jeanluc.adventure.io.text.Style;
|
import thb.jeanluc.adventure.io.text.Style;
|
||||||
@@ -100,6 +102,11 @@ public class ConsoleIO implements GameIO {
|
|||||||
out.println(paint(Style.DIM, line));
|
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) {
|
private String section(String label, List<String> xs, Style st) {
|
||||||
StringBuilder sb = new StringBuilder(" ").append(paint(Style.DIM, label)).append(" ");
|
StringBuilder sb = new StringBuilder(" ").append(paint(Style.DIM, label)).append(" ");
|
||||||
for (int i = 0; i < xs.size(); i++) {
|
for (int i = 0; i < xs.size(); i++) {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package thb.jeanluc.adventure.io;
|
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.Hud;
|
||||||
|
import thb.jeanluc.adventure.io.text.MapView;
|
||||||
import thb.jeanluc.adventure.io.text.Renderings;
|
import thb.jeanluc.adventure.io.text.Renderings;
|
||||||
import thb.jeanluc.adventure.io.text.RoomView;
|
import thb.jeanluc.adventure.io.text.RoomView;
|
||||||
import thb.jeanluc.adventure.io.text.StyledText;
|
import thb.jeanluc.adventure.io.text.StyledText;
|
||||||
@@ -32,4 +34,14 @@ public interface GameIO {
|
|||||||
default void setHud(Hud hud) {
|
default void setHud(Hud hud) {
|
||||||
// no-op
|
// 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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user