terrain_forge/algorithms/
percolation.rs1use crate::{Algorithm, Grid, Rng, Tile};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct PercolationConfig {
7 pub fill_probability: f64,
9 pub keep_largest: bool,
11}
12
13impl Default for PercolationConfig {
14 fn default() -> Self {
15 Self {
16 fill_probability: 0.45,
17 keep_largest: true,
18 }
19 }
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct Percolation {
25 config: PercolationConfig,
26}
27
28impl Percolation {
29 pub fn new(config: PercolationConfig) -> Self {
31 Self { config }
32 }
33}
34
35impl Default for Percolation {
36 fn default() -> Self {
37 Self::new(PercolationConfig::default())
38 }
39}
40
41impl Algorithm<Tile> for Percolation {
42 fn generate(&self, grid: &mut Grid<Tile>, seed: u64) {
43 let mut rng = Rng::new(seed);
44 let (w, h) = (grid.width(), grid.height());
45
46 for y in 1..h - 1 {
47 for x in 1..w - 1 {
48 if rng.chance(self.config.fill_probability) {
49 grid.set(x as i32, y as i32, Tile::Floor);
50 }
51 }
52 }
53
54 if !self.config.keep_largest {
55 return;
56 }
57
58 let regions = grid.flood_regions();
60 if regions.len() <= 1 {
61 return;
62 }
63
64 let largest_region = regions.iter().max_by_key(|r| r.len()).unwrap();
65 let keep: std::collections::HashSet<(usize, usize)> =
66 largest_region.iter().copied().collect();
67
68 for y in 0..h {
69 for x in 0..w {
70 if grid[(x, y)].is_floor() && !keep.contains(&(x, y)) {
71 grid.set(x as i32, y as i32, Tile::Wall);
72 }
73 }
74 }
75 }
76
77 fn name(&self) -> &'static str {
78 "Percolation"
79 }
80}