From e18e242eae971e906959afe1310f42ad1b6f9f44 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 19 May 2026 08:02:00 -0700 Subject: [PATCH] refactor is_winnable --- card_game/src/lib.rs | 68 +++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/card_game/src/lib.rs b/card_game/src/lib.rs index 17c4bc9..44a82c3 100644 --- a/card_game/src/lib.rs +++ b/card_game/src/lib.rs @@ -321,18 +321,29 @@ impl SessionStats { } } -pub struct Session { +#[derive(Clone)] +pub struct Session +where + G::Config: Clone, + G::Instruction: Clone, +{ stats: SessionStats, config: G::Config, state: SessionState, } #[derive(Clone, Eq, Hash, PartialEq)] -pub struct SessionState { +pub struct SessionState +where + G::Instruction: Clone, +{ seed: G, state: G, history: Vec, } -impl SessionState { +impl SessionState +where + G::Instruction: Clone, +{ fn new(state: G) -> Self { Self { seed: state.clone(), @@ -345,6 +356,7 @@ impl Session where G: Clone + Eq + core::hash::Hash, G::Stats: Clone + Default, + G::Config: Clone, G::Instruction: Clone + Eq + core::hash::Hash, { pub fn new(state: G, config: G::Config) -> Self { @@ -390,38 +402,28 @@ where self.state.is_win() } pub fn is_winnable(&self) -> Option> { - let mut observed = std::collections::HashSet::new(); - struct StateMachine { - state: G, - possible_instructions_iter: P, - instruction: I, - } - let mut dummy_stats = self.stats.inner_stats.clone(); - let mut state = self.state.state.clone(); - let mut it = state.possible_instructions(); - let mut path = Vec::new(); - 'outer: while !state.is_win() { - observed.insert(state.clone()); - for instruction in &mut it { - let mut next_state = state.clone(); - next_state.process_instruction(&mut dummy_stats, &self.config, instruction.clone()); - if !observed.contains(&next_state) { - let possible_instructions_iter = - core::mem::replace(&mut it, next_state.possible_instructions()); - let state = core::mem::replace(&mut state, next_state); - path.push(StateMachine { - state, - possible_instructions_iter, - instruction, - }); - continue 'outer; - } + let mut state_moves = std::collections::HashMap::new(); + let mut state = self.clone(); + while !state.is_win() { + // Continue existing iterator if it exists + let it = state_moves + .entry(state.state().clone()) + .or_insert_with(|| state.state().possible_instructions()); + + // Run one possible move + if let Some(instruction) = it.next() { + state.process_instruction(instruction); + continue; + } + + // No more moves. If we can't undo we're done + if state.history().is_empty() { + return None; + } else { + state.undo(); } - let last_state = path.pop()?; - state = last_state.state; - it = last_state.possible_instructions_iter; } - Some(path.into_iter().map(|state| state.instruction).collect()) + Some(state.state.history) } } impl Game for SessionState