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]
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;
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_mut_game(&mut self) -> &mut GameState;
fn calculate_points(&self) -> u8;
@ -25,11 +27,18 @@ pub struct DefaultStrategy {
impl Default for DefaultStrategy {
fn default() -> Self {
let game = GameState::default();
Self {
let mut strategy = Self {
game,
player_id: 2,
color: Color::Black,
}
};
strategy
}
}
impl DefaultStrategy {
fn new() -> Self {
Self::default()
}
}
@ -86,34 +95,35 @@ impl BotStrategy for DefaultStrategy {
}
#[derive(Debug)]
pub struct Bot {
pub struct Bot<BotStrategy> {
pub player_id: PlayerId,
strategy: Box<dyn BotStrategy>,
// color: Color,
// schools_enabled: bool,
strategy: BotStrategy,
color: Color,
schools_enabled: bool,
}
impl Default for Bot {
impl Default for Bot<DefaultStrategy> {
fn default() -> Self {
let strategy = DefaultStrategy::default();
Self {
player_id: 2,
strategy: Box::new(strategy),
// color: Color::Black,
// schools_enabled: false,
strategy: DefaultStrategy::default(),
color: Color::Black,
schools_enabled: false,
}
}
}
impl Bot {
impl<BS> Bot<BS>
where
BS: BotStrategy,
{
/// new initialize a bot
/// # Examples
/// ```let mut bot = Bot::new(Color::Black);
/// 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: Box<dyn BotStrategy>, color: Color) -> Self {
// let game = strategy.get_mut_game();
pub fn new(mut strategy: BS, color: Color, schools_enabled: bool) -> Self {
let game = strategy.get_mut_game();
strategy.init_players();
let player_id = match color {
Color::White => 1,
@ -123,8 +133,8 @@ impl Bot {
Self {
player_id,
strategy,
// color,
// schools_enabled: false,
color,
schools_enabled: false,
}
}
@ -164,19 +174,16 @@ impl Bot {
#[cfg(test)]
mod tests {
use super::*;
use store::{Dice, Stage};
#[test]
fn test_new() {
let bot = Bot::new(Box::new(DefaultStrategy::default()), Color::Black);
// let bot = Bot::new(Box::new(DefaultStrategy::default()), Color::Black, false);
let bot = Bot::new(DefaultStrategy::new(), Color::Black, false);
assert_eq!(bot.get_state().stage, Stage::PreGame);
}
#[test]
fn test_consume() {
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 bot = Bot::new(DefaultStrategy::new(), Color::Black, false);
let mut event = bot.handle_event(&GameEvent::BeginGame { goes_first: 2 });
assert_eq!(event, Some(GameEvent::Roll { 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 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)]
pub struct AppArgs {
@ -72,15 +73,15 @@ impl App {
let dice = self.game.dice_roller.roll();
// get correct points for these board and dice
// let points_rules = PointsRules::new(
// &self
// .game
// .state
// .player_color_by_id(&self.game.player_id.unwrap())
// .unwrap(),
// &self.game.state.board,
// dice,
// );
let points_rules = PointsRules::new(
&self
.game
.state
.player_color_by_id(&self.game.player_id.unwrap())
.unwrap(),
&self.game.state.board,
dice,
);
self.game.handle_event(&GameEvent::RollResult {
player_id: self.game.player_id.unwrap(),
dice,
@ -190,10 +191,10 @@ impl App {
}
}
use pretty_assertions::assert_eq;
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
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};
// Application Game
#[derive(Debug, Default)]
#[derive(Debug)]
pub struct Game {
pub state: GameState,
pub dice_roller: DiceRoller,
pub first_move: Option<CheckerMove>,
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 {
@ -20,9 +32,8 @@ impl Game {
// bot
let bot_id: PlayerId = state.init_player("bot").unwrap();
let bot_color = state.player_color_by_id(&bot_id).unwrap();
let bot_strategy = Box::new(DefaultStrategy::default());
// let bot: Bot = Bot::new(bot_strategy, bot_color, schools_enabled);
let bot: Bot = Bot::new(bot_strategy, bot_color);
let bot_strategy = DefaultStrategy::default();
let bot: Bot<DefaultStrategy> = Bot::new(bot_strategy, bot_color, schools_enabled);
let mut game = Self {
state,

View file

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

View file

@ -310,7 +310,7 @@ impl Board {
/// Check if a field is blocked for a player
pub fn blocked(&self, color: &Color, field: Field) -> Result<bool, Error> {
// 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)
// .map(|blocked| blocked || opp_corner_field == field)
}

View file

@ -1,3 +1,4 @@
use crate::Error;
use rand::distributions::{Distribution, Uniform};
use rand::{rngs::StdRng, SeedableRng};
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)]
mod tests {
use super::*;