feat(io): adaptive ASCII map width; document map command, mark sub-project done

AsciiMap sizes room boxes to the longest visible name (capped) so names
like 'Dark Hallway' are no longer truncated; connector centering follows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 21:09:08 +02:00
parent 7948aa2088
commit 5ebbd2ce42
3 changed files with 27 additions and 12 deletions

View File

@@ -46,6 +46,7 @@ mvn exec:java@gui # Swing-GUI (thb.jeanluc.adventure.AppGui)
|---|---|---| |---|---|---|
| `go <richtung>` | `move`, `walk` | In eine Himmelsrichtung gehen | | `go <richtung>` | `move`, `walk` | In eine Himmelsrichtung gehen |
| `look` | `l` | Aktuellen Raum beschreiben | | `look` | `l` | Aktuellen Raum beschreiben |
| `map` | `m` | Karte der erkundeten Räume anzeigen |
| `inventory` | `inv`, `i` | Inventar anzeigen | | `inventory` | `inv`, `i` | Inventar anzeigen |
| `take <item>` | `pick`, `get` | Gegenstand aufnehmen | | `take <item>` | `pick`, `get` | Gegenstand aufnehmen |
| `drop <item>` | `put` | Gegenstand ablegen | | `drop <item>` | `put` | Gegenstand ablegen |

View File

@@ -56,7 +56,14 @@ Farb-Rollen: Items / NPCs / Exits / Heading / Gefahr.
- **Konsole**: Font nicht kontrollierbar → gestufte Fallbacks - **Konsole**: Font nicht kontrollierbar → gestufte Fallbacks
(reines ASCII → Unicode-Box-Drawing → Nerd-Glyphen) statt harter Annahme. (reines ASCII → Unicode-Box-Drawing → Nerd-Glyphen) statt harter Annahme.
### 3. Karte / Map ### 3. Karte / Map ✅ umgesetzt (Branch `feature/map`)
> Umgesetzt: `MapLayout` (BFS-Gitter-Layout + Fog of War), `MapView`-Modell,
> GUI-`MapPanel` (Graphics2D, ersetzt die Exit-Liste), Konsolen-ASCII via
> `AsciiMap` + `map`-Befehl, Besuchte-Räume-Tracking auf `Player`, Map-Push pro Zug.
> Item/NPC-Marker und Türen-Styling offen (Quest-Teilprojekt). Spec/Plan unter
> `docs/superpowers/`.
- Übersichtskarte der Räume in **beiden** Modi. - Übersichtskarte der Räume in **beiden** Modi.
- Konsole: ASCII-Map. GUI: gezeichnete Map (Grid/Graph). - Konsole: ASCII-Map. GUI: gezeichnete Map (Grid/Graph).

View File

@@ -11,8 +11,9 @@ import java.util.Set;
*/ */
public final class AsciiMap { public final class AsciiMap {
private static final int INNER = 7; // room name field width private static final int MIN_INNER = 7; // minimum room name field width
private static final int GAP = 3; // horizontal corridor width private static final int MAX_INNER = 14; // cap so the map stays compact
private static final int GAP = 3; // horizontal corridor width
private AsciiMap() { private AsciiMap() {
} }
@@ -24,10 +25,12 @@ public final class AsciiMap {
int maxX = 0; int maxX = 0;
int maxY = 0; int maxY = 0;
int inner = MIN_INNER;
Map<Long, RoomCell> at = new HashMap<>(); Map<Long, RoomCell> at = new HashMap<>();
for (RoomCell c : view.cells()) { for (RoomCell c : view.cells()) {
maxX = Math.max(maxX, c.x()); maxX = Math.max(maxX, c.x());
maxY = Math.max(maxY, c.y()); maxY = Math.max(maxY, c.y());
inner = Math.max(inner, Math.min(MAX_INNER, c.name().length()));
at.put(key(c.x(), c.y()), c); at.put(key(c.x(), c.y()), c);
} }
@@ -50,19 +53,23 @@ public final class AsciiMap {
String hz = unicode ? "" : "-"; String hz = unicode ? "" : "-";
String vt = unicode ? "" : "|"; String vt = unicode ? "" : "|";
int boxW = inner + 2;
int leftPad = (boxW - 1) / 2;
int rightPad = boxW - 1 - leftPad;
StyledText.Builder b = StyledText.builder(); StyledText.Builder b = StyledText.builder();
for (int gy = 0; gy <= maxY; gy++) { for (int gy = 0; gy <= maxY; gy++) {
for (int line = 0; line < 3; line++) { for (int line = 0; line < 3; line++) {
for (int gx = 0; gx <= maxX; gx++) { for (int gx = 0; gx <= maxX; gx++) {
RoomCell c = at.get(key(gx, gy)); RoomCell c = at.get(key(gx, gy));
if (c == null) { if (c == null) {
b.plain(" ".repeat(INNER + 2)); b.plain(" ".repeat(boxW));
} else if (line == 0) { } else if (line == 0) {
styled(b, tl + hz.repeat(INNER) + tr, c.state()); styled(b, tl + hz.repeat(inner) + tr, c.state());
} else if (line == 2) { } else if (line == 2) {
styled(b, bl + hz.repeat(INNER) + br, c.state()); styled(b, bl + hz.repeat(inner) + br, c.state());
} else { } else {
styled(b, vt + center(label(c), INNER) + vt, c.state()); styled(b, vt + center(label(c, inner), inner) + vt, c.state());
} }
if (gx < maxX) { if (gx < maxX) {
if (line == 1 && hEdge.contains(key(gx, gy))) { if (line == 1 && hEdge.contains(key(gx, gy))) {
@@ -77,9 +84,9 @@ public final class AsciiMap {
if (gy < maxY) { if (gy < maxY) {
for (int gx = 0; gx <= maxX; gx++) { for (int gx = 0; gx <= maxX; gx++) {
if (vEdge.contains(key(gx, gy))) { if (vEdge.contains(key(gx, gy))) {
b.plain(" ".repeat(4)).dim(vt).plain(" ".repeat(4)); b.plain(" ".repeat(leftPad)).dim(vt).plain(" ".repeat(rightPad));
} else { } else {
b.plain(" ".repeat(INNER + 2)); b.plain(" ".repeat(boxW));
} }
if (gx < maxX) { if (gx < maxX) {
b.plain(" ".repeat(GAP)); b.plain(" ".repeat(GAP));
@@ -99,10 +106,10 @@ public final class AsciiMap {
} }
} }
private static String label(RoomCell c) { private static String label(RoomCell c, int inner) {
String n = c.name(); String n = c.name();
if (n.length() > INNER) { if (n.length() > inner) {
n = n.substring(0, INNER); n = n.substring(0, inner);
} }
return n; return n;
} }