use crate::{trace, FxIndexMap};
use indexmap::map::Entry::Vacant;
use std::{hash::Hash, thread::sleep, time::Duration};
pub struct EHCS<STATE, SUCCESSORS, SUCCESS, HEURISTIC, ITER>
where
STATE: Eq + Hash + Clone,
SUCCESSORS: FnMut(&STATE) -> ITER,
SUCCESS: FnMut(&STATE) -> bool,
HEURISTIC: FnMut(&STATE) -> usize,
ITER: IntoIterator<Item = STATE>,
{
path: Vec<STATE>,
h: usize,
index: usize,
states: FxIndexMap<STATE, usize>,
successors: SUCCESSORS,
success: SUCCESS,
heuristic: HEURISTIC,
}
impl<STATE, SUCCESSORS, SUCCESS, HEURISTIC, ITER> EHCS<STATE, SUCCESSORS, SUCCESS, HEURISTIC, ITER>
where
STATE: Eq + Hash + Clone,
SUCCESSORS: FnMut(&STATE) -> ITER,
SUCCESS: FnMut(&STATE) -> bool,
HEURISTIC: FnMut(&STATE) -> usize,
ITER: IntoIterator<Item = STATE>,
{
pub fn new(
init: &STATE,
successors: SUCCESSORS,
success: SUCCESS,
heuristic: HEURISTIC,
) -> Self {
Self {
path: vec![init.clone()],
h: usize::MAX,
index: 0,
states: FxIndexMap::default(),
successors,
success,
heuristic,
}
}
}
impl<STATE, SUCCESSORS, SUCCESS, HEURISTIC, ITER> Iterator
for EHCS<STATE, SUCCESSORS, SUCCESS, HEURISTIC, ITER>
where
STATE: Eq + Hash + Clone,
SUCCESSORS: FnMut(&STATE) -> ITER,
SUCCESS: FnMut(&STATE) -> bool,
HEURISTIC: FnMut(&STATE) -> usize,
ITER: IntoIterator<Item = STATE>,
{
type Item = Option<Vec<STATE>>;
fn next(&mut self) -> Option<Self::Item> {
if !self.states.is_empty() {
let (node, _) = self.states.get_index(self.index)?;
let h = (self.heuristic)(node);
if h < self.h {
self.path.append(&mut trace(&self.states, self.index));
self.h = h;
self.states.clear();
} else {
for successor in (self.successors)(node) {
if let Vacant(e) = self.states.entry(successor) {
e.insert(self.index);
}
}
}
self.index += 1;
return Some(None);
}
let node = self.path.last().unwrap();
if (self.success)(node) {
return Some(Some(self.path.to_owned()));
}
let best_successor = (self.successors)(node)
.into_iter()
.map(|s| ((self.heuristic)(&s), s))
.min_by(|a, b| a.0.cmp(&b.0));
if let Some((v, s)) = best_successor {
let p_v = (self.heuristic)(node);
if v < p_v {
self.path.push(s);
self.h = p_v;
return Some(None);
} else {
self.index = 0;
self.states.clear();
self.states.insert(node.clone(), 0);
}
} else {
return None;
}
Some(None)
}
}
pub fn solve<STATE, SUCCESSORS, SUCCESS, HEURISTIC, ITER>(
init: &STATE,
successors: SUCCESSORS,
success: SUCCESS,
heuristic: HEURISTIC,
) -> Option<Vec<STATE>>
where
STATE: Eq + Hash + Clone,
SUCCESSORS: FnMut(&STATE) -> ITER,
SUCCESS: FnMut(&STATE) -> bool,
HEURISTIC: FnMut(&STATE) -> usize,
ITER: IntoIterator<Item = STATE>,
{
EHCS::new(init, successors, success, heuristic)
.into_iter()
.find(|i| i.is_some())?
}
pub fn paths<STATE, SUCCESSORS, SUCCESS, HEURISTIC, ITER>(
init: &STATE,
successors: SUCCESSORS,
success: SUCCESS,
heuristic: HEURISTIC,
) -> impl Iterator<Item = Vec<STATE>>
where
STATE: Eq + Hash + Clone,
SUCCESSORS: FnMut(&STATE) -> ITER,
SUCCESS: FnMut(&STATE) -> bool,
HEURISTIC: FnMut(&STATE) -> usize,
ITER: IntoIterator<Item = STATE>,
{
EHCS::new(init, successors, success, heuristic)
.into_iter()
.filter_map(|i| i)
}