1use num_traits::Zero;
12use pi_null::Null;
13use std::{
14 cmp::{Ordering, Reverse},
15 collections::BinaryHeap,
16 fmt::Debug,
17 mem,
18};
19use std::ops::Deref;
20
21#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Debug)]
23pub struct NodeIndex(pub usize);
24
25impl Deref for NodeIndex {
26 type Target = usize;
27
28 fn deref(&self) -> &Self::Target {
29 &self.0
30 }
31}
32
33
34impl Null for NodeIndex {
35 fn is_null(&self) -> bool {
36 self.0.is_null()
37 }
38
39 fn null() -> Self {
40 NodeIndex(usize::null())
41 }
42}
43#[derive(PartialEq, Eq, Clone)]
45pub enum NodeState {
46 None,
48 FromOpen,
50 ToOpen,
52 FromClose,
54 ToClose,
56}
57#[derive(Debug)]
59pub enum AStarResult {
60 Found,
62 NotFound(NodeIndex),
64 LimitNotFound(NodeIndex),
66}
67
68pub trait NodeEntry<N: PartialOrd + Zero + Copy + Debug> {
70 fn g(&self) -> N;
71 fn h(&self) -> N;
72 fn state(&self) -> NodeState;
73 fn parent(&self) -> NodeIndex;
74 fn clear(&mut self, version: usize);
75}
76
77pub struct Finder<N: PartialOrd + Zero + Copy + Debug, E: NodeEntry<N> + Default> {
79 pub nodes: Vec<E>,
81 pub neighbors: Vec<FNode<N>>,
83 pub version: usize,
85}
86
87pub struct AStar<N: PartialOrd + Zero + Copy + Debug, E: NodeEntry<N> + Default> {
93 from_open: BinaryHeap<Reverse<NodeNeighbors<N>>>,
95 finder: Finder<N, E>,
97}
98
99impl<N: PartialOrd + Zero + Copy + Debug, E: NodeEntry<N> + Default> AStar<N, E> {
100 pub fn with_capacity(map_capacity: usize, node_number: usize) -> Self {
103 let mut vec = Vec::with_capacity(map_capacity);
104 vec.resize_with(map_capacity, || E::default());
105 AStar {
106 from_open: BinaryHeap::with_capacity(node_number),
107 finder: Finder {
108 nodes: vec,
109 neighbors: Vec::with_capacity(node_number),
110 version: 0,
111 },
112 }
113 }
114 pub fn resize(&mut self, map_capacity: usize) {
116 self.finder.nodes.resize_with(map_capacity, || E::default())
117 }
118 pub fn find<Arg>(
133 &mut self,
134 start: NodeIndex,
135 end: NodeIndex,
136 max_number: usize,
137 arg: &mut Arg,
138 make_neighbors: fn(&mut Arg, NodeIndex, NodeIndex, &mut Finder<N, E>) -> NodeNeighbors<N>,
139 ) -> AStarResult {
140 self.from_open.clear();
141 self.finder.neighbors.clear();
142 self.finder.version += 1;
143 self.finder.nodes[start.0].clear(self.finder.version);
144 let mut nn = make_neighbors(arg, start, end, &mut self.finder);
146 let mut near = nn.node;
147 let mut near_h = nn.f;
148 println!("start: {:?}, end: {:?}, h0: {:?}", start, end, near_h);
149 loop {
150 let node = nn.pop(&self.finder, NodeState::FromOpen);
152 if node.is_null() {
154 if let Some(n) = self.from_open.pop() {
156 nn = n.0;
157 } else {
158 return AStarResult::NotFound(near);
160 }
161 continue;
162 }
163 if node == end {
165 return AStarResult::Found;
166 }
167 if nn.start < nn.end {
169 let mut nn1 = make_neighbors(arg, node, end, &mut self.finder);
171 let h = self.finder.nodes[node.0].h();
172 if h < near_h {
174 near = node;
175 near_h = h;
176 }
177 if nn1.start < nn1.end {
179 if nn1 < nn {
181 nn1 = mem::replace(&mut nn, nn1);
182 }
183 self.from_open.push(Reverse(nn1));
185 if self.from_open.len() > max_number {
187 return AStarResult::LimitNotFound(node);
188 }
189 }
190 } else {
191 nn = make_neighbors(arg, node, end, &mut self.finder);
193 let h = self.finder.nodes[node.0].h();
194 if h < near_h {
196 near = node;
197 near_h = h;
198 }
199 continue;
200 }
201 if let Some(n) = self.from_open.peek() {
203 if n.0 < nn {
205 let nn2 = self.from_open.pop().unwrap().0;
207 self.from_open.push(Reverse(nn));
209 nn = nn2;
210 }
211 }
212 }
213 }
214 pub fn result_iter<'a>(&'a self, node: NodeIndex) -> ResultIterator<'a, N, E> {
216 ResultIterator {
217 finder: &self.finder,
218 node,
219 }
220 }
221}
222
223#[derive(Clone)]
225pub struct ResultIterator<'a, N: PartialOrd + Zero + Copy + Debug, E: NodeEntry<N> + Default> {
226 pub finder: &'a Finder<N, E>,
227 pub node: NodeIndex,
228}
229
230impl<'a, N: PartialOrd + Zero + Copy + Debug, E: NodeEntry<N> + Default> Iterator
231 for ResultIterator<'a, N, E>
232{
233 type Item = NodeIndex;
234 fn next(&mut self) -> Option<Self::Item> {
235 if self.node.is_null() {
236 return None;
237 }
238 let old = self.node;
239 let e = &self.finder.nodes[self.node.0];
240 self.node = e.parent();
241 Some(old)
242 }
243}
244
245#[derive(Debug, Clone)]
247pub struct NodeNeighbors<N: PartialOrd + Zero + Copy + Debug> {
248 pub f: N,
249 pub node: NodeIndex,
250 pub start: usize,
251 pub end: usize,
252}
253
254impl<N: PartialOrd + Zero + Copy + Debug> NodeNeighbors<N> {
255 fn pop<E: NodeEntry<N> + Default>(
257 &mut self,
258 finder: &Finder<N, E>,
259 state: NodeState,
260 ) -> NodeIndex {
261 while self.start < self.end {
262 let n = &finder.neighbors[self.start];
263 let e = &finder.nodes[n.node.0];
264 self.start += 1;
265 if e.state() == state && e.parent() == self.node {
267 while self.start < self.end {
269 let s = &finder.neighbors[self.start];
270 let e = &finder.nodes[s.node.0];
271 if e.state() == state && e.parent() == self.node {
272 self.f = e.g() + e.h();
273 break;
274 }
275 self.start += 1;
276 }
277 return n.node;
278 }
279 }
280 NodeIndex(usize::MAX)
281 }
282}
283impl<N: PartialOrd + Zero + Copy + Debug> Eq for NodeNeighbors<N> {}
285impl<N: PartialOrd + Zero + Copy + Debug> PartialEq for NodeNeighbors<N> {
287 fn eq(&self, other: &Self) -> bool {
288 self.f.eq(&other.f)
289 }
290}
291impl<N: PartialOrd + Zero + Copy + Debug> PartialOrd for NodeNeighbors<N> {
293 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
294 self.f.partial_cmp(&other.f)
295 }
296}
297impl<N: PartialOrd + Zero + Copy + Debug> Ord for NodeNeighbors<N> {
299 fn cmp(&self, other: &Self) -> Ordering {
300 match self.f.partial_cmp(&other.f) {
301 None => self.node.cmp(&other.node),
302 Some(r) => r,
303 }
304 }
305}
306
307#[derive(Clone)]
309pub struct FNode<N: PartialOrd + Zero + Copy + Debug> {
310 pub f: N,
311 pub node: NodeIndex,
312}
313
314impl<N: PartialOrd + Zero + Copy + Debug> Eq for FNode<N> {}
316impl<N: PartialOrd + Zero + Copy + Debug> PartialEq for FNode<N> {
318 fn eq(&self, other: &Self) -> bool {
319 self.f.eq(&other.f)
320 }
321}
322impl<N: PartialOrd + Zero + Copy + Debug> PartialOrd for FNode<N> {
324 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
325 self.f.partial_cmp(&other.f)
326 }
327}
328impl<N: PartialOrd + Zero + Copy + Debug> Ord for FNode<N> {
330 fn cmp(&self, other: &Self) -> Ordering {
331 match self.f.partial_cmp(&other.f) {
332 None => self.node.cmp(&other.node),
333 Some(r) => r,
334 }
335 }
336}
337
338pub struct DualAStar<N: PartialOrd + Zero + Copy + Debug, E: NodeEntry<N> + Default> {
344 pub astar: AStar<N, E>,
346 pub to_open: BinaryHeap<NodeNeighbors<N>>,
348}