diff --git a/.gitignore b/.gitignore index ea8c4bf..6b3e392 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +*.profraw diff --git a/coverage.md b/coverage.md index 6c31b8b..a1c9a47 100644 --- a/coverage.md +++ b/coverage.md @@ -1,3 +1,8 @@ +``` +cargo install grcov +rustup component add llvm-tools-preview +``` + ``` RUSTFLAGS="-Cinstrument-coverage" cargo clean RUSTFLAGS="-Cinstrument-coverage" cargo test diff --git a/src/level_generator.rs b/src/level_generator.rs index e5b9cad..6b28d12 100644 --- a/src/level_generator.rs +++ b/src/level_generator.rs @@ -35,7 +35,7 @@ enum Direction { } impl LevelGenerator { - pub fn generate_rooms_to_place( + fn generate_rooms_to_place( rng: &mut ThreadRng, level: usize, first: bool, @@ -67,7 +67,7 @@ impl LevelGenerator { rooms_to_place } - pub fn place_rooms( + fn place_rooms( rng: &mut ThreadRng, rooms_to_place: &mut Vec, ) -> [[Room; ROOMS_VERTICAL]; ROOMS_HORIZONTAL] { @@ -134,7 +134,7 @@ impl LevelGenerator { rooms } - pub fn create_mst( + fn create_mst( rooms: &[[Room; ROOMS_VERTICAL]; ROOMS_HORIZONTAL], ) -> Graph<(usize, usize), u16, petgraph::Undirected> { let mut graph = UnGraph::<(usize, usize), u16>::default(); @@ -178,6 +178,45 @@ impl LevelGenerator { // graph } + fn create_connections( + rooms: &mut [[Room; ROOMS_VERTICAL]; ROOMS_HORIZONTAL], + mst: &Graph<(usize, usize), u16, petgraph::Undirected>, + ) { + for edge in mst.raw_edges() { + // the tuples are (col, row) + let (src_node_col, src_node_row) = mst[edge.source()]; + let (tgt_node_col, tgt_node_row) = mst[edge.target()]; + let src_room = rooms[src_node_col][src_node_row]; + let tgt_room = rooms[tgt_node_col][tgt_node_row]; + + if src_node_col == tgt_node_col { + let start_col = + src_node_col * ROOM_WIDTH + src_room.offset_x + (src_room.width + 1) / 2; + let start_row = + src_node_row * ROOM_HEIGHT + src_room.offset_y + src_room.height + 1; + let end_col = + tgt_node_col * ROOM_WIDTH + tgt_room.offset_x + (tgt_room.width + 1) / 2; + let end_row = tgt_node_row * ROOM_HEIGHT - 1 + tgt_room.offset_y; + rooms[src_node_col][src_node_row].connection_down = Some(Connection { + start_pos: (start_col, start_row), + end_pos: (end_col, end_row), + }); + } else { + // println!("Right"); + let start_col = src_node_col * ROOM_WIDTH + src_room.offset_x + src_room.width; + let start_row = + src_node_row * ROOM_HEIGHT + src_room.offset_y + (src_room.height + 1) / 2; + let end_col = tgt_node_col * ROOM_WIDTH -1 + tgt_room.offset_x; + let end_row = + tgt_node_row * ROOM_HEIGHT + tgt_room.offset_y + (tgt_room.height + 1) / 2; + rooms[src_node_col][src_node_row].connection_right = Some(Connection { + start_pos: (start_col, start_row), + end_pos: (end_col, end_row), + }); + } + } + } + pub fn generate(level: usize, first: bool, last: bool) -> Self { let mut rng = rand::thread_rng(); @@ -211,38 +250,11 @@ impl LevelGenerator { /* 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() { - // the tuples are (col, row) - let (src_node_col, src_node_row) = mst[edge.source()]; - let (tgt_node_col, tgt_node_row) = mst[edge.target()]; - // println!("MST Edge from {:?} to {:?}", (src_node_col, src_node_row), (tgt_node_col, tgt_node_row)); - if src_node_col == tgt_node_col { - // println!("Down"); - let start_col = src_node_col * ROOM_WIDTH + ROOM_WIDTH / 2; - let start_row = src_node_row * ROOM_HEIGHT + ROOM_HEIGHT; - let end_col = tgt_node_col * ROOM_WIDTH + ROOM_WIDTH / 2; - let end_row = tgt_node_row * ROOM_HEIGHT; - rooms[src_node_col][src_node_row].connection_down = Some(Connection { - start_pos: (start_col, start_row), - end_pos: (end_col, end_row), - }); - } else { - // println!("Right"); - let start_col = src_node_col * ROOM_WIDTH + ROOM_WIDTH; - let start_row = src_node_row * ROOM_HEIGHT + ROOM_HEIGHT / 2; - let end_col = tgt_node_col * ROOM_WIDTH; - let end_row = tgt_node_row * ROOM_HEIGHT + ROOM_HEIGHT / 2; - rooms[src_node_col][src_node_row].connection_right = Some(Connection { - start_pos: (start_col, start_row), - end_pos: (end_col, end_row), - }); - } - } + let mst: Graph<(usize, usize), u16, petgraph::Undirected> = + LevelGenerator::create_mst(&rooms); + LevelGenerator::create_connections(&mut rooms, &mst); LevelGenerator { level, rooms, rng } } @@ -488,7 +500,7 @@ fn test_place_rooms() { fn test_create_mst() { let mut rng = rand::thread_rng(); let mut rooms = [[Room::new(&mut rng); ROOMS_VERTICAL]; ROOMS_HORIZONTAL]; - let res = LevelGenerator::create_mst(&rooms); + let res: Graph<(usize, usize), u16, petgraph::Undirected> = LevelGenerator::create_mst(&rooms); assert_eq!(res.node_count(), 0); assert_eq!(res.edge_count(), 0); @@ -518,6 +530,285 @@ fn test_create_mst() { assert_eq!(res.edge_count(), 4); } +#[test] +fn test_create_connections_down_1() { + // test full sized rooms for downwards connection + let mut rng = rand::thread_rng(); + let mut rooms = [[Room::new(&mut rng); ROOMS_VERTICAL]; ROOMS_HORIZONTAL]; + rooms[1][1].width = ROOM_WIDTH - 1; + rooms[1][1].offset_x = 0; + rooms[1][1].height = ROOM_HEIGHT - 1; + rooms[1][1].offset_y = 0; + rooms[1][1].kind = RoomType::BasicRoom; + + rooms[1][3].width = ROOM_WIDTH - 1; + rooms[1][3].offset_x = 0; + rooms[1][3].height = ROOM_HEIGHT - 1; + rooms[1][3].offset_y = 0; + rooms[1][3].kind = RoomType::BasicRoom; + let mst: Graph<(usize, usize), u16, petgraph::Undirected> = LevelGenerator::create_mst(&rooms); + LevelGenerator::create_connections(&mut rooms, &mst); + + assert!(rooms[1][1].connection_down.is_some()); + assert_eq!( + rooms[1][1].connection_down.unwrap().start_pos, + (ROOM_WIDTH + ROOM_WIDTH / 2, ROOM_HEIGHT * 2), + "wrong start" + ); + assert_eq!( + rooms[1][1].connection_down.unwrap().end_pos, + (ROOM_WIDTH + ROOM_WIDTH / 2, ROOM_HEIGHT * 3 - 1), + "wrong end" + ); + assert!(rooms[1][1].connection_right.is_none()); + assert!(rooms[1][2].connection_down.is_none()); + assert!(rooms[1][2].connection_right.is_none()); +} + +#[test] +fn test_create_connections_down_2() { + // test reduced width rooms (with overlap) for downwards connection + let mut rng = rand::thread_rng(); + let mut rooms = [[Room::new(&mut rng); ROOMS_VERTICAL]; ROOMS_HORIZONTAL]; + rooms[1][1].width = 5; + rooms[1][1].offset_x = 0; + rooms[1][1].height = ROOM_HEIGHT - 1; + rooms[1][1].offset_y = 0; + rooms[1][1].kind = RoomType::BasicRoom; + + rooms[1][3].width = 5; + rooms[1][3].offset_x = 4; + rooms[1][3].height = ROOM_HEIGHT - 1; + rooms[1][3].offset_y = 0; + rooms[1][3].kind = RoomType::BasicRoom; + let mst: Graph<(usize, usize), u16, petgraph::Undirected> = LevelGenerator::create_mst(&rooms); + LevelGenerator::create_connections(&mut rooms, &mst); + + assert!(rooms[1][1].connection_down.is_some()); + assert_eq!( + rooms[1][1].connection_down.unwrap().start_pos, + (ROOM_WIDTH + 3, ROOM_HEIGHT * 2), + "wrong start" + ); + assert_eq!( + rooms[1][1].connection_down.unwrap().end_pos, + (ROOM_WIDTH + 7, ROOM_HEIGHT * 3 - 1), + "wrong end" + ); + assert!(rooms[1][1].connection_right.is_none()); + assert!(rooms[1][2].connection_down.is_none()); + assert!(rooms[1][2].connection_right.is_none()); +} + +#[test] +fn test_create_connections_down_3() { + // test reduced width rooms (with NO overlap) for downwards connection + let mut rng = rand::thread_rng(); + let mut rooms = [[Room::new(&mut rng); ROOMS_VERTICAL]; ROOMS_HORIZONTAL]; + rooms[1][1].width = 3; + rooms[1][1].offset_x = 0; + rooms[1][1].height = ROOM_HEIGHT - 1; + rooms[1][1].offset_y = 0; + rooms[1][1].kind = RoomType::BasicRoom; + + rooms[1][3].width = 3; + rooms[1][3].offset_x = 5; + rooms[1][3].height = ROOM_HEIGHT - 1; + rooms[1][3].offset_y = 0; + rooms[1][3].kind = RoomType::BasicRoom; + let mst: Graph<(usize, usize), u16, petgraph::Undirected> = LevelGenerator::create_mst(&rooms); + LevelGenerator::create_connections(&mut rooms, &mst); + + assert!(rooms[1][1].connection_down.is_some()); + assert_eq!( + rooms[1][1].connection_down.unwrap().start_pos, + (ROOM_WIDTH + 2, ROOM_HEIGHT * 2), + "wrong start" + ); + assert_eq!( + rooms[1][1].connection_down.unwrap().end_pos, + (ROOM_WIDTH + 7, ROOM_HEIGHT * 3 - 1), + "wrong end" + ); + assert!(rooms[1][1].connection_right.is_none()); + assert!(rooms[1][2].connection_down.is_none()); + assert!(rooms[1][2].connection_right.is_none()); +} + +#[test] +fn test_create_connections_down_4() { + // test reduced and moved width rooms (with NO overlap) for downwards connection + let mut rng = rand::thread_rng(); + let mut rooms = [[Room::new(&mut rng); ROOMS_VERTICAL]; ROOMS_HORIZONTAL]; + rooms[1][1].width = 3; + rooms[1][1].offset_x = 0; + rooms[1][1].height = 4; + rooms[1][1].offset_y = 0; + rooms[1][1].kind = RoomType::BasicRoom; + + rooms[1][3].width = 3; + rooms[1][3].offset_x = 5; + rooms[1][3].height = 4; + rooms[1][3].offset_y = 1; + rooms[1][3].kind = RoomType::BasicRoom; + let mst: Graph<(usize, usize), u16, petgraph::Undirected> = LevelGenerator::create_mst(&rooms); + LevelGenerator::create_connections(&mut rooms, &mst); + + assert!(rooms[1][1].connection_down.is_some()); + assert_eq!( + rooms[1][1].connection_down.unwrap().start_pos, + (ROOM_WIDTH + 2, ROOM_HEIGHT + 5), + "wrong start" + ); + assert_eq!( + rooms[1][1].connection_down.unwrap().end_pos, + (ROOM_WIDTH + 7, ROOM_HEIGHT * 3 + 0), + "wrong end" + ); + assert!(rooms[1][1].connection_right.is_none()); + assert!(rooms[1][2].connection_down.is_none()); + assert!(rooms[1][2].connection_right.is_none()); +} + +#[test] +fn test_create_connections_right_1() { + let mut rng = rand::thread_rng(); + let mut rooms = [[Room::new(&mut rng); ROOMS_VERTICAL]; ROOMS_HORIZONTAL]; + rooms[1][1].width = ROOM_WIDTH - 1; + rooms[1][1].offset_x = 0; + rooms[1][1].height = ROOM_HEIGHT - 1; + rooms[1][1].offset_y = 0; + rooms[1][1].kind = RoomType::BasicRoom; + + rooms[3][1].width = ROOM_WIDTH - 1; + rooms[3][1].offset_x = 0; + rooms[3][1].height = ROOM_HEIGHT - 1; + rooms[3][1].offset_y = 0; + rooms[3][1].kind = RoomType::BasicRoom; + let mst: Graph<(usize, usize), u16, petgraph::Undirected> = LevelGenerator::create_mst(&rooms); + LevelGenerator::create_connections(&mut rooms, &mst); + + assert!(rooms[1][1].connection_down.is_none()); + assert!(rooms[1][1].connection_right.is_some()); + assert_eq!( + rooms[1][1].connection_right.unwrap().start_pos, + (ROOM_WIDTH * 2-1, ROOM_HEIGHT + ROOM_HEIGHT / 2), + "wrong start" + ); + assert_eq!( + rooms[1][1].connection_right.unwrap().end_pos, + (ROOM_WIDTH * 3 - 1, ROOM_HEIGHT + ROOM_HEIGHT / 2), + "wrong end" + ); + assert!(rooms[1][2].connection_down.is_none()); + assert!(rooms[1][2].connection_right.is_none()); +} + +#[test] +fn test_create_connections_right_2() { + // test reduced width rooms (with overlap) for downwards connection + let mut rng = rand::thread_rng(); + let mut rooms = [[Room::new(&mut rng); ROOMS_VERTICAL]; ROOMS_HORIZONTAL]; + rooms[1][1].width = ROOM_WIDTH - 1; + rooms[1][1].offset_x = 0; + rooms[1][1].height = 4; + rooms[1][1].offset_y = 0; + rooms[1][1].kind = RoomType::BasicRoom; + + rooms[3][1].width = ROOM_WIDTH - 1; + rooms[3][1].offset_x = 0; + rooms[3][1].height = 4; + rooms[3][1].offset_y = 2; + rooms[3][1].kind = RoomType::BasicRoom; + let mst: Graph<(usize, usize), u16, petgraph::Undirected> = LevelGenerator::create_mst(&rooms); + LevelGenerator::create_connections(&mut rooms, &mst); + + assert!(rooms[1][1].connection_down.is_none()); + assert!(rooms[1][1].connection_right.is_some()); + assert_eq!( + rooms[1][1].connection_right.unwrap().start_pos, + (ROOM_WIDTH * 2-1, ROOM_HEIGHT + 2), + "wrong start" + ); + assert_eq!( + rooms[1][1].connection_right.unwrap().end_pos, + (ROOM_WIDTH * 3 - 1, ROOM_HEIGHT + 4), + "wrong end" + ); + assert!(rooms[1][2].connection_down.is_none()); + assert!(rooms[1][2].connection_right.is_none()); +} + +#[test] +fn test_create_connections_right_3() { + // test reduced width rooms (with NO overlap) for downwards connection + let mut rng = rand::thread_rng(); + let mut rooms = [[Room::new(&mut rng); ROOMS_VERTICAL]; ROOMS_HORIZONTAL]; + rooms[1][1].width = ROOM_WIDTH - 1; + rooms[1][1].offset_x = 0; + rooms[1][1].height = 2; + rooms[1][1].offset_y = 0; + rooms[1][1].kind = RoomType::BasicRoom; + + rooms[3][1].width = ROOM_WIDTH - 1; + rooms[3][1].offset_x = 0; + rooms[3][1].height = 2; + rooms[3][1].offset_y = 4; + rooms[3][1].kind = RoomType::BasicRoom; + let mst: Graph<(usize, usize), u16, petgraph::Undirected> = LevelGenerator::create_mst(&rooms); + LevelGenerator::create_connections(&mut rooms, &mst); + + assert!(rooms[1][1].connection_down.is_none()); + assert!(rooms[1][1].connection_right.is_some()); + assert_eq!( + rooms[1][1].connection_right.unwrap().start_pos, + (ROOM_WIDTH * 2 - 1, ROOM_HEIGHT + 1), + "wrong start" + ); + assert_eq!( + rooms[1][1].connection_right.unwrap().end_pos, + (ROOM_WIDTH * 3 - 1, ROOM_HEIGHT + 5), + "wrong end" + ); + assert!(rooms[1][2].connection_down.is_none()); + assert!(rooms[1][2].connection_right.is_none()); +} + +#[test] +fn test_create_connections_right_4() { + // test reduced width rooms (with NO overlap) for downwards connection + let mut rng = rand::thread_rng(); + let mut rooms = [[Room::new(&mut rng); ROOMS_VERTICAL]; ROOMS_HORIZONTAL]; + rooms[1][1].width = 4; + rooms[1][1].offset_x = 3; + rooms[1][1].height = 2; + rooms[1][1].offset_y = 0; + rooms[1][1].kind = RoomType::BasicRoom; + + rooms[3][1].width = 3; + rooms[3][1].offset_x = 3; + rooms[3][1].height = 2; + rooms[3][1].offset_y = 4; + rooms[3][1].kind = RoomType::BasicRoom; + let mst: Graph<(usize, usize), u16, petgraph::Undirected> = LevelGenerator::create_mst(&rooms); + LevelGenerator::create_connections(&mut rooms, &mst); + + assert!(rooms[1][1].connection_down.is_none()); + assert!(rooms[1][1].connection_right.is_some()); + assert_eq!( + rooms[1][1].connection_right.unwrap().start_pos, + (ROOM_WIDTH +7, ROOM_HEIGHT + 1), + "wrong start" + ); + assert_eq!( + rooms[1][1].connection_right.unwrap().end_pos, + (ROOM_WIDTH * 3 + 2, ROOM_HEIGHT + 5), + "wrong end" + ); + assert!(rooms[1][2].connection_down.is_none()); + assert!(rooms[1][2].connection_right.is_none()); +} + /* println!(" 0 1 2 3 4 5 6 7"); for r in 0..ROOMS_VERTICAL {