searchlib 0.1.2

Satisficing and optimal search algorithms
Documentation
//! [Hill Climbing Search](https://en.wikipedia.org/wiki/Hill_climbing)

use std::hash::Hash;

pub struct HCS<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>,
    successors: SUCCESSORS,
    success: SUCCESS,
    heuristic: HEURISTIC,
}

impl<STATE, SUCCESSORS, SUCCESS, HEURISTIC, ITER> HCS<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()],
            successors,
            success,
            heuristic,
        }
    }
}

impl<STATE, SUCCESSORS, SUCCESS, HEURISTIC, ITER> Iterator
    for HCS<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> {
        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);
                return Some(None);
            }
        }
        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>,
{
    HCS::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>,
{
    HCS::new(init, successors, success, heuristic)
        .into_iter()
        .filter_map(|i| i)
}