aae0eccc8b
Baut aus einer Startzahl eine 64 × 64 Felder große Karte mit Rand aus Grundgestein, Lichtung am Startpunkt, Felsblock daneben, weichem Fels innen und hartem Fels außen. Die Regeln sind für 300 Startzahlen geprüft. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
133 lines
4.0 KiB
Rust
133 lines
4.0 KiB
Rust
//! 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));
|
|
}
|