pipeworks_mud_mapper.models.room

Room and coordinate models for PipeWorks MUD Mapper.

This module defines the core room-related data structures used by the mapper. Two room types exist to support the two-file workflow:

  • Room: Game truth representation (no coordinates)

  • MapRoom: Authoring representation (includes coordinates)

The separation reflects the principle that coordinates are “authoring scaffolding” - they help humans visualize the map but are not part of the game state.

Direction System

MUDs traditionally use cardinal directions for navigation. This mapper supports six directions as decided in goblin_cartography.md Section 1.7:

Direction

Axis

Typical Use

north

+Y

Horizontal movement

south

-Y

Horizontal movement

east

+X

Horizontal movement

west

-X

Horizontal movement

up

+Z

Vertical (stairs, ladders)

down

-Z

Vertical (trapdoors, basements)

The decision to use 6 directions (not 4) allows rooms to have both a “south” exit AND a “down” exit going to different places - essential for multi-story structures like The Crooked Pipe pub.

Coordinate System

The mapper uses a 3D Cartesian coordinate system:

        +Y (North)
           │
           │
 -X ───────┼─────── +X
(West)     │       (East)
           │
        -Y (South)

 Z: +Z (Up) / -Z (Down)

The origin [0, 0, 0] is conventionally the zone’s spawn room.

Examples

Creating a room for game truth (Zone export):

room = Room(
    id="spawn",
    name="The Crooked Pipe",
    description="A low-ceilinged goblin pub...",
    exits={"north": "front_parlour", "down": "cellar"},
    items=["ale_mug", "chalk"],
)

Creating a room for authoring (MapFile):

map_room = MapRoom(
    id="spawn",
    name="The Crooked Pipe",
    description="A low-ceilinged goblin pub...",
    coords=Coords(x=0, y=0, z=0),
    exits={"north": "front_parlour", "down": "cellar"},
    items=["ale_mug", "chalk"],
)

Converting MapRoom to Room (strips coordinates):

room = map_room.to_room()

See also

-, -

Attributes

Direction

Valid MUD movement directions.

DIRECTIONS

All valid directions as a tuple for iteration.

OPPOSITE_DIRECTION

Mapping of each direction to its opposite.

DIRECTION_OFFSETS

Coordinate offsets for each direction.

DIRECTION_SHORT

Short labels used in the UI for direction indicators.

SHORT_TO_DIRECTION

Reverse mapping for checkbox values back to full direction names.

Classes

Coords

Three-dimensional coordinates for room placement.

Room

A room in game truth format (no coordinates).

MapRoom

A room in authoring format (includes coordinates and LLM metadata).

Module Contents

pipeworks_mud_mapper.models.room.Direction

Valid MUD movement directions.

Constrained to six values matching the decision in goblin_cartography.md: - Horizontal: north, south, east, west - Vertical: up, down

Up/Down are semantically distinct from North/South - they represent vertical traversal (stairs, ladders, trapdoors) rather than horizontal movement on a conceptual map.

pipeworks_mud_mapper.models.room.DIRECTIONS: tuple[Direction, Ellipsis] = ('north', 'south', 'east', 'west', 'up', 'down')

All valid directions as a tuple for iteration.

pipeworks_mud_mapper.models.room.OPPOSITE_DIRECTION: dict[Direction, Direction]

Mapping of each direction to its opposite.

Used for bidirectional exit creation - when creating an exit from A to B, the opposite direction is used for the return exit from B to A.

pipeworks_mud_mapper.models.room.DIRECTION_OFFSETS: dict[Direction, tuple[int, int, int]]

Coordinate offsets for each direction.

These represent the unit vector for movement in each direction: - X axis: East (+1) / West (-1) - Y axis: North (+1) / South (-1) - Z axis: Up (+1) / Down (-1)

Note: Actual room spacing may vary. These offsets indicate direction only, not distance. Use for determining which direction a target room lies relative to a source room.

pipeworks_mud_mapper.models.room.DIRECTION_SHORT: dict[Direction, str]

Short labels used in the UI for direction indicators.

pipeworks_mud_mapper.models.room.SHORT_TO_DIRECTION: dict[str, Direction]

Reverse mapping for checkbox values back to full direction names.

