Files
Jander_Semester2/Semesterprojekt/docs/superpowers/specs/2026-05-31-map-design.md
Jean-Luc Makiola 025372b9b1 docs: spec for map / mini-map (sub-project 2)
Fog-of-war map from the directional exit graph. MapLayout (BFS) produces a
frontend-agnostic MapView; SwingIO draws it (Graphics2D MapPanel, replaces
exits text), ConsoleIO mirrors it as ASCII via the map command. Visited
tracking on Player. Item/NPC markers and locked-door styling deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 20:51:09 +02:00

6.7 KiB
Raw Blame History

Spec: Karte / Mini-Map (Teilprojekt 2)

Stand: 2026-05-31. Zweites Teilprojekt aus enhancement-ideas.md. Baut auf der Präsentations-Schicht (Teilprojekt 1) auf, insbesondere dem reservierten GUI-Seitenpanel und dem semantischen Modell-+-Renderer-Muster.

1. Kontext & Ziel

Räume bilden bereits einen gerichteten N/S/O/W-Graphen über Room.exits (EnumMap<Direction, Room>). Ziel: eine Karte in beiden Frontends, die diesen Graphen sichtbar macht Fog of War (nur Entdecktes), Stil „umrandete Räume + Korridore" (im Brainstorming bestätigt). Die GUI zeichnet grafisch (Graphics2D), die Konsole spiegelt es als ASCII.

Bestätigte Entscheidungen:

  • Fog of War: nur besuchte Räume + deren direkte Nachbarn als ?-Stub.
  • Stil: umrandete Räume, durch Korridore verbunden; aktueller Raum hervorgehoben.
  • Layout aus dem Graphen abgeleitet (keine Koordinaten in YAML).
  • GUI: persistentes Panel ersetzt die Exit-Zeile. Konsole: map-Befehl on demand, Exit-Zeile im Raumtext bleibt.

2. Scope

In Scope:

  • MapView-Modell (platzierte Zellen + Verbindungen, Zustände).
  • MapLayout-Service: BFS-Layout aus dem Exit-Graphen + Fog-of-War-Filter.
  • Besuchte-Räume-Tracking auf Player.
  • GameIO: setMap (Push pro Zug, GUI) + showMap (on demand, Konsole).
  • MapCommand (map, m).
  • Game-Loop ruft setMap pro Zug (neben setHud).
  • GUI: MapPanel (Graphics2D) im Seitenpanel, scrollbar, auf aktuellen Raum zentriert.
  • Konsole: ASCII-Karte (AsciiMap), respektiert GlyphMode.

Out of Scope (spätere Teilprojekte):

  • Marker für Items/NPCs auf der Karte.
  • Styling für verschlossene/blockierte Exits (Quest-Teilprojekt; Karte bekommt später einen Hook dafür).
  • Zoom über das Scrollen hinaus.

3. Architektur (Modell + Renderer pro Frontend)

MapLayout erzeugt aus World (Exit-Graph), der Menge besuchter Räume und dem aktuellen Raum eine frontend-agnostische MapView. Layout und Fog-of-War-Logik liegen ausschließlich hier; die Renderer kennen nur das fertige MapView.

flowchart LR
    W["World (Exit-Graph)"] --> L["MapLayout.compute()"]
    V["Player.visitedRoomIds"] --> L
    C["aktueller Raum"] --> L
    L --> MV["MapView (Zellen + Verbindungen)"]
    MV -- "setMap()" --> GUI["SwingIO → MapPanel (Graphics2D)"]
    MV -- "showMap()" --> CON["ConsoleIO → AsciiMap (StyledText)"]

4. Komponenten & Datenmodell

Views in io.text, Layout-Logik in neuem Package map, GUI-Panel in io.

// io.text
public enum CellState { CURRENT, VISITED, KNOWN }

public record RoomCell(String id, String name, int x, int y, CellState state) {}

public record Connection(RoomCell from, RoomCell to) {}   // Stil via Zellzustand

public record MapView(java.util.List<RoomCell> cells,
                      java.util.List<Connection> connections) {
    public MapView { cells = List.copyOf(cells); connections = List.copyOf(connections); }
}
  • map.MapLayout static MapView compute(World world, String startRoomId, Set<String> visited, Room current).
  • io.text.AsciiMap static StyledText render(MapView, GlyphMode).
  • io.MapPanel JComponent, void show(MapView); paintComponent zeichnet.
  • command.impl.MapCommand baut MapView, ruft io.showMap(view).
  • model.Player Set<String> visitedRoomIds (LinkedHashSet, Reihenfolge stabil).

