1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
//! Integration Tests for BSP dungeon generation
#[cfg(test)]
mod tests {
use dungeon::*;
use pos::Pos;
use rand::{Rng, SeedableRng};
/// Generate a set of test seeds for reproducibility with a seeded RNG
fn generate_test_seeds(seed: u64) -> Vec<u64> {
let mut rng = rand::rngs::StdRng::seed_from_u64(seed);
// Generate 100 random u64 seeds
(0..100).map(|_| rng.random_range(0..u64::MAX)).collect()
}
/// Basic integration test for BSP generation
#[test]
fn test_bsp_integration() {
let test_seeds = generate_test_seeds(123456);
for seed in test_seeds {
let floor = bsp::generate(seed);
// Basic integration test: ensure we get valid data
assert!(!floor.tiles().is_empty());
}
}
/// Test that BSP-generated floors have a valid player start
#[test]
fn test_bsp_player_start() {
let test_seeds = generate_test_seeds(654321);
for seed in test_seeds {
let floor = bsp::generate(seed);
// Ensure player start is a room tile
let start = floor.player_start();
assert_eq!(floor.get(start), map::Tile::Room);
}
}
/// Test that BSP-generated floors have at least one room tile
#[test]
fn test_bsp_2_or_more_rooms() {
let test_seeds = generate_test_seeds(111222);
for seed in test_seeds {
let floor = bsp::generate(seed);
// Ensure we have at least one room tile
let room_count = floor
.tiles()
.iter()
.filter(|&&tile| tile == map::Tile::Room)
.count();
assert!(
room_count >= 1,
"Expected at least one room tile, found {room_count}"
);
}
}
/// Test that BSP-generated floors have walls on the borders
#[test]
fn test_bsp_walls_on_borders() {
let test_seeds = generate_test_seeds(777888);
for seed in test_seeds {
let floor = bsp::generate(seed);
// Go through all tiles, and ensure border tiles are walls
for pos in Pos::values() {
if pos.is_border() {
assert_eq!(
floor.get(pos),
map::Tile::Wall,
"Expected wall at border position {pos:?}"
);
}
}
}
}
// Test that BSP-generated floors are reproducible with the same seed
#[test]
fn test_bsp_reproducibility() {
let test_seeds = generate_test_seeds(111111);
for seed in test_seeds {
let floor1 = bsp::generate(seed);
let floor2 = bsp::generate(seed);
assert_eq!(
floor1.tiles(),
floor2.tiles(),
"Tiles differ for same seed {seed}"
);
assert_eq!(
floor1.player_start(),
floor2.player_start(),
"Player starts differ for same seed {seed}"
);
}
}
// Test that all `air` tiles (`Tile::Room` and `Tile::Hallway`) are reachable from the player start
#[test]
fn test_bsp_all_air_tiles_reachable() {
let test_seeds = generate_test_seeds(333444);
for seed in test_seeds {
check_air_tiles_reachable(seed);
}
}
// Helper function to check that all air tiles are reachable from player start
fn check_air_tiles_reachable(seed: u64) {
let floor = bsp::generate(seed);
// BFS to find all reachable air tiles
let mut visited = vec![false; TILE_COUNT];
let mut queue = vec![floor.player_start()];
visited[floor.player_start().idx()] = true;
while let Some(pos) = queue.pop() {
for neighbor in pos.neighbors() {
let idx = neighbor.idx();
if !visited[idx] && floor.get(neighbor) != map::Tile::Wall {
visited[idx] = true;
queue.push(neighbor);
}
}
}
for (i, &tile) in floor.tiles().iter().enumerate() {
if tile == map::Tile::Room || tile == map::Tile::Hallway {
assert!(visited[i], "Unreachable air tile at index {i}");
}
}
}
}
|