15912
|
1 |
use integral_geometry::Size;
|
15915
|
2 |
use std::collections::HashMap;
|
15913
|
3 |
use vec2d::Vec2D;
|
15912
|
4 |
|
|
5 |
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
|
15913
|
6 |
pub enum Tile {
|
15912
|
7 |
Empty,
|
|
8 |
Outside,
|
|
9 |
Numbered(u32),
|
|
10 |
}
|
|
11 |
|
|
12 |
impl Tile {
|
|
13 |
fn is(&self, i: u32) -> bool {
|
|
14 |
*self == Tile::Numbered(i)
|
|
15 |
}
|
|
16 |
|
|
17 |
fn is_empty(&self) -> bool {
|
|
18 |
match self {
|
|
19 |
Tile::Empty => true,
|
|
20 |
Tile::Outside => true,
|
|
21 |
_ => false,
|
|
22 |
}
|
|
23 |
}
|
|
24 |
|
|
25 |
fn is_empty_or(&self, i: u32) -> bool {
|
|
26 |
match self {
|
|
27 |
Tile::Numbered(n) => *n == i,
|
|
28 |
Tile::Empty => true,
|
|
29 |
_ => false,
|
|
30 |
}
|
|
31 |
}
|
|
32 |
|
|
33 |
fn is_void_or(&self, i: u32) -> bool {
|
|
34 |
match self {
|
|
35 |
Tile::Numbered(n) => *n == i,
|
|
36 |
_ => true,
|
|
37 |
}
|
|
38 |
}
|
|
39 |
}
|
|
40 |
|
|
41 |
impl Default for Tile {
|
|
42 |
fn default() -> Self {
|
|
43 |
Tile::Outside
|
|
44 |
}
|
|
45 |
}
|
|
46 |
|
|
47 |
struct CollapseRule {
|
|
48 |
to_tile: Tile,
|
|
49 |
condition: fn([Tile; 4]) -> bool,
|
|
50 |
}
|
|
51 |
|
|
52 |
#[derive(Default)]
|
15913
|
53 |
pub struct WavefrontCollapse {
|
15912
|
54 |
rules: HashMap<Tile, Vec<CollapseRule>>,
|
|
55 |
}
|
|
56 |
|
|
57 |
impl WavefrontCollapse {
|
15913
|
58 |
pub fn generate_map<I: Iterator<Item = u32>, F: FnOnce(&mut Vec2D<Tile>)>(
|
15912
|
59 |
&mut self,
|
|
60 |
map_size: &Size,
|
|
61 |
seed_fn: F,
|
|
62 |
random_numbers: &mut I,
|
15915
|
63 |
) -> Vec2D<Tile> {
|
15913
|
64 |
let mut land = Vec2D::new(&map_size, Tile::Empty);
|
15912
|
65 |
|
|
66 |
seed_fn(&mut land);
|
|
67 |
|
|
68 |
while self.collapse_step(&mut land, random_numbers) {}
|
|
69 |
|
|
70 |
land
|
|
71 |
}
|
|
72 |
|
|
73 |
fn add_rule(&mut self, from_tile: Tile, to_tile: Tile, condition: fn([Tile; 4]) -> bool) {
|
|
74 |
let rule = CollapseRule { to_tile, condition };
|
|
75 |
self.rules
|
|
76 |
.entry(from_tile)
|
|
77 |
.or_insert_with(Vec::new)
|
|
78 |
.push(rule);
|
|
79 |
}
|
|
80 |
|
|
81 |
fn collapse_step<I: Iterator<Item = u32>>(
|
|
82 |
&self,
|
15913
|
83 |
land: &mut Vec2D<Tile>,
|
15912
|
84 |
random_numbers: &mut I,
|
|
85 |
) -> bool {
|
|
86 |
let mut collapse_occurred = false;
|
|
87 |
for x in 0..land.width() {
|
|
88 |
for y in 0..land.height() {
|
15913
|
89 |
let current_tile = land.get(y, x).expect("valid iteration range");
|
15912
|
90 |
|
|
91 |
if let Some(rules) = self.rules.get(¤t_tile) {
|
|
92 |
for rule in rules
|
|
93 |
.iter()
|
|
94 |
.cycle()
|
|
95 |
.skip(
|
|
96 |
random_numbers.next().unwrap_or_default() as usize % (rules.len() + 1),
|
|
97 |
)
|
|
98 |
.take(rules.len())
|
|
99 |
{
|
|
100 |
let neighbors = self.get_neighbors(&land, x, y);
|
|
101 |
let have_neighbors = neighbors.iter().any(|t| !t.is_empty());
|
|
102 |
if have_neighbors && (rule.condition)(neighbors) {
|
15913
|
103 |
*land.get_mut(y, x).expect("valid iteration range") = rule.to_tile;
|
15912
|
104 |
collapse_occurred = true;
|
|
105 |
break;
|
|
106 |
}
|
|
107 |
}
|
|
108 |
}
|
|
109 |
}
|
|
110 |
}
|
|
111 |
|
|
112 |
collapse_occurred
|
|
113 |
}
|
|
114 |
|
15913
|
115 |
fn get_neighbors(&self, land: &Vec2D<Tile>, x: usize, y: usize) -> [Tile; 4] {
|
15912
|
116 |
[
|
15913
|
117 |
land.get(y, x + 1).map(|p| *p).unwrap_or_default(),
|
|
118 |
land.get(y + 1, x).map(|p| *p).unwrap_or_default(),
|
15915
|
119 |
land.get(y, x.wrapping_sub(1))
|
|
120 |
.map(|p| *p)
|
|
121 |
.unwrap_or_default(),
|
|
122 |
land.get(y.wrapping_sub(1), x)
|
|
123 |
.map(|p| *p)
|
|
124 |
.unwrap_or_default(),
|
15912
|
125 |
]
|
|
126 |
}
|
|
127 |
}
|
|
128 |
|
|
129 |
#[cfg(test)]
|
|
130 |
mod tests {
|
15913
|
131 |
use super::{Tile, WavefrontCollapse};
|
15912
|
132 |
use integral_geometry::Size;
|
15913
|
133 |
use vec2d::Vec2D;
|
15912
|
134 |
|
|
135 |
#[test]
|
|
136 |
fn test_wavefront_collapse() {
|
|
137 |
let size = Size::new(4, 4);
|
|
138 |
let mut rnd = [0u32; 64].into_iter();
|
|
139 |
let mut wfc = WavefrontCollapse::default();
|
|
140 |
|
15913
|
141 |
let empty_land = Vec2D::new(&size, Tile::Empty);
|
|
142 |
let no_rules_land = wfc.generate_map(&size, |_| {}, &mut rnd);
|
15912
|
143 |
|
15913
|
144 |
assert_eq!(empty_land.as_slice(), no_rules_land.as_slice());
|
15912
|
145 |
|
|
146 |
wfc.add_rule(Tile::Empty, Tile::Numbered(0), |neighbors| {
|
|
147 |
neighbors.iter().filter(|&n| *n == Tile::Empty).count() >= 2
|
|
148 |
});
|
15913
|
149 |
let ruled_map = wfc.generate_map(&size, |_| {}, &mut rnd);
|
15912
|
150 |
|
15913
|
151 |
assert_eq!(ruled_map.as_slice(), empty_land.as_slice());
|
15912
|
152 |
}
|
|
153 |
}
|