//! Rules the map generator has to keep for every seed. use grovewright_core::map::{Map, Pos, Terrain}; use grovewright_core::mapgen::{ generate_test_map, outcrop_origin, spawn_pos, HARD_ROCK_DISTANCE, OUTCROP_SIZE, SPAWN_CLEARING_RADIUS, TEST_MAP_SIZE, }; /// Number of seeds every rule is checked against. const SEEDS: u64 = 300; fn terrain_at(map: &Map, x: i32, y: i32) -> Terrain { map.get(Pos::new(x, y)) .expect("position is on the map") .terrain } #[test] fn the_same_seed_gives_the_same_map() { assert_eq!(generate_test_map(42), generate_test_map(42)); } #[test] fn different_seeds_give_different_maps() { assert_ne!(generate_test_map(1), generate_test_map(2)); } #[test] fn the_map_has_the_test_size() { let map = generate_test_map(0); assert_eq!((map.width(), map.height()), (TEST_MAP_SIZE, TEST_MAP_SIZE)); } #[test] fn bedrock_forms_the_border_and_nothing_else() { let last = TEST_MAP_SIZE as i32 - 1; for seed in 0..SEEDS { let map = generate_test_map(seed); for y in 0..=last { for x in 0..=last { let on_border = x == 0 || y == 0 || x == last || y == last; let is_bedrock = terrain_at(&map, x, y) == Terrain::Bedrock; assert_eq!(is_bedrock, on_border, "seed {seed}, tile {x}/{y}"); } } } } #[test] fn the_spawn_clearing_is_open_ground() { for seed in 0..SEEDS { let map = generate_test_map(seed); let spawn = spawn_pos(&map); for dy in -SPAWN_CLEARING_RADIUS..=SPAWN_CLEARING_RADIUS { for dx in -SPAWN_CLEARING_RADIUS..=SPAWN_CLEARING_RADIUS { if dx * dx + dy * dy > SPAWN_CLEARING_RADIUS * SPAWN_CLEARING_RADIUS { continue; } let terrain = terrain_at(&map, spawn.x + dx, spawn.y + dy); assert_eq!(terrain, Terrain::Ground, "seed {seed}, offset {dx}/{dy}"); } } } } #[test] fn a_soft_rock_outcrop_lies_next_to_the_clearing() { for seed in 0..SEEDS { let map = generate_test_map(seed); let spawn = spawn_pos(&map); let origin = outcrop_origin(&map); assert_eq!(origin.x - spawn.x, SPAWN_CLEARING_RADIUS + 2, "seed {seed}"); for y in origin.y..origin.y + OUTCROP_SIZE { for x in origin.x..origin.x + OUTCROP_SIZE { assert_eq!( terrain_at(&map, x, y), Terrain::SoftRock, "seed {seed}, tile {x}/{y}" ); } } } } #[test] fn hard_rock_appears_only_far_from_the_spawn_point() { let last = TEST_MAP_SIZE as i32 - 1; for seed in 0..SEEDS { let map = generate_test_map(seed); let spawn = spawn_pos(&map); for y in 1..last { for x in 1..last { let far = (x - spawn.x).abs().max((y - spawn.y).abs()) >= HARD_ROCK_DISTANCE; match terrain_at(&map, x, y) { Terrain::HardRock => assert!(far, "seed {seed}: hard rock near spawn"), Terrain::SoftRock => assert!(!far, "seed {seed}: soft rock far out"), Terrain::Ground | Terrain::Bedrock => {} } } } } } #[test] fn every_map_mixes_rock_and_open_ground() { for seed in 0..SEEDS { let map = generate_test_map(seed); let total = map.tiles().len(); let rock = map .tiles() .iter() .filter(|tile| !tile.terrain.is_walkable()) .count(); let percent = rock * 100 / total; assert!( (20..=80).contains(&percent), "seed {seed}: {percent} percent rock" ); let hard = map .tiles() .iter() .filter(|tile| tile.terrain == Terrain::HardRock) .count(); assert!(hard > 0, "seed {seed}: no hard rock"); } } #[test] fn no_generated_tile_starts_damaged() { let map = generate_test_map(5); assert!(map.tiles().iter().all(|tile| tile.damage == 0)); }