use crate::{
heuristic::{Heuristic, next_heuristic},
solvestate::{SolveState, SolveStrategy},
};
pub struct SolveIterItem<'h, 'ss> {
pub solve_state: SolveState<'ss>,
pub next_heuristic: Option<&'h dyn Heuristic>,
}
pub struct SolveIter<'h, 'ss> {
solve_state: SolveState<'ss>,
solve_strategy: SolveStrategy,
heuristics: &'h [Box<dyn Heuristic>],
done: bool,
}
impl<'h, 'ss> Iterator for SolveIter<'h, 'ss> {
type Item = SolveIterItem<'h, 'ss>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
if self.solve_state.complete() {
self.done = true;
return Some(SolveIterItem {
solve_state: self.solve_state.clone(),
next_heuristic: None,
});
}
let h = next_heuristic(&self.solve_state, self.solve_strategy, self.heuristics)?;
let changes = h.changes(&self.solve_state)?;
let old_solve_state = self.solve_state.clone();
self.solve_state.apply_changes(&changes);
Some(SolveIterItem {
solve_state: old_solve_state,
next_heuristic: Some(h),
})
}
}
pub fn solve_iter<'h, 'b>(
solve_state: SolveState<'b>,
solve_strategy: SolveStrategy,
heuristics: &'h [Box<dyn Heuristic>],
) -> SolveIter<'h, 'b> {
SolveIter {
solve_state,
solve_strategy,
heuristics,
done: false,
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use anyhow::Result;
use crate::{board::Board, heuristic::all_heuristics};
use super::*;
#[test]
fn solve_iter_succeeds() -> Result<()> {
let board_str = "wwww\nwkkk\nrrrr\nbbbb";
let board = Board::from_str(board_str)?;
let solve_state = SolveState::from(&board);
let heuristics = all_heuristics(&board);
let mut solve_iter = solve_iter(solve_state, SolveStrategy::Fast, &heuristics);
assert!(solve_iter.next().is_some());
Ok(())
}
#[test]
fn solve_iter_does_not_complete_ambiguous_board() -> Result<()> {
let board_str = "wwww\nkkkk\nrrrr\nbbbb"; let board = Board::from_str(board_str)?;
let solve_state = SolveState::from(&board);
let heuristics = all_heuristics(&board);
let state_iter_items =
solve_iter(solve_state, SolveStrategy::Fast, &heuristics).collect::<Vec<_>>();
assert!(
state_iter_items
.iter()
.all(|item| !item.solve_state.complete())
);
Ok(())
}
}