1use crate::{AutomataRules, Method, Rule};
14use std::hash::Hash;
15use std::ops::{Add, Sub};
16use std::default::Default;
17use std::collections::HashMap;
18
19#[cfg(feature = "rayon")]
20use rayon::prelude::*;
21
22#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
26pub struct Vec3 { x: usize, y: usize, z: usize }
27
28pub struct Automaton {
30 rules: AutomataRules,
31 bounds: Vec3,
32 cells: HashMap<Vec3, u8>
33}
34
35impl Vec3 {
38 pub fn new(x: usize, y: usize, z: usize) -> Vec3 { Vec3 { x, y, z } }
40}
41
42impl Add for Vec3 {
43 type Output = Vec3;
44 fn add(self, rhs: Vec3) -> Vec3 {
45 Vec3 {
46 x: self.x + rhs.x,
47 y: self.y + rhs.y,
48 z: self.z + rhs.z
49 }
50 }
51}
52
53impl Sub for Vec3 {
54 type Output = Vec3;
55 fn sub(self, rhs: Vec3) -> Vec3 {
56 Vec3 {
57 x: self.x - rhs.x,
58 y: self.y - rhs.y,
59 z: self.z - rhs.z
60 }
61 }
62}
63
64impl Default for Vec3 {
65 fn default() -> Vec3 { Vec3 { x: 0, y: 0, z: 0 } }
66}
67
68impl Automaton {
69 pub fn new(rules: AutomataRules, bounds: Vec3, start_cells: Vec<Vec3>) -> Result<Automaton, u8> {
73 let other_rules = rules.clone();
74 let mut a = Automaton { rules, bounds, cells: HashMap::new() };
75
76 let max_neighbors: u8 = match a.rules.neighbor_method {
77 Method::Moore => 26,
78 Method::VonNeumann => 6
79 };
80
81 match other_rules.to_survive {
82 Rule::Single(s) => if s > max_neighbors { return Err(max_neighbors) },
83 Rule::Range(r) => if r.start > max_neighbors || r.end > max_neighbors { return Err(max_neighbors) },
84 Rule::Many(m) => for s in m {
85 if s > max_neighbors { return Err(max_neighbors) }
86 }
87 }
88
89 match other_rules.to_be_born {
90 Rule::Single(s) => if s > max_neighbors { return Err(max_neighbors) },
91 Rule::Range(r) => if r.start > max_neighbors || r.end > max_neighbors { return Err(max_neighbors) },
92 Rule::Many(m) => for s in m {
93 if s > max_neighbors { return Err(max_neighbors) }
94 }
95 }
96
97 for x in 0..a.bounds.x {
98 for y in 0..a.bounds.y {
99 for z in 0..a.bounds.z {
100 let v = Vec3::new(x, y, z);
101
102 if start_cells.contains(&v) {
103 a.cells.insert(v, a.rules.cell_states - 1);
104 } else {
105 a.cells.insert(v, 0);
106 }
107 }
108 }
109 }
110
111 Ok(a)
112 }
113
114 pub fn tick(&mut self) {
116 let neighbor_counts = self.cells.iter().map(|(v, _)| {
117 let mut count = 0;
118 let mut poss_neighbors = Vec::new();
119
120 poss_neighbors.push(Vec3::new(v.x - 1, v.y, v.z));
124 poss_neighbors.push(Vec3::new(v.x + 1, v.y, v.z));
125
126 poss_neighbors.push(Vec3::new(v.x, v.y - 1, v.z));
128 poss_neighbors.push(Vec3::new(v.x, v.y + 1, v.z));
129
130 poss_neighbors.push(Vec3::new(v.x, v.y, v.z - 1));
132 poss_neighbors.push(Vec3::new(v.x, v.y, v.z + 1));
133
134 if let Method::Moore = self.rules.neighbor_method {
136 poss_neighbors.push(Vec3::new(v.x, v.y - 1, v.z - 1));
138 poss_neighbors.push(Vec3::new(v.x, v.y - 1, v.z + 1));
139 poss_neighbors.push(Vec3::new(v.x, v.y + 1, v.z - 1));
140 poss_neighbors.push(Vec3::new(v.x, v.y + 1, v.z + 1));
141
142 poss_neighbors.push(Vec3::new(v.x - 1, v.y, v.z - 1));
144 poss_neighbors.push(Vec3::new(v.x - 1, v.y, v.z + 1));
145 poss_neighbors.push(Vec3::new(v.x + 1, v.y, v.z - 1));
146 poss_neighbors.push(Vec3::new(v.x + 1, v.y, v.z + 1));
147
148 poss_neighbors.push(Vec3::new(v.x - 1, v.y - 1, v.z));
150 poss_neighbors.push(Vec3::new(v.x - 1, v.y + 1, v.z));
151 poss_neighbors.push(Vec3::new(v.x + 1, v.y - 1, v.z));
152 poss_neighbors.push(Vec3::new(v.x + 1, v.y + 1, v.z));
153
154 poss_neighbors.push(Vec3::new(v.x - 1, v.y - 1, v.z - 1));
156 poss_neighbors.push(Vec3::new(v.x - 1, v.y - 1, v.z + 1));
157 poss_neighbors.push(Vec3::new(v.x - 1, v.y + 1, v.z - 1));
158 poss_neighbors.push(Vec3::new(v.x - 1, v.y + 1, v.z + 1));
159 poss_neighbors.push(Vec3::new(v.x + 1, v.y - 1, v.z - 1));
160 poss_neighbors.push(Vec3::new(v.x + 1, v.y - 1, v.z + 1));
161 poss_neighbors.push(Vec3::new(v.x + 1, v.y + 1, v.z - 1));
162 poss_neighbors.push(Vec3::new(v.x + 1, v.y + 1, v.z + 1));
163 }
164
165 for poss_neighbor in poss_neighbors {
166 if let Some(s) = self.cells.get(&poss_neighbor) {
167 if s > &0 {
168 count += 1;
169 }
170 }
171 }
172
173 (v.clone(), count)
174 }).collect::<HashMap<Vec3, u8>>();
175
176 self.cells.iter_mut().for_each(|(v, s)| {
177 if s == &0 {
178 match self.rules.to_be_born {
180 Rule::Single(ref goal) => {
181 if let Some(neighbor_count) = neighbor_counts.get(v) {
182 if neighbor_count == goal {
183 *s = self.rules.cell_states - 1;
185 }
186 }
187 },
188 Rule::Range(ref goal_range) => {
189 if let Some(neighbor_count) = neighbor_counts.get(v) {
190 if goal_range.contains(neighbor_count) {
191 *s = self.rules.cell_states - 1;
193 }
194 }
195 },
196 Rule::Many(ref goals) => {
197 if let Some(neighbor_count) = neighbor_counts.get(v) {
198 if goals.contains(neighbor_count) {
199 *s = self.rules.cell_states - 1;
201 }
202 }
203 }
204 }
205 } else if s == &(self.rules.cell_states - 1) {
206 match self.rules.to_survive {
208 Rule::Single(ref goal) => {
209 if let Some(neighbor_count) = neighbor_counts.get(v) {
210 if neighbor_count != goal {
211 *s -= 1;
213 }
214 } else {
215 *s = 0;
217 }
218 },
219 Rule::Range(ref goal_range) => {
220 if let Some(neighbor_count) = neighbor_counts.get(v) {
221 if !goal_range.contains(neighbor_count) {
222 *s -= 1;
224 }
225 } else {
226 *s = 0;
228 }
229 },
230 Rule::Many(ref goals) => {
231 if let Some(neighbor_count) = neighbor_counts.get(v) {
232 if !goals.contains(neighbor_count) {
233 *s -= 1;
235 }
236 } else {
237 *s = 0;
239 }
240 }
241 }
242 } else {
243 *s -= 1;
245 }
246 });
247 }
248
249 #[cfg(feature = "rayon")]
251 pub fn par_tick(&mut self) {
252 let neighbor_counts = self.cells.par_iter().map(|(v, _)| {
253 let mut count = 0;
254 let mut poss_neighbors = Vec::new();
255
256 poss_neighbors.push(Vec3::new(v.x - 1, v.y, v.z));
260 poss_neighbors.push(Vec3::new(v.x + 1, v.y, v.z));
261
262 poss_neighbors.push(Vec3::new(v.x, v.y - 1, v.z));
264 poss_neighbors.push(Vec3::new(v.x, v.y + 1, v.z));
265
266 poss_neighbors.push(Vec3::new(v.x, v.y, v.z - 1));
268 poss_neighbors.push(Vec3::new(v.x, v.y, v.z + 1));
269
270 if let Method::Moore = self.rules.neighbor_method {
272 poss_neighbors.push(Vec3::new(v.x, v.y - 1, v.z - 1));
274 poss_neighbors.push(Vec3::new(v.x, v.y - 1, v.z + 1));
275 poss_neighbors.push(Vec3::new(v.x, v.y + 1, v.z - 1));
276 poss_neighbors.push(Vec3::new(v.x, v.y + 1, v.z + 1));
277
278 poss_neighbors.push(Vec3::new(v.x - 1, v.y, v.z - 1));
280 poss_neighbors.push(Vec3::new(v.x - 1, v.y, v.z + 1));
281 poss_neighbors.push(Vec3::new(v.x + 1, v.y, v.z - 1));
282 poss_neighbors.push(Vec3::new(v.x + 1, v.y, v.z + 1));
283
284 poss_neighbors.push(Vec3::new(v.x - 1, v.y - 1, v.z));
286 poss_neighbors.push(Vec3::new(v.x - 1, v.y + 1, v.z));
287 poss_neighbors.push(Vec3::new(v.x + 1, v.y - 1, v.z));
288 poss_neighbors.push(Vec3::new(v.x + 1, v.y + 1, v.z));
289
290 poss_neighbors.push(Vec3::new(v.x - 1, v.y - 1, v.z - 1));
292 poss_neighbors.push(Vec3::new(v.x - 1, v.y - 1, v.z + 1));
293 poss_neighbors.push(Vec3::new(v.x - 1, v.y + 1, v.z - 1));
294 poss_neighbors.push(Vec3::new(v.x - 1, v.y + 1, v.z + 1));
295 poss_neighbors.push(Vec3::new(v.x + 1, v.y - 1, v.z - 1));
296 poss_neighbors.push(Vec3::new(v.x + 1, v.y - 1, v.z + 1));
297 poss_neighbors.push(Vec3::new(v.x + 1, v.y + 1, v.z - 1));
298 poss_neighbors.push(Vec3::new(v.x + 1, v.y + 1, v.z + 1));
299 }
300
301 for poss_neighbor in poss_neighbors {
302 if let Some(s) = self.cells.get(&poss_neighbor) {
303 if s > &0 {
304 count += 1;
305 }
306 }
307 }
308
309 (v.clone(), count)
310 }).collect::<HashMap<Vec3, u8>>();
311
312 self.cells.par_iter_mut().for_each(|(v, s)| {
313 if s == &0 {
314 match self.rules.to_be_born {
316 Rule::Single(ref goal) => {
317 if let Some(neighbor_count) = neighbor_counts.get(v) {
318 if neighbor_count == goal {
319 *s = self.rules.cell_states - 1;
321 }
322 }
323 },
324 Rule::Range(ref goal_range) => {
325 if let Some(neighbor_count) = neighbor_counts.get(v) {
326 if goal_range.contains(neighbor_count) {
327 *s = self.rules.cell_states - 1;
329 }
330 }
331 },
332 Rule::Many(ref goals) => {
333 if let Some(neighbor_count) = neighbor_counts.get(v) {
334 if goals.contains(neighbor_count) {
335 *s = self.rules.cell_states - 1;
337 }
338 }
339 }
340 }
341 } else if s == &(self.rules.cell_states - 1) {
342 match self.rules.to_survive {
344 Rule::Single(ref goal) => {
345 if let Some(neighbor_count) = neighbor_counts.get(v) {
346 if neighbor_count != goal {
347 *s -= 1;
349 }
350 } else {
351 *s = 0;
353 }
354 },
355 Rule::Range(ref goal_range) => {
356 if let Some(neighbor_count) = neighbor_counts.get(v) {
357 if !goal_range.contains(neighbor_count) {
358 *s -= 1;
360 }
361 } else {
362 *s = 0;
364 }
365 },
366 Rule::Many(ref goals) => {
367 if let Some(neighbor_count) = neighbor_counts.get(v) {
368 if !goals.contains(neighbor_count) {
369 *s -= 1;
371 }
372 } else {
373 *s = 0;
375 }
376 }
377 }
378 } else {
379 *s -= 1;
381 }
382 });
383 }
384
385 pub fn get_cells(&self) -> HashMap<Vec3, u8> {
387 self.cells.clone()
388 }
389}