use super::path_segment::{PathSegment, PathSegment::*};
use crate::{
generics::{grid::a_star_search, Cost, Path},
neighbors::Neighborhood,
Point,
};
#[derive(Debug, Clone)]
pub struct AbstractPath<N: Neighborhood> {
neighborhood: N,
total_cost: Cost,
total_length: usize,
path: Vec<PathSegment>,
end: Point,
current_index: (usize, usize),
}
#[allow(dead_code)]
impl<N: Neighborhood> AbstractPath<N> {
pub fn cost(&self) -> Cost {
self.total_cost
}
pub fn length(&self) -> usize {
self.total_length
}
pub fn safe_next(&mut self, get_cost: impl FnMut(Point) -> isize) -> Option<Point> {
self.internal_next(Some(get_cost))
}
fn internal_next(&mut self, get_cost: Option<impl FnMut(Point) -> isize>) -> Option<Point> {
if self.current_index.0 >= self.path.len() {
return None;
}
let mut current = &self.path[self.current_index.0];
if let Unknown { start, end, .. } = *current {
let path = a_star_search(
|p| self.neighborhood.get_all_neighbors(p),
get_cost.expect("Tried calling next() on a Path that is not fully known. Use safe_next() instead."),
start,
end,
|p| self.neighborhood.heuristic(p, end),
)
.unwrap_or_else(|| {
panic!(
"Impossible Path marked as Possible: {:?} -> {:?}",
start, end
)
});
self.path[self.current_index.0] = Known(path);
current = &self.path[self.current_index.0];
self.current_index.1 = 1; }
let path = match current {
Known(path) => path,
Unknown { .. } => panic!("Internal Error #1 in AbstractPath. Please report this"),
};
let ret = Some(path[self.current_index.1]);
self.current_index.1 += 1;
if self.current_index.1 >= path.len() {
self.current_index.0 += 1;
self.current_index.1 = 1;
}
if ret == Some(self.end) {
self.current_index.0 = self.path.len();
}
ret
}
pub fn resolve(mut self, mut get_cost: impl FnMut(Point) -> isize) -> Path<Point> {
let mut result = Vec::with_capacity(self.total_length);
while let Some(pos) = self.safe_next(&mut get_cost) {
result.push(pos);
}
Path::new(result, self.total_cost)
}
pub(crate) fn new(neighborhood: N, start: Point) -> AbstractPath<N> {
AbstractPath {
neighborhood,
total_cost: 0,
total_length: 0,
path: vec![],
end: start,
current_index: (0, 1),
}
}
pub(crate) fn from_known_path(neighborhood: N, path: Path<Point>) -> AbstractPath<N> {
let end = path[path.len() - 1];
AbstractPath {
neighborhood,
total_cost: path.cost(),
total_length: path.len(),
path: vec![Known(path)],
end,
current_index: (0, 1),
}
}
pub(crate) fn from_node(neighborhood: N, node: Point) -> AbstractPath<N> {
AbstractPath {
neighborhood,
total_cost: 0,
total_length: 0,
path: vec![],
end: node,
current_index: (0, 1),
}
}
pub(crate) fn add_path_segment(&mut self, path: PathSegment) -> &mut Self {
assert!(
self.end == path.start(),
"Added disconnected PathSegment: expected {:?}, got {:?}",
self.end,
path.start()
);
self.total_cost += path.cost();
self.total_length += path.len();
self.end = path.end();
self.path.push(path);
self
}
pub(crate) fn add_path(&mut self, path: Path<Point>) -> &mut Self {
self.total_cost += path.cost();
self.total_length += path.len();
self.end = path[path.len() - 1];
self.path.push(Known(path));
self
}
pub(crate) fn add_node(&mut self, node: Point, cost: Cost, len: usize) -> &mut Self {
self.path.push(Unknown {
start: self.end,
end: node,
cost,
len,
});
self.total_cost += cost;
self.total_length += len;
self.end = node;
self
}
pub(crate) fn set_goal(&mut self, goal: Point) {
self.end = goal;
}
}
impl<N: Neighborhood> Iterator for AbstractPath<N> {
type Item = Point;
fn next(&mut self) -> Option<Point> {
#[allow(unused_assignments)]
let mut arg = Some(dummy_cost_fn);
arg = None;
self.internal_next(arg)
}
}
fn dummy_cost_fn(_: Point) -> isize {
0
}