hexagon_map/sparse_map/
action_field.rs

1use 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    /// Set the passable function.
16    ///
17    /// # Arguments
18    ///
19    /// * `passable`:  A function that returns true if the point is passable.
20    ///
21    /// returns: PathFinder<T>
22    ///
23    /// # Examples
24    ///
25    /// ```
26    /// # use hexagon_map::HexagonMap;
27    /// ```
28    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    /// Get all passable neighbors from a point
61    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}