feat(core): richer default dungeon — denser rooms + loop edges
Default was a pure MST (extra_edge_ratio 0.0), which reads as a linear chain of rooms. Retune DungeonConfig::default to min_leaf 8 / max_depth 5, rooms 5..=11, and extra_edge_ratio 0.30 — ~17 interconnected rooms with loops. Validation inequality still holds (8 - 2 >= 5); boundary test now uses an explicit edge-case config since the default no longer sits on it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5f195fdb0b
commit
ab195306a5
1 changed files with 44 additions and 14 deletions
|
|
@ -63,21 +63,35 @@ pub struct DungeonConfig {
|
|||
}
|
||||
|
||||
impl Default for DungeonConfig {
|
||||
/// A recognizable multi-room dungeon: a 64×40 canvas with each pass at its
|
||||
/// own sensible default.
|
||||
/// A recognizable, interconnected multi-room dungeon on a 64×40 canvas.
|
||||
///
|
||||
/// The per-pass defaults are mutually consistent: with `bsp.min_leaf = 6`,
|
||||
/// `rooms.margin = 1`, and `rooms.min_size = 4`, the smallest possible leaf
|
||||
/// (6 cells on a side) deflates to a 4×4 interior — exactly `min_size` — so
|
||||
/// every leaf carves a room and none is skipped (the inequality
|
||||
/// `min_leaf - 2*margin >= min_size` holds: `6 - 2 >= 4`).
|
||||
/// The recipe deliberately picks a richer flavor than the passes' own
|
||||
/// primitive defaults: a denser partition with larger rooms (`min_leaf 8`,
|
||||
/// `max_depth 5`, rooms `5..=11`) yields ~15–18 rooms, and
|
||||
/// `extra_edge_ratio 0.30` adds loop edges so the connectivity graph isn't a
|
||||
/// strict tree — a pure MST (the `ConnectConfig` primitive default) reads as a
|
||||
/// linear chain of rooms, which is duller to explore. `door_chance` stays at
|
||||
/// 0.5 (an even mix of doors and open archways).
|
||||
///
|
||||
/// These stay consistent so RoomCarver never skips a leaf: the validation
|
||||
/// inequality `min_leaf - 2*margin >= min_size` holds with room to spare
|
||||
/// (`8 - 2 >= 5`). See [`validate`](DungeonConfig::validate).
|
||||
fn default() -> Self {
|
||||
DungeonConfig {
|
||||
width: 64,
|
||||
height: 40,
|
||||
bsp: BspConfig::default(),
|
||||
rooms: RoomConfig::default(),
|
||||
connect: ConnectConfig::default(),
|
||||
bsp: BspConfig {
|
||||
min_leaf: 8,
|
||||
max_depth: 5,
|
||||
},
|
||||
rooms: RoomConfig {
|
||||
min_size: 5,
|
||||
max_size: 11,
|
||||
margin: 1,
|
||||
},
|
||||
connect: ConnectConfig {
|
||||
extra_edge_ratio: 0.30,
|
||||
},
|
||||
doors: DoorConfig::default(),
|
||||
}
|
||||
}
|
||||
|
|
@ -400,12 +414,28 @@ mod tests {
|
|||
assert_eq!(dungeon(cfg).err(), Some(ConfigError::RoomLargerThanLeaf));
|
||||
}
|
||||
|
||||
/// The exact boundary of the inequality is accepted: `min_leaf - 2*margin ==
|
||||
/// min_size` is fine (the default config sits right on this edge).
|
||||
/// The exact boundary of the inequality is accepted: a config where
|
||||
/// `min_leaf - 2*margin == min_size` (the tightest legal fit) validates Ok,
|
||||
/// guarding the `>=` (not `>`) in the check. The shipped default sits safely
|
||||
/// inside this bound (`8 - 2 >= 5`), so we build a boundary config explicitly.
|
||||
#[test]
|
||||
fn boundary_config_is_accepted() {
|
||||
// 6 - 2*1 == 4 == min_size: must be Ok.
|
||||
assert!(DungeonConfig::default().validate().is_ok());
|
||||
// 6 - 2*1 == 4 == min_size: exactly on the edge, must be Ok.
|
||||
let boundary = DungeonConfig {
|
||||
bsp: BspConfig {
|
||||
min_leaf: 6,
|
||||
max_depth: 4,
|
||||
},
|
||||
rooms: RoomConfig {
|
||||
min_size: 4,
|
||||
max_size: 10,
|
||||
margin: 1,
|
||||
},
|
||||
..DungeonConfig::default()
|
||||
};
|
||||
assert!(boundary.validate().is_ok());
|
||||
assert!(dungeon(boundary).is_ok());
|
||||
// The shipped default validates too.
|
||||
assert!(dungeon(DungeonConfig::default()).is_ok());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue