Files
Verbatim/WORLDGEN_PLAN.md
T
2026-06-21 22:27:20 +03:00

6.3 KiB

World Generator Plan

Goal

Procedural world generation with depth-based biomes, rooms, corridors, and randomized features.

Current State

  • Implemented in src/world/worldgen.rs
  • Depth-based dispatch: surface (1-3), caves (4-6), BSP dungeon (7+)
  • Randomized features, pools, trees, walls, rooms, corridors, traps
  • World size: 2048x2048 for main game; 250x250 for tests/AI
  • Seed-based generation with Game::seed
  • Per-chunk world cache in cache/worlds/<seed>/depth_<N>/
  • Tests in tests/worldgen.rs and tests/large_world.rs (ignored, slow)

Algorithms Researched

BSP (Binary Space Partitioning)

  • Recursively divide space into rectangles
  • Place room in each leaf node
  • Connect siblings with corridors
  • Guarantees no overlaps
  • Use for: dungeon rooms (depth 7+)

Cellular Automata (4-5 rule)

  • Fill grid with ~45% random walls
  • 5 iterations: wall if >=4 neighbors are walls, else empty
  • Produces organic cave shapes
  • Flood fill to verify connectivity
  • Use for: caves (depth 4-6, and underground at depth 1-3)

Drunkard's Walk

  • Random walk digs tunnels through solid rock
  • Creates winding cave-like paths
  • Use for: tunnels connecting rooms

Brogue Room Accretion

  • Start with one room, attach new rooms to existing structure
  • Inherently connected (tree structure)
  • Room templates: rectangle, CA blob, circle
  • Use for: room placement strategy

Rooms and Mazes (Bob Nystrom)

  • Place rooms → fill gaps with maze → connect → remove dead ends
  • Inspirational, not directly used

Noita — Herringbone Wang Tiles

  • Pre-made chunks laid in herringbone pattern
  • Randomized contents within chunks
  • Too complex for now, possible future enhancement

Architecture

New module: src/world/worldgen.rs

WorldGenerator
├── rng: &mut CellularAutomaton
├── generate(grid, depth)              — main entry point
├── generate_surface(grid, depth)      — depth 1-3: terrain + caves + features
├── generate_caves(grid, depth)        — depth 4-6: full underground caves
├── generate_dungeon(grid, depth)      — depth 7+: BSP rooms + corridors
│
├── Surface sub-methods:
│   ├── terrain_noise(x, depth)        — multi-octave surface height
│   ├── fill_terrain(grid, depth)      — fill dirt/stone/grass by depth
│   ├── carve_underground_caves(grid)  — CA caves below surface
│   ├── place_trees(grid, count)       — random tree placement
│   ├── place_pools(grid, count, types)— random liquid pools
│   ├── place_sand_dunes(grid, count)  — sand piles
│   └── place_walls(grid, count)       — stone wall obstacles
│
├── Cave sub-methods:
│   ├── ca_caves(grid, fill_prob, iterations) — cellular automata
│   ├── flood_fill_largest(grid)       — find largest connected region
│   ├── seal_small_regions(grid)       — fill disconnected caves
│   └── place_underground_pools(grid)  — lava/acid in caves
│
├── Dungeon sub-methods:
│   ├── bsp_split(rect, depth)         — recursive space partitioning
│   ├── place_room(grid, rect)         — carve room interior
│   ├── connect_rooms(grid, rooms)     — L-shaped corridors
│   ├── place_doors(grid, rooms)       — door at room entrances
│   └── place_traps(grid, rooms)       — acid/fire traps in rooms
│
└── Shared:
    ├── place_stairs(grid, depth)      — stairs in appropriate location
    └── place_items(game, rooms)       — items in rooms/on surface

Depth-based Generation

Depth Type Surface Features Algorithm
1-3 Surface Grass/dirt Trees, water pools, sand dunes, stone walls, underground CA caves Multi-octave noise + CA
4-6 Caves Stone/dirt Large CA caves, lava pools, acid pools, stalactites Cellular automata (4-5 rule)
7+ Dungeon Stone BSP rooms (5x3 to 12x8), corridors, traps, stairs BSP + corridor connection

Implementation Details

Surface terrain (depth 1-3)

  • Multi-octave sine noise: base + detail + micro
  • Amplitude: 4-8 cells variation
  • Surface material: grass at depth 1, dirt at 2-3
  • Below surface: dirt for 8 cells, then stone
  • Border: stone walls

CA cave generation (depth 4-6)

  1. Fill entire grid with stone
  2. Random fill ~45% as empty (cave candidate)
  3. Run 5 iterations of 4-5 rule:
    • Cell becomes wall if >=4 of 8 neighbors are walls
    • Cell becomes empty if <4 neighbors are walls
  4. Flood fill from center, find largest connected region
  5. Seal all cells not in largest region (fill with stone)
  6. Place lava/acid pools in random empty areas
  7. Place stalactites (stone pillars) in random positions

BSP dungeon (depth 7+)

  1. Start with full grid as stone
  2. Recursively split into 2 halves (alternate H/V)
  3. Stop when area < min_room_size (15x10)
  4. In each leaf: place room (smaller than partition, centered)
  5. Connect sibling rooms with L-shaped corridor (2 wide)
  6. Place stairs in the deepest/farthest room
  7. Place items in 2-3 random rooms
  8. Place traps (acid pockets) in 1-2 rooms

Feature placement (all depths)

  • All positions via RNG, not hardcoded
  • Pool count: 2 + depth/2
  • Pool radius: 4-10 cells
  • Pool types by depth:
    • 1-3: water, sand
    • 4-6: lava, acid, water
    • 7+: acid (traps in rooms)
  • Tree count: 3-7 (surface only)
  • Wall count: 1-3 (surface only)

Files

File Change
src/world/worldgen.rs New module — all generation logic
src/world/mod.rs Add pub mod worldgen
src/game.rs init_world() calls WorldGenerator::generate()
tests/worldgen.rs New tests

Tests

  • Stairs exist after generation at any depth
  • At least 3 distinct materials present
  • Player spawn position is not inside solid
  • Different depths produce different structures
  • Depth 7+ has rooms (empty regions > 5x3)
  • CA caves are connected (flood fill test)

Implementation Order

  1. Create worldgen.rs with WorldGenerator struct and generate() dispatch
  2. Implement surface generation (depth 1-3) — move existing code, add RNG
  3. Implement CA cave generation (depth 4-6)
  4. Implement BSP dungeon generation (depth 7+)
  5. Integrate into game.rs::init_world()
  6. Write tests
  7. Run all tests + scenarios
  8. Push