hexagon_map/sparse_map/
action_field.rs1use super::*;
2use crate::HexPoint;
3use std::vec::IntoIter;
4
5pub struct ActionFieldSolver<'a, T> {
6 map: &'a HexagonMap<T>,
7 open: BTreeMap<CubicPoint, f64>,
8 close: BTreeMap<CubicPoint, f64>,
9 passable: Box<dyn Fn(&CubicPoint, &T) -> bool>,
10 action_cost: Box<dyn Fn(&CubicPoint, &T) -> f64>,
11 action_points: f64,
12}
13
14impl<T> HexagonMap<T> {
15 pub fn action_field(&self, start: CubicPoint, action: f64) -> ActionFieldSolver<T> {
29 let mut open = BTreeMap::new();
30 open.insert(start, 0.0);
31 ActionFieldSolver {
32 map: self,
33 open,
34 close: Default::default(),
35 action_points: action,
36 passable: Box::new(|_, _| true),
37 action_cost: Box::new(|_, _| 0.0),
38 }
39 }
40}
41
42impl<'a, T> ActionFieldSolver<'a, T> {
43 pub fn with_passable<F>(mut self, passable: F) -> Self
44 where
45 F: Fn(&CubicPoint, &T) -> bool + 'static,
46 {
47 self.passable = Box::new(passable);
48 self
49 }
50 pub fn with_cost<F>(mut self, cost: F) -> Self
51 where
52 F: Fn(&CubicPoint, &T) -> f64 + 'static,
53 {
54 self.action_cost = Box::new(cost);
55 self
56 }
57}
58
59impl<'a, T> ActionFieldSolver<'a, T> {
60 pub fn neighbors(&self, point: &CubicPoint) -> Vec<(CubicPoint, f64)> {
62 let mut neighbors = Vec::with_capacity(6);
63 for direction in Orientation::all() {
64 let key = point.go(direction);
65 if let Some(value) = self.map.sparse.get(&key) {
66 if !(self.passable)(&key, value) {
67 continue;
68 }
69 if self.close.contains_key(&key) {
70 continue;
71 }
72 let cost = (self.action_cost)(point, value);
73 neighbors.push((key, cost));
74 }
75 }
76 neighbors
77 }
78 pub fn solve(mut self) -> impl Iterator<Item = (f64, CubicPoint)> {
79 while let Some((point, cost)) = self.open.pop_first() {
80 for (neighbor, neighbor_cost) in self.neighbors(&point) {
81 let new_cost = cost + neighbor_cost;
82 if new_cost > self.action_points {
83 continue;
84 }
85 else {
86 self.open.insert(neighbor, new_cost);
87 }
88 }
89 self.close.insert(point, cost);
90 }
91 self.close.iter().map(|(k, v)| (*v, *k)).sorted_unstable_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal))
92 }
93}
94
95impl<'a, T> IntoIterator for ActionFieldSolver<'a, T> {
96 type Item = (f64, CubicPoint);
97 type IntoIter = IntoIter<Self::Item>;
98 fn into_iter(self) -> Self::IntoIter {
99 self.solve().collect_vec().into_iter()
100 }
101}