implement staging api
This commit is contained in:
+45
-47
@@ -1,6 +1,6 @@
|
||||
pub type Rng = rand::rngs::StdRng;
|
||||
|
||||
use card_game::{Card, Game, Pile, Rank, Stack};
|
||||
use card_game::{Card, Game, InstructionConsumer, Pile, Rank, Stack, StagedInstruction};
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
@@ -621,7 +621,7 @@ impl KlondikeState {
|
||||
pub fn is_instruction_valid(
|
||||
&self,
|
||||
config: &KlondikeConfig,
|
||||
instruction: KlondikeInstruction,
|
||||
instruction: &KlondikeInstruction,
|
||||
) -> bool {
|
||||
match instruction {
|
||||
// Stock -> Stock draws a card or resets the stock
|
||||
@@ -830,54 +830,11 @@ impl Game for Klondike {
|
||||
let state = self.state.clone();
|
||||
let config = config.clone();
|
||||
KlondikeIter::new()
|
||||
.filter(move |&instruction| state.is_instruction_valid(&config, instruction))
|
||||
.filter(move |instruction| state.is_instruction_valid(&config, instruction))
|
||||
}
|
||||
fn is_instruction_valid(&self, config: &Self::Config, instruction: Self::Instruction) -> bool {
|
||||
fn is_instruction_valid(&self, config: &Self::Config, instruction: &Self::Instruction) -> bool {
|
||||
self.state.is_instruction_valid(config, instruction)
|
||||
}
|
||||
fn process_instruction(
|
||||
&mut self,
|
||||
stats: &mut Self::Stats,
|
||||
config: &Self::Config,
|
||||
instruction: Self::Instruction,
|
||||
) {
|
||||
stats.increment_moves();
|
||||
match instruction {
|
||||
// Reset the stock if it's empty
|
||||
KlondikeInstruction::RotateStock => {
|
||||
if self.state.stock.face_down().is_empty() {
|
||||
self.state.stock.flip_it_and_reverse_it();
|
||||
stats.increment_recycle_count();
|
||||
} else {
|
||||
for _ in 0..config.draw_stock as usize {
|
||||
self.state.stock.flip_up();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Move a card from anywhere to a foundation
|
||||
KlondikeInstruction::DstFoundation(DstFoundation { src, foundation }) => {
|
||||
stats.increment_move_to_foundation();
|
||||
let (card, did_flip_up) = self.state.take_top_card_flip_up(src);
|
||||
if did_flip_up {
|
||||
stats.increment_flip_up_bonus();
|
||||
}
|
||||
self.state.extend_foundation(foundation, card);
|
||||
}
|
||||
// Move a stack of cards from anywhere to a tableau
|
||||
KlondikeInstruction::DstTableau(DstTableau { src, tableau }) => {
|
||||
match src {
|
||||
KlondikePileStack::Stock => stats.increment_move_to_tableau(),
|
||||
KlondikePileStack::Foundation(_) => stats.increment_move_from_foundation(),
|
||||
KlondikePileStack::Tableau(_) => {}
|
||||
}
|
||||
let (cards, did_flip_up) = self.state.take_stack_flip_up(src);
|
||||
if did_flip_up {
|
||||
stats.increment_flip_up_bonus();
|
||||
}
|
||||
self.state.extend_tableau(tableau, cards);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn is_win(&self) -> bool {
|
||||
// all foundations contain all ranks
|
||||
self.state.foundations.iter().all(|foundation| {
|
||||
@@ -889,6 +846,47 @@ impl Game for Klondike {
|
||||
})
|
||||
}
|
||||
}
|
||||
impl InstructionConsumer for Klondike {
|
||||
fn process_instruction(valid_instruction: StagedInstruction<'_, Self>) {
|
||||
let (game, stats, config, instruction) = valid_instruction.consume();
|
||||
stats.increment_moves();
|
||||
match instruction {
|
||||
// Reset the stock if it's empty
|
||||
KlondikeInstruction::RotateStock => {
|
||||
if game.state.stock.face_down().is_empty() {
|
||||
game.state.stock.flip_it_and_reverse_it();
|
||||
stats.increment_recycle_count();
|
||||
} else {
|
||||
for _ in 0..config.draw_stock as usize {
|
||||
game.state.stock.flip_up();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Move a card from anywhere to a foundation
|
||||
KlondikeInstruction::DstFoundation(DstFoundation { src, foundation }) => {
|
||||
stats.increment_move_to_foundation();
|
||||
let (card, did_flip_up) = game.state.take_top_card_flip_up(src);
|
||||
if did_flip_up {
|
||||
stats.increment_flip_up_bonus();
|
||||
}
|
||||
game.state.extend_foundation(foundation, card);
|
||||
}
|
||||
// Move a stack of cards from anywhere to a tableau
|
||||
KlondikeInstruction::DstTableau(DstTableau { src, tableau }) => {
|
||||
match src {
|
||||
KlondikePileStack::Stock => stats.increment_move_to_tableau(),
|
||||
KlondikePileStack::Foundation(_) => stats.increment_move_from_foundation(),
|
||||
KlondikePileStack::Tableau(_) => {}
|
||||
}
|
||||
let (cards, did_flip_up) = game.state.take_stack_flip_up(src);
|
||||
if did_flip_up {
|
||||
stats.increment_flip_up_bonus();
|
||||
}
|
||||
game.state.extend_tableau(tableau, cards);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl serde::Serialize for KlondikeInstruction {
|
||||
|
||||
@@ -23,7 +23,10 @@ fn test_json() {
|
||||
let solution_result = session.solve();
|
||||
if let Ok(Some(solution)) = solution_result {
|
||||
for snapshot in solution.clean_solution() {
|
||||
session.process_instruction(snapshot.instruction().clone());
|
||||
session
|
||||
.stage_instruction(snapshot.instruction().clone())
|
||||
.unwrap()
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
let serialized = serde_json::to_string(&session).unwrap();
|
||||
@@ -42,7 +45,10 @@ fn test_rmp() {
|
||||
let solution_result = session.solve();
|
||||
if let Ok(Some(solution)) = solution_result {
|
||||
for snapshot in solution.clean_solution() {
|
||||
session.process_instruction(snapshot.instruction().clone());
|
||||
session
|
||||
.stage_instruction(snapshot.instruction().clone())
|
||||
.unwrap()
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
let serialized = rmp_serde::to_vec(&session).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user