GameIO-Erweiterung (additiv)

/** Push pro Zug: GUI aktualisiert ihr Panel; Konsole ignoriert (kein Spam). */
default void setMap(MapView view) { /* no-op */ }

/** On demand (map-Befehl): rendert die Karte. Default = ASCII in UNICODE. */
default void showMap(MapView view) { print(AsciiMap.render(view, GlyphMode.UNICODE)); }
  • ConsoleIO überschreibt showMapprint(AsciiMap.render(view, this.glyphs)) (nutzt also seinen konfigurierten Glyph-Modus). setMap bleibt Default (no-op) → kein Karten-Spam pro Zug in der Konsole.
  • SwingIO überschreibt setMapMapPanel neu zeichnen; showMap → no-op (das Panel ist ohnehin sichtbar).
  • TestIO nutzt beide Defaults: setMap = no-op, showMap druckt UNICODE-ASCII in outputsMapCommand-Test kann darauf assertieren. Kein Override nötig.

So liegt der Glyph-Modus dort, wo er hingehört (am Konsolen-Renderer), ohne die GameIO-Schnittstelle um eine Glyph-Methode aufzublähen.

5. Fog-of-War-Regeln

Zustand Bedeutung Darstellung
CURRENT besuchter Raum, in dem der Spieler steht Goldener Rahmen
VISITED bereits betretener Raum heller Rahmen + Name
KNOWN direkter Exit-Nachbar eines besuchten Raums, noch nicht betreten gestrichelter ?-Stub
(hidden) alles andere nicht platziert

Beim Betreten eines ?-Raums wird er VISITED; seine Nachbarn werden zu neuen KNOWN-Stubs. Die Karte wächst eine Ringschicht voraus.

6. Layout-Algorithmus & Konfliktbehandlung

BFS vom Startraum über den vollständigen Exit-Graphen; jede Richtung verschiebt die Gitterkoordinate (N→y1, S→y+1, O→x+1, W→x1). Hand-gebaute Welten sind geometrisch konsistent; falls BFS zwei Räume auf dieselbe Zelle legt (nicht-planarer Graph), gewinnt der erste, die Kollision wird geloggt, das Rendern läuft weiter (kein Crash). Die Fog-of-War-Filterung läuft nach dem Layout; danach werden die Koordinaten normalisiert (Verschiebung, sodass min = 0,0).

7. Konsolen-Verhalten

map / m druckt die ASCII-Karte on demand (keine persistente Region in der Konsole). Die Box-Raumansicht behält ihre Inline-Exits:-Zeile Konsolenspieler müssen also nicht map tippen, um zu navigieren; die Karte ist Überblick-Bonus. In der GUI ersetzt das Dauerpanel die Exit-Zeile.

8. Fehlerbehandlung

Fall Verhalten
Koordinaten-Kollision (nicht-planar) erste Zuordnung gewinnt, Warnung geloggt, Rendern fährt fort
Startraum hat keine Exits Karte zeigt nur die aktuelle Zelle
Sehr große Karte (viele Räume) GUI-Panel scrollbar, auf aktuelle Zelle zentriert; ASCII so groß wie nötig

9. Testing

  • MapLayout (reine Logik): Koordinaten aus bekanntem Graphen; Fog-Zustände für eine gegebene Visited-Menge; Kollisionsbehandlung; Normalisierung.
  • MapView/Records: Immutabilität.
  • AsciiMap: strukturelle Assertions auf bekanntem MapView (Namen vorhanden, aktueller markiert, ? für KNOWN), Farbe aus.
  • MapCommand: über TestIO erzeugt Karten-Ausgabe.
  • Player: Besuchte-Räume-Tracking (Start + nach Bewegung).
  • SwingIO/MapPanel: nicht unit-getestet (Graphics2D/EDT); manueller Smoke-Test.

10. Offene Detailfragen (in Implementierung entscheidbar)

  • ASCII-Zellbreite/-höhe und Verbindungslänge (Lesbarkeit vs. Kompaktheit).
  • Genaue Farben/Strichstärken im MapPanel (an Präsentations-Palette angelehnt).