From ba26fa4eb37e78b6dc47cb7f4e96733375e022fc Mon Sep 17 00:00:00 2001 From: alf9310 Date: Sun, 9 Nov 2025 17:12:15 -0500 Subject: dungeon_generation: added stair generation and fixed room center vs rabdom point recursion --- dungeon/src/bsp.rs | 41 ++++++++++++++++++++++++++++++----------- dungeon/tests/bsp_tests.rs | 14 ++++++++++++++ 2 files changed, 44 insertions(+), 11 deletions(-) (limited to 'dungeon') diff --git a/dungeon/src/bsp.rs b/dungeon/src/bsp.rs index f996405..9b288a2 100644 --- a/dungeon/src/bsp.rs +++ b/dungeon/src/bsp.rs @@ -17,7 +17,7 @@ const MAX_ROOM_SIZE: u16 = 12; /// The `Rect` type represents a rectangle inside the map (x,y,width,height). /// (x,y) is the top-left corner. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] struct Rect { x: u16, y: u16, @@ -34,13 +34,20 @@ impl Rect { fn center(&self) -> Pos { let cx = self.x + self.w / 2; let cy = self.y + self.h / 2; - Pos::new(cx as u16, cy as u16).unwrap_or(const_pos!(1, 1)) + Pos::new(cx, cy).unwrap_or(const_pos!(1, 1)) + } + + /// Returns a random point in this rectangle. + fn random_point(&self, rng: &mut R) -> Pos { + let rx = rng.random_range(self.x..(self.x + self.w)); + let ry = rng.random_range(self.y..(self.y + self.h)); + Pos::new(rx, ry).unwrap_or(self.center()) } } /// The `Node` type represents a node in the BSP tree. /// Has optional left and right children, and an optional room rectangle. -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, Eq)] struct Node { rect: Rect, // Area this node covers left: Option>, // Left child (if not leaf) @@ -207,19 +214,24 @@ impl Node { return right.room_center(); } // Fallback (should not happen) - const_pos!(1, 1) + panic!("No room found in subtree"); } - /// Return a point (x,y) on the border of the room in this node. + /// Return a random point for a room in this subtree: + /// if node has a room, return a randiom point in it, else try left then right. fn random_point_in_room(&self, rng: &mut R) -> Pos { + // Base case: if this node has a room, return a random point in it if let Some(room) = &self.room { - let rx = rng.random_range(room.x..(room.x + room.w)); - let ry = rng.random_range(room.y..(room.y + room.h)); - Pos::new(rx, ry).unwrap_or(self.rect.center()) - } else { - // No room: return center of rect - self.rect.center() + return room.random_point(rng); + } + if let Some(left) = &self.left { + return left.random_point_in_room(rng); } + if let Some(right) = &self.right { + return right.random_point_in_room(rng); + } + // Fallback (should not happen) + panic!("No room found in subtree"); } /// Connect rooms of child nodes recursively and collect corridors to carve. @@ -377,6 +389,13 @@ pub fn generate(seed: u64) -> (Box<[Tile; TILE_COUNT]>, Pos) { let player_start = player_room.room_center(); // Set one tile to Stairs (exit) in a random room different from player start + let mut exit_room = player_room; + while exit_room == player_room { + exit_room = leaves.choose(&mut rng).unwrap_or(&leaves[0]); + } + let exit_pos = exit_room.room_center(); + let exit_idx = exit_pos.xy().0 + exit_pos.xy().1 * MAP_SIZE; + tiles_box[exit_idx as usize] = Tile::Stairs; // Return tiles and player_start (tiles_box, player_start) diff --git a/dungeon/tests/bsp_tests.rs b/dungeon/tests/bsp_tests.rs index 2e3a781..6bd0153 100644 --- a/dungeon/tests/bsp_tests.rs +++ b/dungeon/tests/bsp_tests.rs @@ -3,6 +3,7 @@ mod tests { use dungeon::*; + /// Basic integration test for BSP generation #[test] fn test_bsp_integration() { let seed = 12345u64; @@ -12,4 +13,17 @@ mod tests { assert!(player_start.x() < map::MAP_SIZE); assert!(player_start.y() < map::MAP_SIZE); } + + /// Test that BSP-generated floors have a valid player start + #[test] + fn test_bsp_player_start() { + let seed = 12345u64; + let (tiles, player_start) = bsp::generate(seed); + // Ensure player start is within bounds + assert!(player_start.x() < map::MAP_SIZE); + assert!(player_start.y() < map::MAP_SIZE); + // Ensure player start is an air tile + let idx = player_start.idx(); + assert_eq!(tiles[idx], map::Tile::Air); + } } -- cgit v1.2.3-freya