1use rand;
2
3use rand::Rng;
4
5pub struct CellularMap {
6 width: u32,
7 height: u32,
8 map: Vec<u8>,
9}
10
11pub enum EvolveStrategy {
12 Default, Cleaning, }
15
16impl CellularMap {
17 pub fn new(w: u32, h: u32) -> CellularMap {
34 let mut arraymap: Vec<u8> = Vec::with_capacity((w * h) as usize);
35 for _ in 0..w * h {
36 arraymap.push(0);
37 }
38 CellularMap {
39 width: w,
40 height: h,
41 map: arraymap,
42 }
43 }
44
45 pub fn get_width(self: &CellularMap) -> u32 {
47 self.width
48 }
49
50 pub fn get_height(self: &CellularMap) -> u32 {
52 self.height
53 }
54
55 pub fn get_element(self: &CellularMap, r: u32, c: u32) -> u8 {
57 return self.map[self.get_index(r, c)];
58 }
59
60 pub fn random_fill(self: &mut CellularMap, wall_prob: u32) {
62 for index in 0..self.width * self.height {
63 let (c, r) = (index % self.width, index / self.width);
64 self.map[index as usize] = if self.is_on_border(r, c) {
65 1
66 } else {
67 let map_middle = self.height / 2;
68 if r == map_middle {
69 0
70 } else {
71 let value = rand::thread_rng().gen_range(0, 100);
72 if value < wall_prob {
73 1
74 } else {
75 0
76 }
77 }
78 };
79 }
80 }
81
82 pub fn evolve_default(self: &mut CellularMap) {
83 self.evolve(EvolveStrategy::Default)
84 }
85
86 pub fn evolve(self: &mut CellularMap, _strategy: EvolveStrategy) {
88 for r in 0..self.height {
89 for c in 0..self.width {
90 let value = self.place_logic(r, c);
91 let index = self.get_index(r, c);
92 self.map[index] = value;
93 }
94 }
95 }
96
97 fn place_logic(self: &mut CellularMap, r: u32, c: u32) -> u8 {
99 let num_wall1 = self.count_adjacent_wall(r, c, 1, 1);
100 let num_wall2 = self.count_adjacent_wall(r, c, 2, 2);
101
102 let index = self.get_index(r, c);
103 if self.map[index] == 1u8 {
104 if num_wall1 >= 3 {
105 1
106 } else {
107 0
108 }
109 } else {
110 if num_wall1 >= 5 || num_wall2 <= 2 {
111 1
112 } else {
113 0
114 }
115 }
116 }
117
118 fn count_adjacent_wall(self: &mut CellularMap,
120 r: u32,
121 c: u32,
122 scopex: u32,
123 scopey: u32)
124 -> u32 {
125 let endx = c + scopex + 1;
126 let endy = r + scopey + 1;
127
128 let startx = if scopex > c {
129 0
130 } else {
131 c - scopex
132 };
133 let underx = if scopex > c {
134 scopex - c
135 } else {
136 0
137 };
138
139 let starty = if scopey > r {
140 0
141 } else {
142 r - scopey
143 };
144 let undery = if scopey > r {
145 scopey - r
146 } else {
147 0
148 };
149
150 let mut wallcounter = underx * (2 * scopex + 1) + undery * (2 * scopey + 1) -
151 undery * underx;
152
153 for iy in starty..endy {
154 for ix in startx..endx {
155 if (ix != c || iy != r) && self.is_wall(iy, ix) {
156 wallcounter += 1;
157 }
158 }
159 }
160 return wallcounter;
161 }
162
163 fn is_wall(self: &CellularMap, r: u32, c: u32) -> bool {
165 let index = self.get_index(r, c);
166 self.is_out_of_bound(r, c) || self.map[index] == 1
167 }
168
169 fn is_out_of_bound(self: &CellularMap, r: u32, c: u32) -> bool {
171 c > self.width - 1 || r > self.height - 1
172 }
173
174 fn is_on_border(self: &CellularMap, r: u32, c: u32) -> bool {
176 c == 0 || r == 0 || c == self.width - 1 || r == self.height - 1
177 }
178
179 fn get_index(self: &CellularMap, r: u32, c: u32) -> usize {
181 (c + r * self.width) as usize
182 }
183}
184
185#[test]
189fn constructor_test() {
190 let cm = CellularMap::new(12, 12);
191
192 assert!(12 == cm.width);
193 assert!(12 == cm.height);
194}
195
196#[test]
197fn get_element_test() {
198 let mut cm = CellularMap::new(12, 12);
199 cm.map[4] = 2u8;
200 assert_eq!(2u8, cm.get_element(0, 4));
201}
202
203