refact: BotStrategy dyn trait

This commit is contained in:
Henri Bourcereau 2024-11-04 17:37:36 +01:00
parent 4ee2b02a41
commit 5762187b04
6 changed files with 43 additions and 69 deletions

View file

@ -1,10 +1,8 @@
mod bot; mod bot;
use store::{ use store::{CheckerMove, Color, GameEvent, GameState, PlayerId, PointsRules, TurnStage};
CheckerMove, Color, Dice, GameEvent, GameState, Player, PlayerId, PointsRules, Stage, TurnStage,
};
pub trait BotStrategy { pub trait BotStrategy: std::fmt::Debug {
fn get_game(&self) -> &GameState; fn get_game(&self) -> &GameState;
fn get_mut_game(&mut self) -> &mut GameState; fn get_mut_game(&mut self) -> &mut GameState;
fn calculate_points(&self) -> u8; fn calculate_points(&self) -> u8;
@ -27,19 +25,12 @@ pub struct DefaultStrategy {
impl Default for DefaultStrategy { impl Default for DefaultStrategy {
fn default() -> Self { fn default() -> Self {
let game = GameState::default(); let game = GameState::default();
let mut strategy = Self { Self {
game, game,
player_id: 2, player_id: 2,
color: Color::Black, color: Color::Black,
};
strategy
} }
} }
impl DefaultStrategy {
fn new() -> Self {
Self::default()
}
} }
impl BotStrategy for DefaultStrategy { impl BotStrategy for DefaultStrategy {
@ -95,35 +86,34 @@ impl BotStrategy for DefaultStrategy {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Bot<BotStrategy> { pub struct Bot {
pub player_id: PlayerId, pub player_id: PlayerId,
strategy: BotStrategy, strategy: Box<dyn BotStrategy>,
color: Color, // color: Color,
schools_enabled: bool, // schools_enabled: bool,
} }
impl Default for Bot<DefaultStrategy> { impl Default for Bot {
fn default() -> Self { fn default() -> Self {
let strategy = DefaultStrategy::default();
Self { Self {
player_id: 2, player_id: 2,
strategy: DefaultStrategy::default(), strategy: Box::new(strategy),
color: Color::Black, // color: Color::Black,
schools_enabled: false, // schools_enabled: false,
} }
} }
} }
impl<BS> Bot<BS> impl Bot {
where
BS: BotStrategy,
{
/// new initialize a bot /// new initialize a bot
/// # Examples /// # Examples
/// ```let mut bot = Bot::new(Color::Black); /// ```let mut bot = Bot::new(Color::Black);
/// assert_eq!(bot.game.stage, Stage::PreGame); /// assert_eq!(bot.game.stage, Stage::PreGame);
/// ``` /// ```
pub fn new(mut strategy: BS, color: Color, schools_enabled: bool) -> Self { // pub fn new(mut strategy: Box<dyn BotStrategy>, color: Color, schools_enabled: bool) -> Self {
let game = strategy.get_mut_game(); pub fn new(mut strategy: Box<dyn BotStrategy>, color: Color) -> Self {
// let game = strategy.get_mut_game();
strategy.init_players(); strategy.init_players();
let player_id = match color { let player_id = match color {
Color::White => 1, Color::White => 1,
@ -133,8 +123,8 @@ where
Self { Self {
player_id, player_id,
strategy, strategy,
color, // color,
schools_enabled: false, // schools_enabled: false,
} }
} }
@ -174,16 +164,19 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use store::{Dice, Stage};
#[test] #[test]
fn test_new() { fn test_new() {
let bot = Bot::new(DefaultStrategy::new(), Color::Black, false); let bot = Bot::new(Box::new(DefaultStrategy::default()), Color::Black);
// let bot = Bot::new(Box::new(DefaultStrategy::default()), Color::Black, false);
assert_eq!(bot.get_state().stage, Stage::PreGame); assert_eq!(bot.get_state().stage, Stage::PreGame);
} }
#[test] #[test]
fn test_consume() { fn test_consume() {
let mut bot = Bot::new(DefaultStrategy::new(), Color::Black, false); let mut bot = Bot::new(Box::new(DefaultStrategy::default()), Color::Black);
// let mut bot = Bot::new(Box::new(DefaultStrategy::default()), Color::Black, false);
let mut event = bot.handle_event(&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 })); assert_eq!(event, Some(GameEvent::Roll { player_id: 2 }));
assert_eq!(bot.get_state().active_player_id, 2); assert_eq!(bot.get_state().active_player_id, 2);

View file

@ -1,8 +1,7 @@
use itertools::Itertools; use itertools::Itertools;
use crate::game_runner::Game; use crate::game_runner::Game;
use bot::BotStrategy; use store::{CheckerMove, GameEvent, GameState, Stage, TurnStage};
use store::{CheckerMove, GameEvent, GameState, PointsRules, Stage, TurnStage};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct AppArgs { pub struct AppArgs {
@ -73,15 +72,15 @@ impl App {
let dice = self.game.dice_roller.roll(); let dice = self.game.dice_roller.roll();
// get correct points for these board and dice // get correct points for these board and dice
let points_rules = PointsRules::new( // let points_rules = PointsRules::new(
&self // &self
.game // .game
.state // .state
.player_color_by_id(&self.game.player_id.unwrap()) // .player_color_by_id(&self.game.player_id.unwrap())
.unwrap(), // .unwrap(),
&self.game.state.board, // &self.game.state.board,
dice, // dice,
); // );
self.game.handle_event(&GameEvent::RollResult { self.game.handle_event(&GameEvent::RollResult {
player_id: self.game.player_id.unwrap(), player_id: self.game.player_id.unwrap(),
dice, dice,
@ -191,10 +190,10 @@ impl App {
} }
} }
use pretty_assertions::assert_eq;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use pretty_assertions::assert_eq;
#[test] #[test]
fn test_display() { fn test_display() {

View file

@ -1,26 +1,14 @@
use bot::{Bot, BotStrategy, DefaultStrategy}; use bot::{Bot, DefaultStrategy};
use store::{CheckerMove, DiceRoller, GameEvent, GameState, PlayerId, TurnStage}; use store::{CheckerMove, DiceRoller, GameEvent, GameState, PlayerId, TurnStage};
// Application Game // Application Game
#[derive(Debug)] #[derive(Debug, Default)]
pub struct Game { pub struct Game {
pub state: GameState, pub state: GameState,
pub dice_roller: DiceRoller, pub dice_roller: DiceRoller,
pub first_move: Option<CheckerMove>, pub first_move: Option<CheckerMove>,
pub player_id: Option<PlayerId>, pub player_id: Option<PlayerId>,
bot: Bot<DefaultStrategy>, bot: Bot,
}
impl Default for Game {
fn default() -> Self {
Self {
state: GameState::default(),
dice_roller: DiceRoller::default(),
first_move: None,
player_id: None,
bot: Bot::default(),
}
}
} }
impl Game { impl Game {
@ -32,8 +20,9 @@ impl Game {
// bot // bot
let bot_id: PlayerId = state.init_player("bot").unwrap(); let bot_id: PlayerId = state.init_player("bot").unwrap();
let bot_color = state.player_color_by_id(&bot_id).unwrap(); let bot_color = state.player_color_by_id(&bot_id).unwrap();
let bot_strategy = DefaultStrategy::default(); let bot_strategy = Box::new(DefaultStrategy::default());
let bot: Bot<DefaultStrategy> = Bot::new(bot_strategy, bot_color, schools_enabled); // let bot: Bot = Bot::new(bot_strategy, bot_color, schools_enabled);
let bot: Bot = Bot::new(bot_strategy, bot_color);
let mut game = Self { let mut game = Self {
state, state,

View file

@ -25,6 +25,6 @@ pub fn render(app: &mut App, f: &mut Frame) {
) )
.style(Style::default().fg(Color::Yellow)) .style(Style::default().fg(Color::Yellow))
.alignment(Alignment::Center), .alignment(Alignment::Center),
f.size(), f.area(),
) )
} }

View file

@ -310,7 +310,7 @@ impl Board {
/// Check if a field is blocked for a player /// Check if a field is blocked for a player
pub fn blocked(&self, color: &Color, field: Field) -> Result<bool, Error> { pub fn blocked(&self, color: &Color, field: Field) -> Result<bool, Error> {
// the square is blocked on the opponent rest corner // the square is blocked on the opponent rest corner
let opp_corner_field = if color == &Color::White { 13 } else { 12 }; // let opp_corner_field = if color == &Color::White { 13 } else { 12 };
self.passage_blocked(color, field) self.passage_blocked(color, field)
// .map(|blocked| blocked || opp_corner_field == field) // .map(|blocked| blocked || opp_corner_field == field)
} }

View file

@ -1,4 +1,3 @@
use crate::Error;
use rand::distributions::{Distribution, Uniform}; use rand::distributions::{Distribution, Uniform};
use rand::{rngs::StdRng, SeedableRng}; use rand::{rngs::StdRng, SeedableRng};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -76,12 +75,6 @@ impl Dice {
// } // }
} }
/// Trait to roll the dices
pub trait Roll {
/// Roll the dices
fn roll(&mut self) -> &mut Self;
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;