103 lines
2.6 KiB
Rust
103 lines
2.6 KiB
Rust
use rand::prelude::*;
|
|
use super::{MapGenerator, MapModifier};
|
|
use super::map::{Map, TileType};
|
|
|
|
|
|
pub struct CellularAutomataGen {
|
|
width: usize,
|
|
height: usize
|
|
}
|
|
|
|
impl MapGenerator for CellularAutomataGen {
|
|
fn generate_map(&self, rng : &mut StdRng) -> Map {
|
|
self.build(rng)
|
|
}
|
|
}
|
|
|
|
impl CellularAutomataGen {
|
|
pub fn new(width: usize, height: usize) -> CellularAutomataGen {
|
|
CellularAutomataGen {width, height}
|
|
}
|
|
|
|
/// Generate map
|
|
fn build(&self, rng : &mut StdRng) -> Map {
|
|
let mut map = Map::new(self.width, self.height);
|
|
// First we completely randomize the map, setting 55% of it to be floor.
|
|
for y in 1..self.height-1 {
|
|
for x in 1..self.width-1 {
|
|
let roll = rng.next_u32() % 100;
|
|
if roll > 55 { map.set_tile(x, y, TileType::Floor) }
|
|
else { map.set_tile(x, y, TileType::Wall) }
|
|
}
|
|
}
|
|
|
|
// Now we iteratively apply cellular automata rules
|
|
for _ in 0..15 {
|
|
map = apply_iteration(&map);
|
|
}
|
|
|
|
map
|
|
}
|
|
|
|
}
|
|
|
|
impl MapModifier for CellularAutomataGen {
|
|
fn modify_map(&self, _rng: &mut StdRng, map : &Map) -> Map {
|
|
apply_iteration(map)
|
|
}
|
|
}
|
|
|
|
|
|
fn apply_iteration(map: &Map) -> Map {
|
|
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.at(*x, *y) == TileType::Wall)
|
|
.count();
|
|
|
|
if neighbors > 4 || neighbors == 0 {
|
|
new_map.set_tile(x, y, TileType::Wall)
|
|
}
|
|
else {
|
|
new_map.set_tile(x, y, TileType::Floor);
|
|
}
|
|
}
|
|
}
|
|
|
|
new_map
|
|
}
|
|
|
|
/// ------------------------------------------------------------------------------------------------
|
|
/// Module unit tests
|
|
/// ------------------------------------------------------------------------------------------------
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_iteration_wal() {
|
|
let map = Map::new(3, 3);
|
|
let new_map = apply_iteration(&map);
|
|
assert_eq!(new_map.at(1, 1), TileType::Wall);
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn test_iteration_floor() {
|
|
let mut map = Map::new(3, 3);
|
|
for i in 0..3 {
|
|
for j in 0..2 {
|
|
map.set_tile(i, j, TileType::Floor);
|
|
}
|
|
}
|
|
let new_map = apply_iteration(&map);
|
|
assert_eq!(new_map.at(1, 1), TileType::Floor);
|
|
}
|
|
|
|
} |