terrain_forge/algorithms/
dla.rs

1use crate::{Algorithm, Grid, Rng, Tile};
2
3#[derive(Debug, Clone)]
4pub struct DlaConfig {
5    pub num_particles: usize,
6    pub max_walk_steps: usize,
7}
8
9impl Default for DlaConfig {
10    fn default() -> Self {
11        Self {
12            num_particles: 500,
13            max_walk_steps: 1000,
14        }
15    }
16}
17
18pub struct Dla {
19    config: DlaConfig,
20}
21
22impl Dla {
23    pub fn new(config: DlaConfig) -> Self {
24        Self { config }
25    }
26}
27
28impl Default for Dla {
29    fn default() -> Self {
30        Self::new(DlaConfig::default())
31    }
32}
33
34impl Algorithm<Tile> for Dla {
35    fn generate(&self, grid: &mut Grid<Tile>, seed: u64) {
36        let mut rng = Rng::new(seed);
37        let (w, h) = (grid.width(), grid.height());
38        let dirs: [(i32, i32); 4] = [(0, -1), (1, 0), (0, 1), (-1, 0)];
39
40        // Seed in center
41        grid.set(w as i32 / 2, h as i32 / 2, Tile::Floor);
42
43        for _ in 0..self.config.num_particles {
44            let mut x = rng.range(1, w as i32 - 1);
45            let mut y = rng.range(1, h as i32 - 1);
46
47            for _ in 0..self.config.max_walk_steps {
48                let has_neighbor = dirs.iter().any(|&(dx, dy)| {
49                    grid.get(x + dx, y + dy)
50                        .map(|t| t.is_floor())
51                        .unwrap_or(false)
52                });
53
54                if has_neighbor {
55                    grid.set(x, y, Tile::Floor);
56                    break;
57                }
58
59                let (dx, dy) = dirs[rng.range_usize(0, 4)];
60                let (nx, ny) = (x + dx, y + dy);
61                if nx > 0 && nx < w as i32 - 1 && ny > 0 && ny < h as i32 - 1 {
62                    x = nx;
63                    y = ny;
64                }
65            }
66        }
67    }
68
69    fn name(&self) -> &'static str {
70        "DLA"
71    }
72}