class pipeworks_mud_mapper.models.room.Coords(/, **data)[source]

Bases: pydantic.BaseModel

Three-dimensional coordinates for room placement.

Coordinates are authoring metadata - they help humans visualize and validate the map layout but are not used by the game engine. The MUD server operates on pure topology (room connections) not geometry.

x

East/West position. Positive = East, Negative = West.

Type:

int

y

North/South position. Positive = North, Negative = South.

Type:

int

z

Up/Down level. Positive = Up (upper floors), Negative = Down (basements).

Type:

int

Examples

>>> coords = Coords(x=0, y=0, z=0)  # Origin (typically spawn room)
>>> coords = Coords(x=5, y=-5, z=0)  # 5 units east, 5 units south
>>> coords = Coords(x=0, y=0, z=-1)  # One level below origin (basement)

Notes

The coordinate system follows standard mathematical conventions: - Origin at (0, 0, 0) - Right-hand rule for axis orientation - Integers only (no fractional positions)

to_tuple()[source]

Convert coordinates to a tuple.

Returns:

Coordinates as (x, y, z) tuple.

Return type:

tuple[int, int, int]

Examples

>>> Coords(x=1, y=2, z=3).to_tuple()
(1, 2, 3)
to_list()[source]

Convert coordinates to a list.

This format matches the JSON serialization used in map files.

Returns:

Coordinates as [x, y, z] list.

Return type:

list[int]

Examples

>>> Coords(x=1, y=2, z=3).to_list()
[1, 2, 3]
classmethod from_list(coords)[source]

Create Coords from a list.

Parameters:

coords (list[int]) – Coordinates as [x, y, z] list.

Returns:

New Coords instance.

Return type:

Coords

Raises:

ValueError – If coords does not have exactly 3 elements.

Examples

>>> Coords.from_list([1, 2, 3])
Coords(x=1, y=2, z=3)
offset(direction)[source]

Return new coordinates offset in the given direction.

Parameters:

direction (Direction) – The direction to offset towards.

Returns:

New Coords offset by one unit in the given direction.

Return type:

Coords

Examples

>>> origin = Coords(x=0, y=0, z=0)
>>> origin.offset("north")
Coords(x=0, y=1, z=0)
>>> origin.offset("down")
Coords(x=0, y=0, z=-1)
class pipeworks_mud_mapper.models.room.Room(/, **data)[source]

Bases: pydantic.BaseModel

A room in game truth format (no coordinates).

This model represents a room as it appears in exported zone files - the format consumed by the MUD server. Coordinates are excluded because the game engine operates on topology (connections) not geometry (positions).

id

Unique identifier within the zone. Used as dictionary key and in exit references. Should be lowercase with underscores (e.g., “front_parlour”).

Type:

str

name

Human-readable display name shown to players (e.g., “Front Parlour”).

Type:

str

description

Room description shown when a player enters or looks. Can be multiple sentences. Defaults to empty string.

Type:

str

exits

Mapping of direction to target room ID. Target can be same-zone (e.g., “front_parlour”) or cross-zone (e.g., “docks:east_pier”).

Type:

dict[Direction, str]

items

List of item IDs present in this room. Items must be defined in the zone’s items dictionary.

Type:

list[str]

Examples

>>> room = Room(
...     id="spawn",
...     name="The Crooked Pipe",
...     description="A low-ceilinged goblin pub with sticky floors.",
...     exits={"north": "front_parlour", "down": "cellar"},
...     items=["ale_mug"],
... )

See also

MapRoom

Room with coordinates for authoring.

Zone

Container for rooms in game truth format.

classmethod validate_id(v)[source]

Validate room ID format.

Room IDs must start with a letter and contain only lowercase letters, numbers, and underscores.

Parameters:

v (str) – The room ID to validate.

Returns:

The validated room ID.

Return type:

str

Raises:

ValueError – If the ID format is invalid.

class pipeworks_mud_mapper.models.room.MapRoom(/, **data)[source]

Bases: pydantic.BaseModel

A room in authoring format (includes coordinates and LLM metadata).

