use crate::grid::{Grid, Point};
use std::cmp::Ordering;
use std::collections::{BinaryHeap, HashMap};
type Cost = u32;
#[derive(Debug, Eq, PartialEq)]
pub struct Node {
pub point: Point,
pub cost: Cost,
pub heuristic: Cost,
}
impl Ord for Node {
fn cmp(&self, other: &Self) -> Ordering {
(other.cost + other.heuristic).cmp(&(self.cost + self.heuristic))
}
}
impl PartialOrd for Node {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
pub fn manhattan_distance(a: Point, b: Point) -> Cost {
((a.x as i32 - b.x as i32).abs() + (a.y as i32 - b.y as i32).abs()) as Cost
}
pub fn a_star(grid: &Grid, start: Point, goal: Point) -> Option<Vec<Point>> {
let mut frontier = BinaryHeap::new();
let mut came_from: HashMap<Point, Point> = HashMap::new();
let mut cost_so_far: HashMap<Point, Cost> = HashMap::new();
cost_so_far.insert(start, 0);
frontier.push(Node {
point: start,
cost: 0,
heuristic: manhattan_distance(start, goal),
});
while let Some(current) = frontier.pop() {
if current.point == goal {
let mut path = vec![goal];
let mut curr = goal;
while curr != start {
curr = came_from[&curr];
path.push(curr);
}
path.reverse();
return Some(path);
}
for next_point in grid.neighbors(current.point) {
let new_cost = cost_so_far[¤t.point] + 1;
if !cost_so_far.contains_key(&next_point) || new_cost < cost_so_far[&next_point] {
cost_so_far.insert(next_point, new_cost);
let priority = manhattan_distance(next_point, goal);
frontier.push(Node {
point: next_point,
cost: new_cost,
heuristic: priority,
});
came_from.insert(next_point, current.point);
}
}
}
None }