use rand::prelude::*;
use crate::MapFilter;
use crate::MapBuffer;
pub struct CellularAutomata {
num_iteraction: u32,
}
impl MapFilter for CellularAutomata {
fn modify_map(&self, _rng: &mut StdRng, map: &MapBuffer) -> MapBuffer {
self.build(map)
}
}
impl CellularAutomata {
pub fn new() -> Box<CellularAutomata> {
Box::new(CellularAutomata { num_iteraction: 15})
}
fn build(&self, map: &MapBuffer) -> MapBuffer {
let mut new_map = map.clone();
for _ in 0..self.num_iteraction {
new_map = apply_iteration(&new_map);
}
new_map
}
}
fn apply_iteration(map: &MapBuffer) -> MapBuffer {
let mut new_map = map.clone();
for y in 1..map.height-1 {
for x in 1..map.width-1 {
let idxs = [
(x-1, y-1), (x, y-1), (x+1, y-1),
(x-1, y), (x+1, y),
(x-1, y+1), (x, y+1), (x+1, y+1)];
let neighbors = idxs.iter()
.filter(|(x, y)| map.is_blocked(*x, *y))
.count();
let walkable = neighbors < 5 && neighbors > 0;
new_map.set_walkable(x, y, walkable);
}
}
new_map
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_iteration_wal() {
let map = MapBuffer::new(3, 3);
let new_map = apply_iteration(&map);
assert!(new_map.is_blocked(1, 1));
}
#[test]
fn test_iteration_floor() {
let mut map = MapBuffer::new(3, 3);
for i in 0..3 {
for j in 0..2 {
map.set_walkable(i, j, true);
}
}
let new_map = apply_iteration(&map);
assert!(new_map.is_walkable(1, 1));
}
}