// TODO: pub struct ValidInstruction(I); pub trait Game { type Instruction; fn possible_instructions(&self) -> impl Iterator + use; fn is_instruction_valid(&self, instruction: Self::Instruction) -> bool; fn process_instruction(&mut self, instruction: Self::Instruction); fn is_win(&self) -> bool; } #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum Suit { Spades = 0b00, Hearts = 0b01, Clubs = 0b10, Diamonds = 0b11, } impl Suit { pub const SUITS: [Self; 4] = [Self::Spades, Self::Hearts, Self::Clubs, Self::Diamonds]; /// Is the suit red. pub fn is_red(self) -> bool { self as u8 & 0b01 != 0 } /// Is the suit shape spikey. (Bouba/kiki) pub fn is_kiki(self) -> bool { self as u8 & 0b10 != 0 } } #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct CardValue(u8); impl CardValue { pub const ACE: Self = CardValue(1); pub const TWO: Self = CardValue(2); pub const THREE: Self = CardValue(3); pub const FOUR: Self = CardValue(4); pub const FIVE: Self = CardValue(5); pub const SIX: Self = CardValue(6); pub const SEVEN: Self = CardValue(7); pub const EIGHT: Self = CardValue(8); pub const NINE: Self = CardValue(9); pub const TEN: Self = CardValue(10); pub const JACK: Self = CardValue(11); pub const QUEEN: Self = CardValue(12); pub const KING: Self = CardValue(13); pub fn get(self) -> u8 { self.0 } pub fn checked_add(self, offset: u8) -> Option { let new_value = self.0.checked_add(offset)?; if 13 < new_value { None } else { Some(CardValue(new_value)) } } pub fn checked_sub(self, offset: u8) -> Option { let new_value = self.0.checked_sub(offset)?; if new_value < 1 { None } else { Some(CardValue(new_value)) } } } /// An identifier which specifies the deck id, suit, and card value. /// 2 bits for deck ID /// 2 bits for suit ID /// 4 bits for card Value /// TODO: better encoding for slightly more decks #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Card(u8); impl Card { pub fn new(deck: u8, suit: Suit, CardValue(value): CardValue) -> Self { Self(deck << 6 | (suit as u8) << 4 | value) } pub fn value(&self) -> CardValue { let masked = self.0 & 0b1111; CardValue(masked) } pub fn suit(&self) -> Suit { let red = self.is_red(); let kiki = self.is_kiki(); match (kiki, red) { (false, false) => Suit::Spades, (false, true) => Suit::Hearts, (true, false) => Suit::Clubs, (true, true) => Suit::Diamonds, } } /// Is the suit red. pub fn is_red(&self) -> bool { self.0 & 0b010000 != 0 } /// Is the suit shape spikey. (Bouba/kiki) pub fn is_kiki(&self) -> bool { self.0 & 0b100000 != 0 } pub fn deck(&self) -> u8 { self.0 >> 6 } } #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Stack(arrayvec::ArrayVec); impl Stack { pub fn new() -> Self { Self(arrayvec::ArrayVec::new()) } } impl Stack<52> { /// Generate a full deck of cards with the specified deck id. pub fn full_deck(deck: u8) -> Self { let mut stack = arrayvec::ArrayVec::new(); for suit in Suit::SUITS { for value in 1..=13 { stack.push(Card::new(deck, suit, CardValue(value))); } } Stack(stack) } } impl From> for Stack { fn from(value: arrayvec::ArrayVec) -> Self { Self(value) } } impl core::ops::Deref for Stack { type Target = arrayvec::ArrayVec; fn deref(&self) -> &Self::Target { &self.0 } } impl core::ops::DerefMut for Stack { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl IntoIterator for Stack { type Item = Card; type IntoIter = arrayvec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Pile { face_down: Stack, face_up: Stack, } impl Pile { pub fn new() -> Self { Self { face_down: Stack::new(), face_up: Stack::new(), } } pub fn new_face_down(stack: Stack) -> Self { Self { face_down: stack, face_up: Stack::new(), } } pub fn flip_it_and_reverse_it(&mut self) { self.swap_up_down(); self.face_up.reverse(); } pub fn swap_up_down(&mut self) { core::mem::swap(&mut self.face_up, &mut self.face_down); } pub fn flip_up(&mut self) { if let Some(card) = self.face_down.pop() { self.face_up.push(card); } } pub fn is_empty(&self) -> bool { self.face_down.is_empty() && self.face_up.is_empty() } pub fn pop(&mut self) -> Option { self.face_up.pop() } pub fn pop_flip_up(&mut self) -> Option { let card = self.pop()?; if self.face_up.is_empty() { self.flip_up(); } Some(card) } pub fn push(&mut self, card: Card) { self.face_up.push(card); } pub fn face_up(&self) -> &[Card] { &self.face_up } pub fn face_down(&self) -> &[Card] { &self.face_down } } #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Session { seed: G, state: G, history: Vec, } impl Session where G::Instruction: Clone + Eq + core::hash::Hash, { pub fn new(state: G) -> Self { Self { seed: state.clone(), state, history: Vec::new(), } } pub fn state(&self) -> &G { &self.state } pub fn history(&self) -> &[G::Instruction] { &self.history } pub fn is_winnable(&self) -> Option> { let mut observed = std::collections::HashSet::new(); struct StateMachine { state: G, possible_instructions_iter: P, instruction: I, } let state = self.state.clone(); let mut state = StateMachine { possible_instructions_iter: state.possible_instructions(), state, instruction: None, }; let mut history = Vec::new(); 'outer: while !state.state.is_win() { observed.insert(state.state.clone()); for instruction in &mut state.possible_instructions_iter { let mut next_state = state.state.clone(); next_state.process_instruction(instruction.clone()); if !observed.contains(&next_state) { let it = next_state.possible_instructions(); history.push(core::mem::replace( &mut state, StateMachine { state: next_state, possible_instructions_iter: it, instruction: Some(instruction), }, )); continue 'outer; } } let Some(last_state) = history.pop() else { return None; }; state = last_state; } Some( history .into_iter() .filter_map(|state| state.instruction) .collect(), ) } pub fn undo(&mut self) { // replay the entire history of the game except one move self.history.pop(); let mut state = self.seed.clone(); for instruction in self.history() { state.process_instruction(instruction.clone()); } self.state = state; } } impl Game for Session where G::Instruction: Clone, { type Instruction = G::Instruction; fn possible_instructions(&self) -> impl Iterator + use { self.state.possible_instructions() } fn is_instruction_valid(&self, instruction: Self::Instruction) -> bool { self.state.is_instruction_valid(instruction) } fn process_instruction(&mut self, instruction: Self::Instruction) { self.history.push(instruction.clone()); self.state.process_instruction(instruction); } fn is_win(&self) -> bool { self.state.is_win() } }