Skip to main content

terrain_forge/algorithms/
agent.rs

1use crate::{Algorithm, Grid, Rng, Tile};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5/// Configuration for agent-based carving.
6pub struct AgentConfig {
7    /// Number of carving agents. Default: 5.
8    pub num_agents: usize,
9    /// Steps each agent takes. Default: 200.
10    pub steps_per_agent: usize,
11    /// Probability of turning each step (0.0–1.0). Default: 0.3.
12    pub turn_chance: f64,
13}
14
15impl Default for AgentConfig {
16    fn default() -> Self {
17        Self {
18            num_agents: 5,
19            steps_per_agent: 200,
20            turn_chance: 0.3,
21        }
22    }
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26/// Agent-based terrain carver.
27pub struct AgentBased {
28    config: AgentConfig,
29}
30
31impl AgentBased {
32    /// Creates a new agent-based generator with the given config.
33    pub fn new(config: AgentConfig) -> Self {
34        Self { config }
35    }
36}
37
38impl Default for AgentBased {
39    fn default() -> Self {
40        Self::new(AgentConfig::default())
41    }
42}
43
44impl Algorithm<Tile> for AgentBased {
45    fn generate(&self, grid: &mut Grid<Tile>, seed: u64) {
46        let mut rng = Rng::new(seed);
47        let dirs: [(i32, i32); 4] = [(0, -1), (1, 0), (0, 1), (-1, 0)];
48        let (w, h) = (grid.width() as i32, grid.height() as i32);
49
50        for _ in 0..self.config.num_agents {
51            let mut x = rng.range(1, w - 1);
52            let mut y = rng.range(1, h - 1);
53            let mut dir = rng.range_usize(0, 4);
54
55            for _ in 0..self.config.steps_per_agent {
56                grid.set(x, y, Tile::Floor);
57
58                if rng.chance(self.config.turn_chance) {
59                    dir = if rng.chance(0.5) {
60                        (dir + 1) % 4
61                    } else {
62                        (dir + 3) % 4
63                    };
64                }
65
66                let (dx, dy) = dirs[dir];
67                let (nx, ny) = (x + dx, y + dy);
68
69                if nx > 0 && nx < w - 1 && ny > 0 && ny < h - 1 {
70                    x = nx;
71                    y = ny;
72                } else {
73                    dir = (dir + 2) % 4;
74                }
75            }
76        }
77    }
78
79    fn name(&self) -> &'static str {
80        "AgentBased"
81    }
82}