Compare commits

..

No commits in common. "5762187b047f0863eb4a646dcbaad5cbca71578a" and "5d4401a1fece7aacf71bbbb377b3bebcdd5b8fb7" have entirely different histories.

17 changed files with 3369 additions and 76 deletions

3322
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,11 @@
[workspace] [workspace]
resolver = "2" resolver="2"
members = ["client_tui", "client_cli", "bot", "server", "store"] members = [
"client",
"client_tui",
"client_cli",
"bot",
"server",
"store"
]

View file

@ -1,8 +1,10 @@
mod bot; mod bot;
use store::{CheckerMove, Color, GameEvent, GameState, PlayerId, PointsRules, TurnStage}; use store::{
CheckerMove, Color, Dice, GameEvent, GameState, Player, PlayerId, PointsRules, Stage, TurnStage,
};
pub trait BotStrategy: std::fmt::Debug { pub trait BotStrategy {
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;
@ -25,11 +27,18 @@ 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();
Self { let mut strategy = Self {
game, game,
player_id: 2, player_id: 2,
color: Color::Black, color: Color::Black,
} };
strategy
}
}
impl DefaultStrategy {
fn new() -> Self {
Self::default()
} }
} }
@ -86,34 +95,35 @@ impl BotStrategy for DefaultStrategy {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Bot { pub struct Bot<BotStrategy> {
pub player_id: PlayerId, pub player_id: PlayerId,
strategy: Box<dyn BotStrategy>, strategy: BotStrategy,
// color: Color, color: Color,
// schools_enabled: bool, schools_enabled: bool,
} }
impl Default for Bot { impl Default for Bot<DefaultStrategy> {
fn default() -> Self { fn default() -> Self {
let strategy = DefaultStrategy::default();
Self { Self {
player_id: 2, player_id: 2,
strategy: Box::new(strategy), strategy: DefaultStrategy::default(),
// color: Color::Black, color: Color::Black,
// schools_enabled: false, schools_enabled: false,
} }
} }
} }
impl Bot { impl<BS> Bot<BS>
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: Box<dyn BotStrategy>, color: Color, schools_enabled: bool) -> Self { pub fn new(mut strategy: BS, color: Color, schools_enabled: bool) -> Self {
pub fn new(mut strategy: Box<dyn BotStrategy>, color: Color) -> Self { let game = strategy.get_mut_game();
// 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,
@ -123,8 +133,8 @@ impl Bot {
Self { Self {
player_id, player_id,
strategy, strategy,
// color, color,
// schools_enabled: false, schools_enabled: false,
} }
} }
@ -164,19 +174,16 @@ impl Bot {
#[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(Box::new(DefaultStrategy::default()), Color::Black); let bot = Bot::new(DefaultStrategy::new(), Color::Black, false);
// 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(Box::new(DefaultStrategy::default()), Color::Black); let mut bot = Bot::new(DefaultStrategy::new(), Color::Black, false);
// 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

Before

Width:  |  Height:  |  Size: 2.9 MiB

After

Width:  |  Height:  |  Size: 2.9 MiB

View file

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

View file

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

@ -1,7 +1,8 @@
use itertools::Itertools; use itertools::Itertools;
use crate::game_runner::Game; use crate::game_runner::Game;
use store::{CheckerMove, GameEvent, GameState, Stage, TurnStage}; use bot::BotStrategy;
use store::{CheckerMove, GameEvent, GameState, PointsRules, Stage, TurnStage};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct AppArgs { pub struct AppArgs {
@ -72,15 +73,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,
@ -190,10 +191,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,14 +1,26 @@
use bot::{Bot, DefaultStrategy}; use bot::{Bot, BotStrategy, DefaultStrategy};
use store::{CheckerMove, DiceRoller, GameEvent, GameState, PlayerId, TurnStage}; use store::{CheckerMove, DiceRoller, GameEvent, GameState, PlayerId, TurnStage};
// Application Game // Application Game
#[derive(Debug, Default)] #[derive(Debug)]
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, bot: Bot<DefaultStrategy>,
}
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 {
@ -20,9 +32,8 @@ 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 = Box::new(DefaultStrategy::default()); let bot_strategy = DefaultStrategy::default();
// let bot: Bot = Bot::new(bot_strategy, bot_color, schools_enabled); let bot: Bot<DefaultStrategy> = 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.area(), f.size(),
) )
} }

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,3 +1,4 @@
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};
@ -75,6 +76,12 @@ 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::*;