use crate::Hex;
#[cfg(feature = "bevy_platform")]
use bevy_platform::collections::HashMap;
use std::collections::BinaryHeap;
#[cfg(not(feature = "bevy_platform"))]
use std::collections::HashMap;
struct Node {
coord: Hex,
score: u32,
}
impl PartialEq for Node {
fn eq(&self, other: &Self) -> bool {
self.score == other.score
}
}
impl Eq for Node {}
impl PartialOrd for Node {
fn partial_cmp(&self, rhs: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(rhs))
}
}
impl Ord for Node {
fn cmp(&self, rhs: &Self) -> std::cmp::Ordering {
rhs.score.cmp(&self.score)
}
}
fn reconstruct_path(came_from: &HashMap<Hex, Hex>, end: Hex) -> Vec<Hex> {
let mut path: Vec<_> =
std::iter::successors(Some(end), move |¤t| came_from.get(¤t).copied())
.collect();
path.reverse();
path
}
pub fn a_star(start: Hex, end: Hex, cost: impl Fn(Hex, Hex) -> Option<u32>) -> Option<Vec<Hex>> {
let heuristic = |h: Hex| h.unsigned_distance_to(end);
cost(end, end)?;
let start_node = Node {
coord: start,
score: heuristic(start) + cost(start, start)?,
};
let mut open = BinaryHeap::new();
open.push(start_node);
let mut costs = HashMap::new();
costs.insert(start, 0);
let mut came_from = HashMap::new();
while let Some(node) = open.pop() {
if node.coord == end {
return Some(reconstruct_path(&came_from, end));
}
let current_cost = costs[&node.coord];
for neighbor in node.coord.all_neighbors() {
let Some(cost) = cost(node.coord, neighbor) else {
continue;
};
let neighbor_cost = current_cost + cost;
if !costs.contains_key(&neighbor) || costs[&neighbor] > neighbor_cost {
came_from.insert(neighbor, node.coord);
costs.insert(neighbor, neighbor_cost);
open.push(Node {
coord: neighbor,
score: neighbor_cost + heuristic(neighbor),
});
}
}
}
None
}