mapgen/
lib.rs

1//! Generators for dungeon type maps.
2//! 
3//! Generators can bu used directly or they can be combined with
4//! `MapGenerator`s and `MapModifier`s
5//! 
6//! * MapGenerators are use to create initial map.
7//! * MapModifiers modify existing map.
8//! 
9//! Example
10//! ```
11//! use mapgen::{MapFilter, MapBuilder};
12//! use mapgen::filter::{
13//!     NoiseGenerator,
14//!     CellularAutomata,
15//!     starting_point::{AreaStartingPosition, XStart, YStart}
16//! };
17//! use mapgen::geometry::Point;
18//! 
19//! let map = MapBuilder::new(80, 50)
20//!             .with(NoiseGenerator::uniform())
21//!             .with(CellularAutomata::new())
22//!             .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
23//!             .build();
24//! 
25//! assert_eq!(map.width, 80);
26//! assert_eq!(map.height, 50);
27//! assert_eq!(map.starting_point.is_some(), true);
28//! ```
29//!  
30
31pub mod filter;
32pub mod geometry;
33pub mod metric;
34pub mod map_buffer;
35
36pub (crate) mod dijkstra;
37pub (crate) mod random;
38
39use std::time::{SystemTime, UNIX_EPOCH};
40use rand::prelude::*;
41
42pub use map_buffer::{MapBuffer, Symmetry};
43pub use filter::*;
44
45
46/// Trait which should be implemented by map modifier. 
47/// Modifier takes initiall map and apply changes to it.
48pub trait MapFilter {
49    fn modify_map(&self, rng: &mut StdRng, map: &MapBuffer) -> MapBuffer;
50}
51
52/// Used to chain MapBuilder and MapModifiers to create the final map.
53pub struct MapBuilder {
54    width: usize,
55    height: usize,
56    modifiers: Vec<Box<dyn MapFilter>>,
57}
58
59impl MapBuilder {
60    /// Create Map Builder with initial map generator
61    pub fn new(width: usize, height: usize) -> MapBuilder {
62        MapBuilder { 
63            width,
64            height,
65            modifiers: Vec::new(),
66        }
67    }
68
69    pub fn with(&mut self, modifier : Box<dyn MapFilter>) -> &mut MapBuilder {
70        self.modifiers.push(modifier);
71        self
72    }
73
74    /// Build map using random number seeded with system time
75    pub fn build(&mut self) -> MapBuffer {
76        let system_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Can't access system time");
77        let mut rng = StdRng::seed_from_u64(system_time.as_millis() as u64);
78        self.build_with_rng(&mut rng)
79    }
80
81    /// Build map using provided random number generator
82    pub fn build_with_rng(&mut self, rng: &mut StdRng) -> MapBuffer {
83        let mut map = MapBuffer::new(self.width, self.height);
84        
85        // Build additional layers in turn
86        for modifier in self.modifiers.iter() {
87            map = modifier.modify_map(rng, &map);
88        }
89
90        map
91    }
92
93}
94
95/// ------------------------------------------------------------------------------------------------
96/// Module unit tests
97/// ------------------------------------------------------------------------------------------------
98#[cfg(test)]
99mod tests {
100    use super::*;
101    use filter::{
102        CellularAutomata,
103        NoiseGenerator,
104        {AreaStartingPosition, XStart, YStart},
105    };
106
107    #[test]
108    fn test_ca_map() {
109        let map = MapBuilder::new(80, 50)
110            .with(NoiseGenerator::new(0.55))
111            .with(CellularAutomata::new())
112            .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
113            .build();
114
115        assert_eq!(map.width, 80);
116        assert_eq!(map.height, 50);
117        assert!(map.starting_point.is_some());
118    }
119
120}