From 2139de2fcd9aab3cc8d020b130ff2d7cf19c29b3 Mon Sep 17 00:00:00 2001 From: Henri Bourcereau Date: Sat, 30 Mar 2024 16:10:53 +0100 Subject: [PATCH] refact --- bot/src/lib.rs | 8 +++---- client_cli/src/app.rs | 23 +++++++++---------- store/src/board.rs | 47 +++++++++++++------------------------- store/src/game.rs | 52 +------------------------------------------ 4 files changed, 31 insertions(+), 99 deletions(-) diff --git a/bot/src/lib.rs b/bot/src/lib.rs index 591d8f8..d4ab239 100644 --- a/bot/src/lib.rs +++ b/bot/src/lib.rs @@ -44,7 +44,7 @@ impl Bot { } } - pub fn consume(&mut self, event: &GameEvent) -> Option { + pub fn handle_event(&mut self, event: &GameEvent) -> Option { self.game.consume(event); // println!("bot game {:?}", self.game); // println!("bot player_id {:?}", self.player_id); @@ -98,13 +98,13 @@ mod tests { #[test] fn test_consume() { let mut bot = Bot::new(Color::Black); - let mut event = bot.consume(&GameEvent::BeginGame { goes_first: 2 }); + let mut event = bot.handle_event(&GameEvent::BeginGame { goes_first: 2 }); assert_eq!(event, Some(GameEvent::Roll { player_id: 2 })); - event = bot.consume(&GameEvent::BeginGame { goes_first: 1 }); + event = bot.handle_event(&GameEvent::BeginGame { goes_first: 1 }); assert_eq!(event, None); - event = bot.consume(&GameEvent::RollResult { + bot.handle_event(&GameEvent::RollResult { player_id: 2, dice: Dice { values: (2, 3) }, }); diff --git a/client_cli/src/app.rs b/client_cli/src/app.rs index 04e2b44..6ca617b 100644 --- a/client_cli/src/app.rs +++ b/client_cli/src/app.rs @@ -35,13 +35,13 @@ impl Game { player_id, bot, }; - game.consume(&GameEvent::BeginGame { + game.handle_event(&GameEvent::BeginGame { goes_first: player_id.unwrap(), }); game } - pub fn consume(&mut self, event: &GameEvent) -> Option { + pub fn handle_event(&mut self, event: &GameEvent) -> Option { if !self.state.validate(event) { return None; } @@ -50,13 +50,12 @@ impl Game { // chain all successive bot actions let bot_event = self .bot - .consume(event) - .map(|evt| self.consume(&evt)) - .flatten(); + .handle_event(event) + .and_then(|evt| self.handle_event(&evt)); // roll dice for bot if needed if self.bot_needs_dice_roll() { let dice = self.dice_roller.roll(); - self.consume(&GameEvent::RollResult { + self.handle_event(&GameEvent::RollResult { player_id: self.bot.player_id, dice, }) @@ -127,7 +126,7 @@ impl App { return; } let dice = self.game.dice_roller.roll(); - self.game.consume(&GameEvent::RollResult { + self.game.handle_event(&GameEvent::RollResult { player_id: self.game.player_id.unwrap(), dice, }); @@ -143,22 +142,22 @@ impl App { .map(|str| str.parse().unwrap_or(0)) .collect(); if positions.len() == 2 && positions[0] != 0 && positions[1] != 0 { - let checker_move = CheckerMove::new(positions[0], positions[1]); - if checker_move.is_ok() { + if let Ok(checker_move) = CheckerMove::new(positions[0], positions[1]) { + // if checker_move.is_ok() { if self.game.first_move.is_some() { let move_event = GameEvent::Move { player_id: self.game.player_id.unwrap(), - moves: (self.game.first_move.unwrap(), checker_move.unwrap()), + moves: (self.game.first_move.unwrap(), checker_move), }; if !self.game.state.validate(&move_event) { println!("Move invalid"); self.game.first_move = None; return; } - self.game.consume(&move_event); + self.game.handle_event(&move_event); self.game.first_move = None; } else { - self.game.first_move = Some(checker_move.unwrap()); + self.game.first_move = Some(checker_move); } return; } diff --git a/store/src/board.rs b/store/src/board.rs index 1abc8d2..5b1f44b 100644 --- a/store/src/board.rs +++ b/store/src/board.rs @@ -1,4 +1,4 @@ -use crate::player::{Color, Player}; +use crate::player::Color; use crate::Error; use serde::{Deserialize, Serialize}; use std::cmp; @@ -31,7 +31,7 @@ impl CheckerMove { // println!("from {} to {}", from, to); // check if the field is on the board // we allow 0 for 'to', which represents the exit of a checker - if from < 1 || 24 < from || 24 < to { + if !(1..25).contains(&from) || 24 < to { return Err(Error::FieldInvalid); } // check that the destination is after the origin field @@ -98,7 +98,7 @@ impl Board { // Pieces placement -> 77bits (24 + 23 + 30 max) // inspired by https://www.gnu.org/software/gnubg/manual/html_node/A-technical-description-of-the-Position-ID.html // - white positions - let white_board = self.positions.clone(); + let white_board = self.positions; let mut pos_bits = white_board.iter().fold(vec![], |acc, nb| { let mut new_acc = acc.clone(); if *nb > 0 { @@ -110,7 +110,7 @@ impl Board { }); // - black positions - let mut black_board = self.positions.clone(); + let mut black_board = self.positions; black_board.reverse(); let mut pos_black_bits = black_board.iter().fold(vec![], |acc, nb| { let mut new_acc = acc.clone(); @@ -192,14 +192,13 @@ impl Board { line.replace_range(31..31, "| |"); output = output + " |" + &line + " |\n"; } - output = output + " |------------------------------ | | -----------------------------|\n"; + output += " |------------------------------ | | -----------------------------|\n"; for mut line in lower { // add middle bar line.replace_range(31..31, "| |"); output = output + " |" + &line + " |\n"; } - output = output - + " ---------------------------------------------------------------- + output += " ---------------------------------------------------------------- 12 11 10 9 8 7 6 5 4 3 2 1 \n"; output } @@ -280,22 +279,20 @@ impl Board { } pub fn get_field_checkers(&self, field: Field) -> Result<(u8, Option<&Color>), Error> { - if field < 1 || field > 24 { + if !(1..25).contains(&field) { return Err(Error::FieldInvalid); } let checkers_count = self.positions[field - 1]; - let color = if checkers_count < 0 { - Some(&Color::Black) - } else if checkers_count > 0 { - Some(&Color::White) - } else { - None + let color = match checkers_count.cmp(&0) { + cmp::Ordering::Less => Some(&Color::Black), + cmp::Ordering::Greater => Some(&Color::White), + cmp::Ordering::Equal => None, }; - Ok((checkers_count.abs() as u8, color)) + Ok((checkers_count.unsigned_abs(), color)) } pub fn get_checkers_color(&self, field: Field) -> Result, Error> { - self.get_field_checkers(field).map(|(count, color)| color) + self.get_field_checkers(field).map(|(_ount, color)| color) } /// returns the list of Fields containing Checkers of the Color @@ -357,7 +354,7 @@ impl Board { pub fn add_checker(&mut self, color: &Color, field: Field) -> Result<(), Error> { let checker_color = self.get_checkers_color(field)?; // error if the case contains the other color - if None != checker_color && Some(color) != checker_color { + if checker_color.is_some() && Some(color) != checker_color { return Err(Error::FieldInvalid); } let unit = match color { @@ -369,19 +366,6 @@ impl Board { } } -/// Trait to move checkers -pub trait Move { - /// Move a checker - fn move_checker(&mut self, player: &Player, dice: u8, from: Field) -> Result<&mut Self, Error> - where - Self: Sized; - - /// Move permitted - fn move_permitted(&mut self, player: &Player, dice: u8) -> Result<&mut Self, Error> - where - Self: Sized; -} - // Unit Tests #[cfg(test)] mod tests { @@ -395,7 +379,7 @@ mod tests { #[test] fn blocked_outofrange() -> Result<(), Error> { let board = Board::new(); - assert!(!board.blocked(&Color::White, 0).is_err()); + assert!(board.blocked(&Color::White, 0).is_ok()); assert!(board.blocked(&Color::White, 28).is_err()); Ok(()) } @@ -435,7 +419,6 @@ mod tests { #[test] fn set_wrong_amount1() { let mut board = Board::new(); - let player = Player::new("".into(), Color::White); assert!(board.set(&Color::White, 23, -3).is_err()); } diff --git a/store/src/game.rs b/store/src/game.rs index feb437f..b1364dc 100644 --- a/store/src/game.rs +++ b/store/src/game.rs @@ -1,5 +1,5 @@ //! # Play a TricTrac Game -use crate::board::{Board, CheckerMove, Field, Move}; +use crate::board::{Board, CheckerMove, Field}; use crate::dice::{Dice, DiceRoller, Roll}; use crate::player::{Color, Player, PlayerId}; use crate::Error; @@ -502,56 +502,6 @@ pub enum GameEvent { }, } -impl Move for GameState { - fn move_checker(&mut self, player: &Player, dice: u8, from: usize) -> Result<&mut Self, Error> { - // check if move is permitted - let _ = self.move_permitted(player, dice)?; - - // remove checker from old position - self.board.set(&player.color, from, -1)?; - - // move checker to new position, in case it is reaching the off position, set it off - let new_position = from as i8 - dice as i8; - if new_position < 0 { - // self.board.set_off(player, 1)?; - } else { - // self.board.set(player, new_position as usize, 1)?; - } - - // switch to other player if all dice have been consumed - self.switch_active_player(); - self.roll_first = true; - - Ok(self) - } - - /// Implements checks to validate if the player is allowed to move - fn move_permitted(&mut self, player: &Player, dice: u8) -> Result<&mut Self, Error> { - let maybe_player_id = self.player_id(&player); - // check if player is allowed to move - if maybe_player_id != Some(&self.active_player_id) { - return Err(Error::NotYourTurn); - } - - // if player is nobody, you can not play and have to roll first - if maybe_player_id.is_none() { - return Err(Error::RollFirst); - } - - // check if player has to roll first - if self.roll_first { - return Err(Error::RollFirst); - } - - // check if dice value has actually been rolled - if dice != self.dice.values.0 && dice != self.dice.values.1 { - return Err(Error::DiceInvalid); - } - - Ok(self) - } -} - #[cfg(test)] mod tests { use super::*;