work on level generation including tests
This commit is contained in:
parent
c429784775
commit
50d98bfb4d
|
@ -0,0 +1,5 @@
|
||||||
|
```
|
||||||
|
RUSTFLAGS="-Cinstrument-coverage" cargo clean
|
||||||
|
RUSTFLAGS="-Cinstrument-coverage" cargo test
|
||||||
|
grcov . --binary-path ./target/debug/deps/ -s . -t html --branch --ignore-not-existing --ignore '../*' --ignore "/*" -o target/coverage/html
|
||||||
|
```
|
|
@ -4,7 +4,7 @@ use crate::{monster::MonsterTypes, room::RoomType};
|
||||||
|
|
||||||
|
|
||||||
/// the number of rooms in vertical direction
|
/// the number of rooms in vertical direction
|
||||||
pub const ROOMS_HORIZONAL: usize = 8;
|
pub const ROOMS_HORIZONTAL: usize = 8;
|
||||||
/// the number of rooms in horizontal direction
|
/// the number of rooms in horizontal direction
|
||||||
pub const ROOMS_VERTICAL: usize = 7;
|
pub const ROOMS_VERTICAL: usize = 7;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ pub const MIN_WIDTH: u16 = 120;
|
||||||
pub const MIN_HEIGHT: u16 = LEVEL_HEIGHT as u16;
|
pub const MIN_HEIGHT: u16 = LEVEL_HEIGHT as u16;
|
||||||
|
|
||||||
/// the calculated width of a level
|
/// the calculated width of a level
|
||||||
pub const LEVEL_WIDTH: usize = 1 + ROOMS_HORIZONAL * ROOM_WIDTH;
|
pub const LEVEL_WIDTH: usize = 1 + ROOMS_HORIZONTAL * ROOM_WIDTH;
|
||||||
/// the calculated height of a level
|
/// the calculated height of a level
|
||||||
pub const LEVEL_HEIGHT: usize = 1 + ROOMS_VERTICAL * ROOM_HEIGHT;
|
pub const LEVEL_HEIGHT: usize = 1 + ROOMS_VERTICAL * ROOM_HEIGHT;
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ use crate::position::Position;
|
||||||
use crate::room::Connection;
|
use crate::room::Connection;
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{
|
constants::{
|
||||||
get_room_type_per_level, LEVEL_HEIGHT, LEVEL_WIDTH, ROOMS_HORIZONAL, ROOMS_VERTICAL,
|
get_room_type_per_level, LEVEL_HEIGHT, LEVEL_WIDTH, ROOMS_HORIZONTAL, ROOMS_VERTICAL,
|
||||||
},
|
},
|
||||||
level::{Level, StructureElement},
|
level::{Level, StructureElement},
|
||||||
room::{Room, RoomType},
|
room::{Room, RoomType},
|
||||||
|
@ -26,7 +26,7 @@ use crate::{
|
||||||
|
|
||||||
pub struct LevelGenerator {
|
pub struct LevelGenerator {
|
||||||
level: usize,
|
level: usize,
|
||||||
rooms: [[Room; ROOMS_VERTICAL]; ROOMS_HORIZONAL],
|
rooms: [[Room; ROOMS_VERTICAL]; ROOMS_HORIZONTAL],
|
||||||
rng: ThreadRng,
|
rng: ThreadRng,
|
||||||
}
|
}
|
||||||
enum Direction {
|
enum Direction {
|
||||||
|
@ -35,48 +35,56 @@ enum Direction {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LevelGenerator {
|
impl LevelGenerator {
|
||||||
pub fn generate(level: usize, first: bool, last: bool) -> Self {
|
pub fn generate_rooms_to_place(
|
||||||
let mut rng = rand::thread_rng();
|
rng: &mut ThreadRng,
|
||||||
let mut rooms = [[Room::new(&mut rng); ROOMS_VERTICAL]; ROOMS_HORIZONAL];
|
level: usize,
|
||||||
|
first: bool,
|
||||||
|
last: bool,
|
||||||
|
) -> Vec<Room> {
|
||||||
|
let mut rooms_to_place: Vec<Room> = Vec::with_capacity(ROOMS_VERTICAL * ROOMS_HORIZONTAL);
|
||||||
|
|
||||||
/*
|
let mut start_room = Room::new(rng);
|
||||||
Fill grid with unconnected rooms
|
|
||||||
*/
|
|
||||||
|
|
||||||
let mut rooms_to_place: Vec<Room> = Vec::with_capacity(ROOMS_VERTICAL * ROOMS_HORIZONAL);
|
|
||||||
|
|
||||||
let mut start_room = Room::new(&mut rng);
|
|
||||||
if first {
|
if first {
|
||||||
start_room.kind = RoomType::Start;
|
start_room.kind = RoomType::Start;
|
||||||
} else {
|
} else {
|
||||||
start_room.kind = RoomType::StairUp;
|
start_room.kind = RoomType::StairUp;
|
||||||
}
|
}
|
||||||
rooms_to_place.push(start_room);
|
rooms_to_place.push(start_room);
|
||||||
let mut end_room = Room::new(&mut rng);
|
for _ in 2..ROOMS_HORIZONTAL * ROOMS_VERTICAL {
|
||||||
|
let mut room = Room::new(rng);
|
||||||
|
room.kind = LevelGenerator::select_room_type(level, rng);
|
||||||
|
if room.kind != RoomType::EmptyRoom {
|
||||||
|
rooms_to_place.push(room);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut end_room = Room::new(rng);
|
||||||
if last {
|
if last {
|
||||||
end_room.kind = RoomType::End;
|
end_room.kind = RoomType::End;
|
||||||
} else {
|
} else {
|
||||||
end_room.kind = RoomType::StairDown;
|
end_room.kind = RoomType::StairDown;
|
||||||
}
|
}
|
||||||
rooms_to_place.push(end_room);
|
rooms_to_place.push(end_room);
|
||||||
for _ in 2..ROOMS_HORIZONAL * ROOMS_VERTICAL {
|
rooms_to_place
|
||||||
let mut room = Room::new(&mut rng);
|
|
||||||
room.kind = LevelGenerator::select_room_type(level, &mut rng);
|
|
||||||
if room.kind != RoomType::EmptyRoom {
|
|
||||||
rooms_to_place.push(room);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
let mut room_row = rng.gen_range(1..ROOMS_VERTICAL);
|
pub fn place_rooms(
|
||||||
let mut room_col = rng.gen_range(1..ROOMS_HORIZONAL);
|
rng: &mut ThreadRng,
|
||||||
|
rooms_to_place: &mut Vec<Room>,
|
||||||
|
) -> [[Room; ROOMS_VERTICAL]; ROOMS_HORIZONTAL] {
|
||||||
|
let mut rooms: [[Room; 7]; 8] = [[Room::new(rng); ROOMS_VERTICAL]; ROOMS_HORIZONTAL];
|
||||||
|
let mut room_row = rng.gen_range(0..ROOMS_VERTICAL);
|
||||||
|
let mut room_col = rng.gen_range(0..ROOMS_HORIZONTAL);
|
||||||
rooms[room_col][room_row] = rooms_to_place.pop().unwrap();
|
rooms[room_col][room_row] = rooms_to_place.pop().unwrap();
|
||||||
while let Some(room) = rooms_to_place.pop() {
|
while let Some(room) = rooms_to_place.pop() {
|
||||||
|
let mut placed = false;
|
||||||
|
// randomize going horizontal or vertical
|
||||||
let mut directions_to_try = vec![Direction::Horizontal, Direction::Vertical];
|
let mut directions_to_try = vec![Direction::Horizontal, Direction::Vertical];
|
||||||
directions_to_try.shuffle(&mut rng);
|
directions_to_try.shuffle(rng);
|
||||||
while !directions_to_try.is_empty() {
|
while !directions_to_try.is_empty() {
|
||||||
match directions_to_try.pop().unwrap() {
|
match directions_to_try.pop().unwrap() {
|
||||||
Direction::Horizontal => {
|
Direction::Horizontal => {
|
||||||
let mut free_cols: Vec<usize> = vec![];
|
let mut free_cols: Vec<usize> = vec![];
|
||||||
for col in 0..ROOMS_HORIZONAL {
|
for col in 0..ROOMS_HORIZONTAL {
|
||||||
if rooms[col][room_row].kind == RoomType::EmptyRoom {
|
if rooms[col][room_row].kind == RoomType::EmptyRoom {
|
||||||
free_cols.push(col);
|
free_cols.push(col);
|
||||||
}
|
}
|
||||||
|
@ -84,9 +92,10 @@ impl LevelGenerator {
|
||||||
if free_cols.is_empty() {
|
if free_cols.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
free_cols.shuffle(&mut rng);
|
free_cols.shuffle(rng);
|
||||||
room_col = *free_cols.first().unwrap();
|
room_col = *free_cols.first().unwrap();
|
||||||
rooms[room_col][room_row] = room;
|
rooms[room_col][room_row] = room;
|
||||||
|
placed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Direction::Vertical => {
|
Direction::Vertical => {
|
||||||
|
@ -99,54 +108,50 @@ impl LevelGenerator {
|
||||||
if free_rows.is_empty() {
|
if free_rows.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
free_rows.shuffle(&mut rng);
|
free_rows.shuffle(rng);
|
||||||
room_row = *free_rows.first().unwrap();
|
room_row = *free_rows.first().unwrap();
|
||||||
rooms[room_col][room_row] = room;
|
rooms[room_col][room_row] = room;
|
||||||
|
placed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all fields in the row/column was full so we can place it at any empty position
|
||||||
|
if !placed {
|
||||||
|
let mut free_pos: Vec<(usize, usize)> = vec![];
|
||||||
|
for col in 0..ROOMS_HORIZONTAL {
|
||||||
|
for row in 0..ROOMS_VERTICAL {
|
||||||
|
if rooms[col][row].kind == RoomType::EmptyRoom {
|
||||||
|
free_pos.push((col, row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let selected_pos = free_pos[rng.gen_range(0..free_pos.len())];
|
||||||
|
rooms[selected_pos.0][selected_pos.1] = room;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rooms
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug print a text view of the dungeon
|
pub fn create_mst(
|
||||||
println!(" 0 1 2 3 4 5 6 7");
|
rooms: &[[Room; ROOMS_VERTICAL]; ROOMS_HORIZONTAL],
|
||||||
for r in 0..ROOMS_VERTICAL {
|
) -> Graph<(usize, usize), u16, petgraph::Undirected> {
|
||||||
print!("{} ", r);
|
|
||||||
for c in 0..ROOMS_HORIZONAL {
|
|
||||||
match rooms[c][r].kind {
|
|
||||||
RoomType::Start => print!("S "),
|
|
||||||
RoomType::End => print!("E "),
|
|
||||||
RoomType::StairUp => print!("< "),
|
|
||||||
RoomType::StairDown => print!("> "),
|
|
||||||
RoomType::BasicRoom => print!("B "),
|
|
||||||
RoomType::ArtifactRoom => print!("A "),
|
|
||||||
RoomType::MonsterRoom => print!("M "),
|
|
||||||
RoomType::EmptyRoom => print!(" "),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
println!();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Construct a graph from the unconnected rooms and make a minum spanning tree of it
|
|
||||||
*/
|
|
||||||
let mut graph = UnGraph::<(usize, usize), u16>::default();
|
let mut graph = UnGraph::<(usize, usize), u16>::default();
|
||||||
// collect nodes
|
for col in 0..ROOMS_HORIZONTAL {
|
||||||
for col in 0..ROOMS_HORIZONAL {
|
|
||||||
for row in 0..ROOMS_VERTICAL {
|
for row in 0..ROOMS_VERTICAL {
|
||||||
if rooms[col][row].kind != RoomType::EmptyRoom {
|
if rooms[col][row].kind != RoomType::EmptyRoom {
|
||||||
graph.add_node((col, row));
|
graph.add_node((col, row));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// collect edges between nodes, each right and down till we find the next room
|
for col in 0..ROOMS_HORIZONTAL {
|
||||||
for col in 0..ROOMS_HORIZONAL {
|
|
||||||
for row in 0..ROOMS_VERTICAL {
|
for row in 0..ROOMS_VERTICAL {
|
||||||
if rooms[col][row].kind == RoomType::EmptyRoom {
|
if rooms[col][row].kind == RoomType::EmptyRoom {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(src_index) = graph.node_indices().find(|i| graph[*i] == (col, row)) {
|
if let Some(src_index) = graph.node_indices().find(|i| graph[*i] == (col, row)) {
|
||||||
for col_1 in col + 1..ROOMS_HORIZONAL {
|
for col_1 in col + 1..ROOMS_HORIZONTAL {
|
||||||
if rooms[col_1][row].kind != RoomType::EmptyRoom {
|
if rooms[col_1][row].kind != RoomType::EmptyRoom {
|
||||||
if let Some(tgt_index) =
|
if let Some(tgt_index) =
|
||||||
graph.node_indices().find(|i| graph[*i] == (col_1, row))
|
graph.node_indices().find(|i| graph[*i] == (col_1, row))
|
||||||
|
@ -169,8 +174,46 @@ impl LevelGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mst: Graph<(usize, usize), u16, petgraph::Undirected> =
|
Graph::from_elements(min_spanning_tree(&graph))
|
||||||
Graph::from_elements(min_spanning_tree(&graph));
|
// graph
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate(level: usize, first: bool, last: bool) -> Self {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fill grid with unconnected rooms
|
||||||
|
*/
|
||||||
|
|
||||||
|
let mut rooms_to_place: Vec<Room> =
|
||||||
|
LevelGenerator::generate_rooms_to_place(&mut rng, level, first, last);
|
||||||
|
let mut rooms: [[Room; 7]; 8] = LevelGenerator::place_rooms(&mut rng, &mut rooms_to_place);
|
||||||
|
|
||||||
|
// debug print a text view of the dungeon
|
||||||
|
println!(" 0 1 2 3 4 5 6 7");
|
||||||
|
for r in 0..ROOMS_VERTICAL {
|
||||||
|
print!("{} ", r);
|
||||||
|
for c in 0..ROOMS_HORIZONTAL {
|
||||||
|
match rooms[c][r].kind {
|
||||||
|
RoomType::Start => print!("S "),
|
||||||
|
RoomType::End => print!("E "),
|
||||||
|
RoomType::StairUp => print!("< "),
|
||||||
|
RoomType::StairDown => print!("> "),
|
||||||
|
RoomType::BasicRoom => print!("_ "),
|
||||||
|
RoomType::ArtifactRoom => print!("A "),
|
||||||
|
RoomType::MonsterRoom => print!("M "),
|
||||||
|
RoomType::EmptyRoom => print!(" "),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Construct a graph from the unconnected rooms and make a minum spanning tree of it
|
||||||
|
*/
|
||||||
|
|
||||||
|
let mst: Graph<(usize, usize), u16, petgraph::Undirected> =LevelGenerator::create_mst(&rooms);
|
||||||
|
|
||||||
for edge in mst.raw_edges() {
|
for edge in mst.raw_edges() {
|
||||||
// the tuples are (col, row)
|
// the tuples are (col, row)
|
||||||
let (src_node_col, src_node_row) = mst[edge.source()];
|
let (src_node_col, src_node_row) = mst[edge.source()];
|
||||||
|
@ -200,11 +243,7 @@ impl LevelGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LevelGenerator {
|
LevelGenerator { level, rooms, rng }
|
||||||
level,
|
|
||||||
rooms,
|
|
||||||
rng,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_monster(position: Position, rng: &mut ThreadRng) -> Box<dyn Monster> {
|
fn select_monster(position: Position, rng: &mut ThreadRng) -> Box<dyn Monster> {
|
||||||
|
@ -242,39 +281,41 @@ impl LevelGenerator {
|
||||||
let mut end_pos = (0, 0);
|
let mut end_pos = (0, 0);
|
||||||
let mut monsters: Vec<Box<dyn Monster>> = Vec::with_capacity(10);
|
let mut monsters: Vec<Box<dyn Monster>> = Vec::with_capacity(10);
|
||||||
let mut artifacts: Vec<Box<dyn Artifact>> = Vec::with_capacity(10);
|
let mut artifacts: Vec<Box<dyn Artifact>> = Vec::with_capacity(10);
|
||||||
for col in 0..ROOMS_HORIZONAL {
|
for col in 0..ROOMS_HORIZONTAL {
|
||||||
for row in 0..ROOMS_VERTICAL {
|
for row in 0..ROOMS_VERTICAL {
|
||||||
let room = self.rooms[col][row];
|
let room = self.rooms[col][row];
|
||||||
let position = room.render(&mut structure, col, row);
|
let position = room.render(&mut structure, col, row);
|
||||||
match room.kind {
|
match room.kind {
|
||||||
RoomType::Start => {start_pos=position},
|
RoomType::Start => start_pos = position,
|
||||||
RoomType::End => {end_pos=position},
|
RoomType::End => end_pos = position,
|
||||||
RoomType::StairUp => {start_pos=position},
|
RoomType::StairUp => start_pos = position,
|
||||||
RoomType::StairDown => {end_pos=position},
|
RoomType::StairDown => end_pos = position,
|
||||||
RoomType::BasicRoom => {},
|
RoomType::BasicRoom => {}
|
||||||
RoomType::ArtifactRoom => {
|
RoomType::ArtifactRoom => {
|
||||||
match self.rng.gen_range(1..=100) {
|
match self.rng.gen_range(1..=100) {
|
||||||
1..=50 => {
|
1..=50 => {
|
||||||
artifacts
|
artifacts.push(Box::new(Chest::new(Position::new(
|
||||||
.push(Box::new(Chest::new(Position::new(self.level, position.0, position.1))));
|
self.level, position.0, position.1,
|
||||||
|
))));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
artifacts
|
artifacts.push(Box::new(Potion::new(Position::new(
|
||||||
.push(Box::new(Potion::new(Position::new(self.level, position.0, position.1))));
|
self.level, position.0, position.1,
|
||||||
|
))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
RoomType::MonsterRoom => {
|
RoomType::MonsterRoom => {
|
||||||
monsters.push(LevelGenerator::select_monster(
|
monsters.push(LevelGenerator::select_monster(
|
||||||
Position::new(self.level, position.0, position.1),
|
Position::new(self.level, position.0, position.1),
|
||||||
&mut self.rng,
|
&mut self.rng,
|
||||||
));
|
));
|
||||||
},
|
}
|
||||||
RoomType::EmptyRoom => {},
|
RoomType::EmptyRoom => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for col in 0..ROOMS_HORIZONAL {
|
for col in 0..ROOMS_HORIZONTAL {
|
||||||
for row in 0..ROOMS_VERTICAL {
|
for row in 0..ROOMS_VERTICAL {
|
||||||
if let Some(connection) = self.rooms[col][row].connection_down {
|
if let Some(connection) = self.rooms[col][row].connection_down {
|
||||||
// println!("down");
|
// println!("down");
|
||||||
|
@ -299,17 +340,201 @@ impl LevelGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_level_gen() {
|
||||||
|
// for _ in 0..1000 {
|
||||||
|
// LevelGenerator::generate(0, true, false).render();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_level_gen_respects_level() {
|
||||||
|
// let level = LevelGenerator::generate(0, true, false).render();
|
||||||
|
// assert_eq!(0, level.level);
|
||||||
|
// let level = LevelGenerator::generate(1, true, false).render();
|
||||||
|
// assert_eq!(1, level.level);
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn find_room_types(rooms: &Vec<Room>) -> (bool, bool, bool, bool) {
|
||||||
|
let mut start_found = false;
|
||||||
|
let mut end_found: bool = false;
|
||||||
|
let mut down_found: bool = false;
|
||||||
|
let mut up_found: bool = false;
|
||||||
|
for room in rooms {
|
||||||
|
if room.kind == RoomType::Start {
|
||||||
|
start_found = true;
|
||||||
|
}
|
||||||
|
if room.kind == RoomType::End {
|
||||||
|
end_found = true;
|
||||||
|
}
|
||||||
|
if room.kind == RoomType::StairDown {
|
||||||
|
down_found = true;
|
||||||
|
}
|
||||||
|
if room.kind == RoomType::StairUp {
|
||||||
|
up_found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(start_found, up_found, down_found, end_found)
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_level_gen() {
|
fn test_rooms_to_place_first_level() {
|
||||||
for _ in 0..1000 {
|
let mut rng = rand::thread_rng();
|
||||||
LevelGenerator::generate(0, true, false).render();
|
let res = LevelGenerator::generate_rooms_to_place(&mut rng, 0, true, false);
|
||||||
|
assert!(
|
||||||
|
res.len() <= ROOMS_HORIZONTAL * ROOMS_VERTICAL,
|
||||||
|
"too many rooms created"
|
||||||
|
);
|
||||||
|
assert!(0 < res.len(), "too many rooms created");
|
||||||
|
|
||||||
|
let (start_found, up_found, down_found, end_found) = find_room_types(&res);
|
||||||
|
assert!(start_found);
|
||||||
|
assert!(!end_found);
|
||||||
|
assert!(down_found);
|
||||||
|
assert!(!up_found);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rooms_to_place_middle_level() {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let res = LevelGenerator::generate_rooms_to_place(&mut rng, 1, false, false);
|
||||||
|
assert!(
|
||||||
|
res.len() <= ROOMS_HORIZONTAL * ROOMS_VERTICAL,
|
||||||
|
"too many rooms created"
|
||||||
|
);
|
||||||
|
assert!(0 < res.len(), "too many rooms created");
|
||||||
|
|
||||||
|
let (start_found, up_found, down_found, end_found) = find_room_types(&res);
|
||||||
|
assert!(!start_found);
|
||||||
|
assert!(!end_found);
|
||||||
|
assert!(down_found);
|
||||||
|
assert!(up_found);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rooms_to_place_last_level() {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let res = LevelGenerator::generate_rooms_to_place(&mut rng, 2, false, true);
|
||||||
|
assert!(
|
||||||
|
res.len() <= ROOMS_HORIZONTAL * ROOMS_VERTICAL,
|
||||||
|
"too many rooms created"
|
||||||
|
);
|
||||||
|
assert!(0 < res.len(), "too many rooms created");
|
||||||
|
|
||||||
|
let (start_found, up_found, down_found, end_found) = find_room_types(&res);
|
||||||
|
assert!(!start_found);
|
||||||
|
assert!(end_found);
|
||||||
|
assert!(!down_found);
|
||||||
|
assert!(up_found);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn check_valid_placement(rooms: &[[Room; ROOMS_VERTICAL]; ROOMS_HORIZONTAL]) -> bool {
|
||||||
|
for col in 0..ROOMS_HORIZONTAL {
|
||||||
|
for row in 0..ROOMS_VERTICAL {
|
||||||
|
if rooms[col][row].kind != RoomType::EmptyRoom {
|
||||||
|
let mut count = 0;
|
||||||
|
for test_col in 0..ROOMS_HORIZONTAL {
|
||||||
|
if rooms[test_col][row].kind != RoomType::EmptyRoom {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for test_row in 0..ROOMS_VERTICAL {
|
||||||
|
if rooms[col][test_row].kind != RoomType::EmptyRoom {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count < 3 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn count_rooms(rooms: &[[Room; ROOMS_VERTICAL]; ROOMS_HORIZONTAL]) -> usize {
|
||||||
|
let mut res = 0;
|
||||||
|
for col in 0..ROOMS_HORIZONTAL {
|
||||||
|
for row in 0..ROOMS_VERTICAL {
|
||||||
|
if rooms[col][row].kind != RoomType::EmptyRoom {
|
||||||
|
res += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_place_rooms() {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
for count in 2..ROOMS_HORIZONTAL * ROOMS_VERTICAL {
|
||||||
|
let mut rooms: Vec<Room> = vec![Room::new(&mut rng), Room::new(&mut rng)];
|
||||||
|
rooms[0].kind = RoomType::Start;
|
||||||
|
rooms[1].kind = RoomType::End;
|
||||||
|
for t in 2..count {
|
||||||
|
rooms.push(Room::new(&mut rng));
|
||||||
|
rooms[t].kind = RoomType::BasicRoom;
|
||||||
|
}
|
||||||
|
let res = LevelGenerator::place_rooms(&mut rng, &mut rooms);
|
||||||
|
|
||||||
|
assert_eq!(count_rooms(&res), count, "counting {}", count);
|
||||||
|
assert!(check_valid_placement(&res));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_level_gen_respects_level() {
|
fn test_create_mst() {
|
||||||
let level = LevelGenerator::generate(0, true, false).render();
|
let mut rng = rand::thread_rng();
|
||||||
assert_eq!(0, level.level);
|
let mut rooms = [[Room::new(&mut rng); ROOMS_VERTICAL]; ROOMS_HORIZONTAL];
|
||||||
let level = LevelGenerator::generate(1, true, false).render();
|
let res = LevelGenerator::create_mst(&rooms);
|
||||||
assert_eq!(1, level.level);
|
assert_eq!(res.node_count(), 0);
|
||||||
|
assert_eq!(res.edge_count(), 0);
|
||||||
|
|
||||||
|
rooms[1][1].kind = RoomType::BasicRoom;
|
||||||
|
let res = LevelGenerator::create_mst(&rooms);
|
||||||
|
assert_eq!(res.node_count(), 1);
|
||||||
|
assert_eq!(res.edge_count(), 0);
|
||||||
|
|
||||||
|
rooms[1][3].kind = RoomType::BasicRoom;
|
||||||
|
let res = LevelGenerator::create_mst(&rooms);
|
||||||
|
assert_eq!(res.node_count(), 2);
|
||||||
|
assert_eq!(res.edge_count(), 1);
|
||||||
|
|
||||||
|
rooms[3][1].kind = RoomType::BasicRoom;
|
||||||
|
let res = LevelGenerator::create_mst(&rooms);
|
||||||
|
assert_eq!(res.node_count(), 3);
|
||||||
|
assert_eq!(res.edge_count(), 2);
|
||||||
|
|
||||||
|
rooms[3][3].kind = RoomType::BasicRoom;
|
||||||
|
let res = LevelGenerator::create_mst(&rooms);
|
||||||
|
assert_eq!(res.node_count(), 4);
|
||||||
|
assert_eq!(res.edge_count(), 3);
|
||||||
|
|
||||||
|
rooms[3][5].kind = RoomType::BasicRoom;
|
||||||
|
let res = LevelGenerator::create_mst(&rooms);
|
||||||
|
assert_eq!(res.node_count(), 5);
|
||||||
|
assert_eq!(res.edge_count(), 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
println!(" 0 1 2 3 4 5 6 7");
|
||||||
|
for r in 0..ROOMS_VERTICAL {
|
||||||
|
print!("{} ", r);
|
||||||
|
for c in 0..ROOMS_HORIZONTAL {
|
||||||
|
match res[c][r].kind {
|
||||||
|
RoomType::Start => print!("S "),
|
||||||
|
RoomType::End => print!("E "),
|
||||||
|
RoomType::StairUp => print!("< "),
|
||||||
|
RoomType::StairDown => print!("> "),
|
||||||
|
RoomType::BasicRoom => print!("_ "),
|
||||||
|
RoomType::ArtifactRoom => print!("A "),
|
||||||
|
RoomType::MonsterRoom => print!("M "),
|
||||||
|
RoomType::EmptyRoom => print!(" "),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
*/
|
||||||
|
|
Loading…
Reference in New Issue