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
129
130
131
132
133
134
135
|
//! Integration Tests for BSP dungeon generation
#[cfg(test)]
mod tests {
use dungeon::*;
use pos::Pos;
use rand::{Rng, SeedableRng, rngs::SmallRng};
/// Generate a set of test seeds for reproducibility with a seeded RNG
fn generate_test_seeds(seed: u64) -> Vec<u64> {
let mut rng = SmallRng::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 rng = SmallRng::seed_from_u64(seed);
let floor = bsp::generate(seed, rng);
// 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 rng = SmallRng::seed_from_u64(seed);
let floor = bsp::generate(seed, rng);
// 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 rng = SmallRng::seed_from_u64(seed);
let floor = bsp::generate(seed, rng);
// 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 rng = SmallRng::seed_from_u64(seed);
let floor = bsp::generate(seed, rng);
// 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 rng1 = SmallRng::seed_from_u64(seed);
let rng2 = SmallRng::seed_from_u64(seed);
let floor1 = bsp::generate(seed, rng1);
let floor2 = bsp::generate(seed, rng2);
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 rng = SmallRng::seed_from_u64(seed);
let floor = bsp::generate(seed, rng);
// 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}");
}
}
}
}
|