Generator für die Testkarte
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>
This commit is contained in:
@@ -9,4 +9,5 @@
|
||||
pub mod codec;
|
||||
pub mod hash;
|
||||
pub mod map;
|
||||
pub mod mapgen;
|
||||
pub mod rng;
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
//! Generator for the milestone 1 test map.
|
||||
//!
|
||||
//! The broad layout is fixed and the details are random: a bedrock border, a
|
||||
//! clearing around the spawn point, a rock outcrop right next to the
|
||||
//! clearing, cave-like soft rock in the inner area and hard rock further out.
|
||||
|
||||
use crate::map::{Map, Pos, Terrain, Tile};
|
||||
use crate::rng::Rng;
|
||||
|
||||
/// Edge length of the test map, in tiles.
|
||||
pub const TEST_MAP_SIZE: u32 = 64;
|
||||
/// Tiles within this distance of the spawn point are always open ground.
|
||||
pub const SPAWN_CLEARING_RADIUS: i32 = 5;
|
||||
/// Edge length of the soft rock outcrop that every test map has.
|
||||
pub const OUTCROP_SIZE: i32 = 4;
|
||||
/// Rock at least this many tiles from the spawn point, counted along the
|
||||
/// longer axis, is hard rock.
|
||||
pub const HARD_ROCK_DISTANCE: i32 = 22;
|
||||
|
||||
const INITIAL_ROCK_PERCENT: u32 = 46;
|
||||
const SMOOTHING_PASSES: u32 = 4;
|
||||
/// Keeps the map sequence apart from other uses of the same seed.
|
||||
const SEED_SALT: u64 = 0x6D61_7067_656E_0001;
|
||||
|
||||
/// Spawn point of a map: its centre tile.
|
||||
pub fn spawn_pos(map: &Map) -> Pos {
|
||||
Pos::new((map.width() / 2) as i32, (map.height() / 2) as i32)
|
||||
}
|
||||
|
||||
/// Top left tile of the soft rock outcrop next to the spawn clearing.
|
||||
pub fn outcrop_origin(map: &Map) -> Pos {
|
||||
let spawn = spawn_pos(map);
|
||||
Pos::new(spawn.x + SPAWN_CLEARING_RADIUS + 2, spawn.y - 2)
|
||||
}
|
||||
|
||||
/// Builds the test map for `seed`. The same seed always gives the same map.
|
||||
pub fn generate_test_map(seed: u64) -> Map {
|
||||
let size = TEST_MAP_SIZE;
|
||||
let mut rng = Rng::new(seed ^ SEED_SALT);
|
||||
|
||||
let mut rock = vec![false; (size as usize) * (size as usize)];
|
||||
for cell in rock.iter_mut() {
|
||||
*cell = rng.below(100) < INITIAL_ROCK_PERCENT;
|
||||
}
|
||||
for _ in 0..SMOOTHING_PASSES {
|
||||
rock = smooth(&rock, size);
|
||||
}
|
||||
|
||||
let mut map = Map::filled(size, size, Terrain::Ground);
|
||||
let spawn = spawn_pos(&map);
|
||||
let outcrop = outcrop_origin(&map);
|
||||
let last = size as i32 - 1;
|
||||
|
||||
for y in 0..=last {
|
||||
for x in 0..=last {
|
||||
let dx = x - spawn.x;
|
||||
let dy = y - spawn.y;
|
||||
let on_border = x == 0 || y == 0 || x == last || y == last;
|
||||
let in_clearing = dx * dx + dy * dy <= SPAWN_CLEARING_RADIUS * SPAWN_CLEARING_RADIUS;
|
||||
let in_outcrop = (outcrop.x..outcrop.x + OUTCROP_SIZE).contains(&x)
|
||||
&& (outcrop.y..outcrop.y + OUTCROP_SIZE).contains(&y);
|
||||
let is_rock = rock[(y as usize) * (size as usize) + (x as usize)];
|
||||
|
||||
let terrain = if on_border {
|
||||
Terrain::Bedrock
|
||||
} else if in_clearing {
|
||||
Terrain::Ground
|
||||
} else if in_outcrop {
|
||||
Terrain::SoftRock
|
||||
} else if !is_rock {
|
||||
Terrain::Ground
|
||||
} else if dx.abs().max(dy.abs()) >= HARD_ROCK_DISTANCE {
|
||||
Terrain::HardRock
|
||||
} else {
|
||||
Terrain::SoftRock
|
||||
};
|
||||
map.set(Pos::new(x, y), Tile::new(terrain));
|
||||
}
|
||||
}
|
||||
map
|
||||
}
|
||||
|
||||
/// One pass of cave smoothing: a cell becomes rock when at least five of the
|
||||
/// nine cells around it, itself included, are rock. Cells outside the grid
|
||||
/// count as rock.
|
||||
fn smooth(rock: &[bool], size: u32) -> Vec<bool> {
|
||||
let size = size as i32;
|
||||
let mut out = vec![false; rock.len()];
|
||||
for y in 0..size {
|
||||
for x in 0..size {
|
||||
let mut count = 0;
|
||||
for ny in y - 1..=y + 1 {
|
||||
for nx in x - 1..=x + 1 {
|
||||
let outside = nx < 0 || ny < 0 || nx >= size || ny >= size;
|
||||
if outside || rock[(ny * size + nx) as usize] {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
out[(y * size + x) as usize] = count >= 5;
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
Reference in New Issue
Block a user