use std::collections::BinaryHeap;
use movingai::Coords2D;
use movingai::Map2D;
use crate::node::Node;
use crate::utils::{distance, rewind};
use crate::Route;
pub fn a_star_path<U, T: Map2D<U>>(map: &T, start: Coords2D, goal: Coords2D) -> Option<Route> {
if start == goal {
return Some(Route::from((0.0, vec![])));
}
let capacity = (1 + start.0 + 1 - start.0 - 1) * (1 + start.1 + 1 - start.1 - 1);
let mut open = BinaryHeap::with_capacity(capacity);
let mut closed = Vec::<Node>::with_capacity(capacity);
open.push(Node {
f: distance(start, goal),
g: 0.0,
h: distance(start, goal),
position: start,
parent: start,
});
while let Some(node_current) = open.pop() {
if node_current.position == goal {
let path = rewind(&node_current, &closed);
let route = Route::from((node_current.g, path));
return Some(route);
}
for successor in map.neighbors(node_current.position) {
let distance_to_goal = distance(successor, goal);
let distance_from_parent = distance(node_current.position, successor);
let total_distance = node_current.g + distance_from_parent;
if let Some(closed) = closed.iter().find(|x| x.position == successor) {
if closed.f < total_distance + distance_to_goal {
continue;
}
}
if let Some(old_open) = open.iter().find(|x| x.position == successor) {
if old_open.g < total_distance {
continue;
}
}
let node_successor = Node {
f: total_distance + distance_to_goal,
g: total_distance,
h: distance_to_goal,
position: successor,
parent: node_current.position,
};
open.push(node_successor);
}
if let Some(index) = closed
.iter()
.position(|x| x.position == node_current.position)
{
closed.remove(index);
}
closed.push(node_current);
}
None
}