implement solve budget

This commit is contained in:
2026-05-29 14:09:20 -07:00
parent 1de633adb3
commit 9f6514367d
2 changed files with 29 additions and 5 deletions
+27 -3
View File
@@ -312,6 +312,18 @@ impl<const CAP: usize> Pile<CAP, CAP> {
} }
} }
#[derive(Clone, Debug)]
pub enum SolveError {
MovesBudgetExceeded,
StatesBudgetExceeded,
}
impl std::fmt::Display for SolveError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
impl std::error::Error for SolveError {}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum SessionInstruction<I> { pub enum SessionInstruction<I> {
Undo, Undo,
@@ -338,12 +350,16 @@ impl<S> SessionStats<S> {
pub struct SessionConfig<C> { pub struct SessionConfig<C> {
pub inner: C, pub inner: C,
pub undo_penalty: i32, pub undo_penalty: i32,
pub solve_moves_budget: u64,
pub solve_states_budget: u64,
} }
impl<C> SessionConfig<C> { impl<C> SessionConfig<C> {
fn new_default(inner: C) -> Self { fn new_default(inner: C) -> Self {
Self { Self {
inner, inner,
undo_penalty: -15, undo_penalty: -15,
solve_moves_budget: 100_000,
solve_states_budget: 100_000,
} }
} }
} }
@@ -438,10 +454,18 @@ where
pub fn is_win(&self) -> bool { pub fn is_win(&self) -> bool {
self.state.is_win() self.state.is_win()
} }
pub fn is_winnable(&self) -> Option<Vec<StateSnapshot<G>>> { pub fn solve(&self) -> Result<Option<Vec<StateSnapshot<G>>>, SolveError> {
let mut state_moves = std::collections::HashMap::new(); let mut state_moves = std::collections::HashMap::new();
let mut state = self.clone(); let mut state = self.clone();
let mut moves = 0;
while !state.is_win() { while !state.is_win() {
moves += 1;
if self.config.solve_moves_budget < moves {
return Err(SolveError::MovesBudgetExceeded);
}
if self.config.solve_states_budget < state_moves.len() as u64 {
return Err(SolveError::StatesBudgetExceeded);
}
// Continue existing iterator if it exists // Continue existing iterator if it exists
let it = state_moves let it = state_moves
.entry(state.state().state().clone()) .entry(state.state().state().clone())
@@ -460,12 +484,12 @@ where
// No more moves. If we can't undo we're done // No more moves. If we can't undo we're done
if state.history().is_empty() { if state.history().is_empty() {
return None; return Ok(None);
} else { } else {
state.undo(); state.undo();
} }
} }
Some(state.state.history) Ok(Some(state.state.history))
} }
} }
impl<G: Game<Score = i32>> Game for SessionState<G> impl<G: Game<Score = i32>> Game for SessionState<G>
+2 -2
View File
@@ -3,8 +3,8 @@ use klondike::Klondike;
#[test] #[test]
fn test_is_winnable() { fn test_is_winnable() {
// is winnable // is winnable
let is_winnable = Session::new_default(Klondike::with_seed(124)).is_winnable(); let solution_result = Session::new_default(Klondike::with_seed(124)).solve();
if let Some(win_moves) = is_winnable { if let Ok(Some(win_moves)) = solution_result {
// for (i, ins) in win_moves.into_iter().enumerate() { // for (i, ins) in win_moves.into_iter().enumerate() {
// println!("{i} = {:?}", ins.instruction()); // println!("{i} = {:?}", ins.instruction());
// } // }