terrain_forge/algorithms/
cellular.rs1use crate::{Algorithm, Grid, Rng, Tile};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct CellularConfig {
7 pub initial_floor_chance: f64,
9 pub iterations: usize,
11 pub birth_limit: usize,
13 pub death_limit: usize,
15}
16
17impl Default for CellularConfig {
18 fn default() -> Self {
19 Self {
20 initial_floor_chance: 0.45,
21 iterations: 4,
22 birth_limit: 5,
23 death_limit: 4,
24 }
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct CellularAutomata {
31 config: CellularConfig,
32}
33
34impl CellularAutomata {
35 pub fn new(config: CellularConfig) -> Self {
37 Self { config }
38 }
39}
40
41impl Default for CellularAutomata {
42 fn default() -> Self {
43 Self::new(CellularConfig::default())
44 }
45}
46
47impl Algorithm<Tile> for CellularAutomata {
48 fn generate(&self, grid: &mut Grid<Tile>, seed: u64) {
49 let mut rng = Rng::new(seed);
50 let (w, h) = (grid.width(), grid.height());
51
52 for y in 1..h - 1 {
53 for x in 1..w - 1 {
54 if rng.chance(self.config.initial_floor_chance) {
55 grid.set(x as i32, y as i32, Tile::Floor);
56 }
57 }
58 }
59
60 for _ in 0..self.config.iterations {
61 let snapshot: Vec<bool> = (0..w * h)
62 .map(|i| grid[(i % w, i / w)].is_floor())
63 .collect();
64
65 for y in 1..h - 1 {
66 for x in 1..w - 1 {
67 let neighbors = count_neighbors(&snapshot, x, y, w);
68 let is_floor = snapshot[y * w + x];
69 let new_floor = if is_floor {
70 neighbors >= self.config.death_limit
71 } else {
72 neighbors >= self.config.birth_limit
73 };
74 grid.set(
75 x as i32,
76 y as i32,
77 if new_floor { Tile::Floor } else { Tile::Wall },
78 );
79 }
80 }
81 }
82 }
83
84 fn name(&self) -> &'static str {
85 "CellularAutomata"
86 }
87}
88
89fn count_neighbors(cells: &[bool], x: usize, y: usize, w: usize) -> usize {
90 let mut count = 0;
91 for dy in -1i32..=1 {
92 for dx in -1i32..=1 {
93 if dx == 0 && dy == 0 {
94 continue;
95 }
96 let nx = (x as i32 + dx) as usize;
97 let ny = (y as i32 + dy) as usize;
98 if cells[ny * w + nx] {
99 count += 1;
100 }
101 }
102 }
103 count
104}