terrain_forge/algorithms/
voronoi.rs1use crate::{Algorithm, Grid, Rng, Tile};
2
3#[derive(Debug, Clone)]
4pub struct VoronoiConfig {
5 pub num_points: usize,
6 pub floor_chance: f64,
7}
8
9impl Default for VoronoiConfig {
10 fn default() -> Self { Self { num_points: 15, floor_chance: 0.5 } }
11}
12
13pub struct Voronoi {
14 config: VoronoiConfig,
15}
16
17impl Voronoi {
18 pub fn new(config: VoronoiConfig) -> Self { Self { config } }
19}
20
21impl Default for Voronoi {
22 fn default() -> Self { Self::new(VoronoiConfig::default()) }
23}
24
25impl Algorithm<Tile> for Voronoi {
26 fn generate(&self, grid: &mut Grid<Tile>, seed: u64) {
27 let mut rng = Rng::new(seed);
28 let (w, h) = (grid.width(), grid.height());
29
30 let points: Vec<(usize, usize)> = (0..self.config.num_points)
31 .map(|_| (rng.range_usize(1, w - 1), rng.range_usize(1, h - 1)))
32 .collect();
33
34 let is_floor: Vec<bool> = (0..self.config.num_points)
35 .map(|_| rng.chance(self.config.floor_chance))
36 .collect();
37
38 for y in 1..h - 1 {
39 for x in 1..w - 1 {
40 let mut min_dist = usize::MAX;
41 let mut closest = 0;
42 for (i, &(px, py)) in points.iter().enumerate() {
43 let dist = (x as i32 - px as i32).unsigned_abs() as usize
44 + (y as i32 - py as i32).unsigned_abs() as usize;
45 if dist < min_dist {
46 min_dist = dist;
47 closest = i;
48 }
49 }
50 if is_floor[closest] {
51 grid.set(x as i32, y as i32, Tile::Floor);
52 }
53 }
54 }
55 }
56
57 fn name(&self) -> &'static str { "Voronoi" }
58}