use std::collections::BinaryHeap;
use bevy::math::UVec3;
use indexmap::map::Entry::{Occupied, Vacant};
use ndarray::ArrayView3;
use crate::graph::Graph;
use crate::raycast::line_of_sight_ordinal;
use crate::{neighbor::Neighborhood, path::Path, FxIndexMap, Point, SmallestCostHolder};
#[allow(dead_code)]
pub fn theta_grid<N: Neighborhood>(
neighborhood: &N,
grid: &ArrayView3<Point>,
start: UVec3,
goal: UVec3,
size_hint: usize,
) -> Option<Path> {
let mut to_visit = BinaryHeap::with_capacity(size_hint / 2);
to_visit.push(SmallestCostHolder {
estimated_cost: 0,
cost: 0,
index: 0,
});
let mut visited: FxIndexMap<UVec3, (usize, u32)> = FxIndexMap::default();
visited.insert(start, (usize::MAX, 0));
while let Some(SmallestCostHolder { cost, index, .. }) = to_visit.pop() {
let neighbors = {
let (current_pos, &(_, current_cost)) = visited.get_index(index).unwrap();
if *current_pos == goal {
let mut current = index;
let mut steps = vec![];
while current != usize::MAX {
let (pos, _) = visited.get_index(current).unwrap();
steps.push(*pos);
current = visited.get(pos).unwrap().0;
}
steps.reverse();
return Some(Path::new(steps, current_cost));
}
if cost > current_cost {
continue;
}
let mut neighbors = vec![];
neighborhood.neighbors(grid, *current_pos, &mut neighbors);
neighbors
};
for &neighbor in neighbors.iter() {
let neighbor_point = &grid[[
neighbor.x as usize,
neighbor.y as usize,
neighbor.z as usize,
]];
if neighbor_point.wall || neighbor_point.cost == 0 {
continue;
}
let (parent_pos, (parent_index, parent_cost)) = visited.get_index(index).unwrap();
let (new_cost, parent) = if line_of_sight_ordinal(grid, *parent_pos, neighbor) {
(parent_cost + neighbor_point.cost, *parent_index)
} else {
(cost + neighbor_point.cost, index)
};
let h;
let n;
match visited.entry(neighbor) {
Vacant(e) => {
h = neighborhood.heuristic(neighbor, goal);
n = e.index();
e.insert((parent, new_cost));
}
Occupied(mut e) => {
if e.get().1 > new_cost {
h = neighborhood.heuristic(neighbor, goal);
n = e.index();
e.insert((parent, new_cost));
} else {
continue;
}
}
}
to_visit.push(SmallestCostHolder {
estimated_cost: h,
cost: new_cost,
index: n,
});
}
}
None
}
#[allow(dead_code)]
pub fn theta_graph<N: Neighborhood>(
neighborhood: &N,
graph: &Graph,
grid: &ArrayView3<Point>,
start: UVec3,
goal: UVec3,
size_hint: usize,
) -> Option<Path> {
let mut to_visit = BinaryHeap::with_capacity(size_hint / 2);
to_visit.push(SmallestCostHolder {
estimated_cost: 0,
cost: 0,
index: 0,
});
let mut visited: FxIndexMap<UVec3, (usize, u32)> = FxIndexMap::default();
visited.insert(start, (usize::MAX, 0));
while let Some(SmallestCostHolder { cost, index, .. }) = to_visit.pop() {
let (neighbors, _) = {
let (current_pos, &(_, current_cost)) = visited.get_index(index).unwrap();
if *current_pos == goal {
let mut current = index;
let mut steps = vec![];
while current != usize::MAX {
let (pos, _) = visited.get_index(current).unwrap();
steps.push(*pos);
current = visited.get(pos).unwrap().0;
}
steps.reverse();
return Some(Path::new(steps, current_cost));
}
if cost > current_cost {
continue;
}
let node = graph.get_node(*current_pos).unwrap();
let neighbors = node.get_edges();
(neighbors, current_pos.clone())
};
for &neighbor in neighbors.iter() {
let neighbor_node = graph.get_node(neighbor).unwrap();
if neighbor_node.edges.is_empty() {
continue;
}
let (parent_pos, (parent_index, parent_cost)) = visited.get_index(index).unwrap();
let neighbor_cost = neighborhood.heuristic(neighbor, goal);
let (new_cost, parent) = if line_of_sight_ordinal(grid, *parent_pos, neighbor) {
(parent_cost + neighbor_cost, *parent_index)
} else {
(cost + neighbor_cost, index)
};
let h;
let n;
match visited.entry(neighbor) {
Vacant(e) => {
h = neighborhood.heuristic(neighbor, goal);
n = e.index();
e.insert((parent, new_cost));
}
Occupied(mut e) => {
if e.get().1 > new_cost {
h = neighborhood.heuristic(neighbor, goal);
n = e.index();
e.insert((parent, new_cost));
} else {
continue;
}
}
}
to_visit.push(SmallestCostHolder {
estimated_cost: h,
cost: new_cost,
index: n,
});
}
}
None
}