This model represents a room as it appears in map files - the format used by the mapper tool during authoring. It extends the game truth Room with:

  • Coordinates: Position in 3D space for visualization

  • LLM generation metadata: Provenance info for AI-generated descriptions

  • Description validation metadata: Latest validator output for the description

Both fields are “authoring scaffolding” - they help humans create and understand the map but are not part of the game state. When exporting to a zone file, both are stripped using to_room().

id

Unique identifier within the zone.

Type:

str

name

Human-readable display name.

Type:

str

description

Room description text.

Type:

str

coords

Position in 3D space (x, y, z). Used for visualization only.

Type:

Coords

exits

Mapping of direction to target room ID.

Type:

dict[Direction, str]

items

List of item IDs present in this room.

Type:

list[str]

llm_generation

Metadata about the last LLM generation for this room’s description. Only present if the description was generated by Ollama. Contains model name, seed, parameters, and prompts for reproducibility. Stripped during zone export (like coords).

Type:

OllamaGenerationInfo | None

description_validation

Metadata about the last validator run for this description. Stripped during zone export (like coords).

Type:

DescriptionValidationInfo | None

Examples

>>> map_room = MapRoom(
...     id="spawn",
...     name="The Crooked Pipe",
...     description="A low-ceilinged goblin pub.",
...     coords=Coords(x=0, y=0, z=0),
...     exits={"north": "front_parlour"},
...     items=["ale_mug"],
... )

Converting to game truth format (strips coords and llm_generation):

>>> room = map_room.to_room()
>>> hasattr(room, 'coords')  # False - stripped
False
>>> hasattr(room, 'llm_generation')  # Also stripped
False

See also

Room

Game truth format (no coordinates or LLM metadata).

MapFile

Container for MapRooms.

OllamaGenerationInfo

LLM generation metadata model.

classmethod validate_id(v)[source]

Validate room ID format.

Room IDs must start with a letter and contain only lowercase letters, numbers, and underscores.

to_room()[source]

Convert to game truth format by stripping authoring metadata.

Removes coordinates and LLM generation metadata, producing a Room suitable for zone export. The MUD server only needs topology (room connections) and content (description, items), not authoring aids.

Returns:

A Room instance without coordinates or LLM metadata.

Return type:

Room

Notes

The following fields are intentionally NOT copied to the output:

  • coords: Visualization aid, not game state

  • llm_generation: Provenance tracking, not game state

  • description_validation: Validator output, not game state

Examples

>>> map_room = MapRoom(
...     id="spawn",
...     name="Spawn",
...     coords=Coords(x=0, y=0, z=0),
... )
>>> room = map_room.to_room()
>>> hasattr(room, 'coords')
False
classmethod from_dict(data)[source]

Create MapRoom from a dictionary (legacy format support).

This method handles various input formats:

  • Legacy coords as [x, y, z] list (converted to Coords object)

  • Files without llm_generation field (defaults to None)

  • Files with llm_generation as dict (validated by Pydantic)

Parameters:

data (dict) –

Room data dictionary. May contain:

  • coords as [x, y, z] list or Coords object

  • llm_generation as dict, None, or missing entirely

Returns:

New MapRoom instance with all fields properly typed.

Return type:

MapRoom

Examples

Basic room without LLM metadata (legacy format):

>>> data = {
...     "id": "spawn",
...     "name": "Spawn",
...     "coords": [0, 0, 0],
...     "exits": {},
...     "items": [],
... }
>>> room = MapRoom.from_dict(data)
>>> room.coords
Coords(x=0, y=0, z=0)
>>> room.llm_generation is None
True

Room with LLM generation metadata:

>>> data = {
...     "id": "spawn",
...     "name": "Spawn",
...     "coords": [0, 0, 0],
...     "exits": {},
...     "items": [],
...     "llm_generation": {
...         "model": "gemma2:2b",
...         "actual_seed": 12345,
...         "template_id": "custom",
...         "temperature": 0.7,
...         "top_k": 40,
...         "top_p": 0.9,
...         "num_ctx": 4096,
...         "num_predict": 512,
...         "system_prompt": "...",
...         "user_prompt": "...",
...         "generated_at": "2024-01-15T10:30:00Z",
...     },
... }
>>> room = MapRoom.from_dict(data)
>>> room.llm_generation.model
'gemma2:2b'