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}