reikhelm/.dev/2026-05-28-procgen-map-core/tasks/08-room-carver.md
Parley Hatch 08e99e38a3 chore: scaffold reikhelm cargo workspace (core + viz crates)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 20:56:24 -06:00

3.1 KiB

Task 8: RoomCarver Pass

Depends on: Task 6

Context Files

  • .dev/2026-05-28-procgen-map-core/spec/design.md — §4.7 (Shaper role), §5 (data flow).
  • .dev/2026-05-28-procgen-map-core/README.md — inter-pass data contract (RoomCarver row).
  • reikhelm-core/src/pass.rsPass, GenContext (Task 6).
  • reikhelm-core/src/region.rs, reikhelm-core/src/map.rsRegion, RegionKind::Room, Tile::Floor.
  • reikhelm-core/src/passes/mod.rs — append the module declaration here.

Files

  • Create: reikhelm-core/src/passes/room.rsRoomConfig, RoomCarver.
  • Modify: reikhelm-core/src/passes/mod.rs — append pub mod room; and re-export RoomCarver, RoomConfig.

What to Build

A shaper (spec §4.7) that turns BSP leaves into actual rooms. For each existing Room region (the placeholders from BspPartition), it picks a room rectangle that fits inside the leaf bounds (random size within RoomConfig limits, leaving a margin from the leaf edge so corridors and walls have room), carves Tile::Floor into ctx.tiles over that rectangle, and updates the region's bounds to the actual room rect and fills cells with the carved points. A leaf too small to hold a min_size room is skipped gracefully: its region is left in place with empty cells (never removed) — removal would break the RegionId-as-index invariant (Task 5). A Room region with empty cells denotes "not actually a room"; downstream room consumers (MstConnect, CorridorCarver) treat only Room regions with non-empty cells as real rooms. (In the assembled dungeon recipe this case never fires — Task 12's config validation guarantees every leaf fits a room — but the pass must handle it without panicking per spec §8.)

This pass reads/writes ctx.regions and ctx.tiles only; it does not depend on BspPartition's code, only on the documented "placeholder Room regions" precondition — so tests construct that precondition directly.

Interface Dependencies

  • Consumes: Pass, GenContext, Rng (Task 6); Region, Tile (Task 5).
  • Produces:
    • struct RoomConfig { min_size: i32, max_size: i32, margin: i32 } (+ Default).
    • struct RoomCarver { /* holds RoomConfig */ }new(cfg) -> Self; impl Pass with name() == "room_carver".
    • Writes to context: Floor tiles; finalized Room region bounds/cells.

Tests

  • Given a GenContext with two placeholder Room regions over a Wall grid, after running: each carved room's bounds lies within its original leaf bounds and within the map; the floor cell count matches bounds area.
  • Carved floors do not extend outside the originating leaf (margin respected).
  • A leaf smaller than min_size is skipped without panicking.
  • Determinism: same seed/sub-stream → identical carved rooms.

Success Criteria

  • RoomCarver carves Floor rooms inside leaf bounds, respecting size/margin, and finalizes region bounds/cells.
  • Undersized leaves are handled gracefully (no panic).
  • pub mod room; appended to passes/mod.rs.
  • Tests pass: cargo test -p reikhelm-core room

Commit

"feat(core): RoomCarver pass"