feat: calcul automatique des points #3
This commit is contained in:
parent
08fd067a95
commit
17605efe76
|
|
@ -9,6 +9,7 @@ pub struct Bot {
|
||||||
pub game: GameState,
|
pub game: GameState,
|
||||||
pub player_id: PlayerId,
|
pub player_id: PlayerId,
|
||||||
color: Color,
|
color: Color,
|
||||||
|
schools_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Bot {
|
impl Default for Bot {
|
||||||
|
|
@ -17,6 +18,7 @@ impl Default for Bot {
|
||||||
game: GameState::default(),
|
game: GameState::default(),
|
||||||
player_id: 1,
|
player_id: 1,
|
||||||
color: Color::Black,
|
color: Color::Black,
|
||||||
|
schools_enabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +31,7 @@ impl Bot {
|
||||||
/// ```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(color: Color) -> Self {
|
pub fn new(color: Color, schools_enabled: bool) -> Self {
|
||||||
let mut game = GameState::default();
|
let mut game = GameState::default();
|
||||||
game.init_player("p1");
|
game.init_player("p1");
|
||||||
game.init_player("p2");
|
game.init_player("p2");
|
||||||
|
|
@ -43,6 +45,7 @@ impl Bot {
|
||||||
game,
|
game,
|
||||||
player_id,
|
player_id,
|
||||||
color,
|
color,
|
||||||
|
schools_enabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,13 +110,13 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new() {
|
fn test_new() {
|
||||||
let bot = Bot::new(Color::Black);
|
let bot = Bot::new(Color::Black, false);
|
||||||
assert_eq!(bot.game.stage, Stage::PreGame);
|
assert_eq!(bot.game.stage, Stage::PreGame);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_consume() {
|
fn test_consume() {
|
||||||
let mut bot = Bot::new(Color::Black);
|
let mut bot = Bot::new(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 }));
|
||||||
|
|
||||||
|
|
@ -124,6 +127,6 @@ mod tests {
|
||||||
player_id: 2,
|
player_id: 2,
|
||||||
dice: Dice { values: (2, 3) },
|
dice: Dice { values: (2, 3) },
|
||||||
});
|
});
|
||||||
assert_eq!(bot.game.turn_stage, TurnStage::MarkPoints);
|
assert_eq!(bot.game.turn_stage, TurnStage::Move);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@ use itertools::Itertools;
|
||||||
|
|
||||||
use bot::Bot;
|
use bot::Bot;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use store::{CheckerMove, DiceRoller, GameEvent, GameState, PlayerId, Stage, TurnStage};
|
use store::{
|
||||||
|
CheckerMove, DiceRoller, GameEvent, GameState, PlayerId, PointsRules, Stage, TurnStage,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct AppArgs {
|
pub struct AppArgs {
|
||||||
|
|
@ -21,14 +23,14 @@ pub struct Game {
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
// Constructs a new instance of [`App`].
|
// Constructs a new instance of [`App`].
|
||||||
pub fn new(seed: Option<u64>) -> Self {
|
pub fn new(schools_enabled: bool, seed: Option<u64>) -> Self {
|
||||||
let mut state = GameState::default();
|
let mut state = GameState::new(schools_enabled);
|
||||||
// local : player
|
// local : player
|
||||||
let player_id: Option<PlayerId> = state.init_player("myself");
|
let player_id: Option<PlayerId> = state.init_player("myself");
|
||||||
// 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: Bot = Bot::new(bot_color);
|
let bot: Bot = Bot::new(bot_color, schools_enabled);
|
||||||
|
|
||||||
let mut game = Self {
|
let mut game = Self {
|
||||||
state,
|
state,
|
||||||
|
|
@ -77,20 +79,23 @@ impl Game {
|
||||||
pub struct App {
|
pub struct App {
|
||||||
// should the application exit?
|
// should the application exit?
|
||||||
pub should_quit: bool,
|
pub should_quit: bool,
|
||||||
|
pub schools_enabled: bool,
|
||||||
pub game: Game,
|
pub game: Game,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
// Constructs a new instance of [`App`].
|
// Constructs a new instance of [`App`].
|
||||||
pub fn new(args: AppArgs) -> Self {
|
pub fn new(args: AppArgs) -> Self {
|
||||||
|
let schools_enabled = false;
|
||||||
Self {
|
Self {
|
||||||
game: Game::new(args.seed.map(|s| s as u64)),
|
game: Game::new(schools_enabled, args.seed.map(|s| s as u64)),
|
||||||
should_quit: false,
|
should_quit: false,
|
||||||
|
schools_enabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
self.game.state = GameState::new();
|
self.game.state = GameState::new(self.schools_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(&mut self, input: &str) {
|
pub fn input(&mut self, input: &str) {
|
||||||
|
|
@ -130,6 +135,17 @@ impl App {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let dice = self.game.dice_roller.roll();
|
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,
|
||||||
|
);
|
||||||
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,
|
||||||
|
|
@ -247,7 +263,7 @@ Rolled dice : 0 & 0
|
||||||
#[test]
|
#[test]
|
||||||
fn test_move() {
|
fn test_move() {
|
||||||
let expected = "-------------------------------
|
let expected = "-------------------------------
|
||||||
InGame > myself > RollDice
|
InGame > myself > MarkAdvPoints
|
||||||
Rolled dice : 4 & 6
|
Rolled dice : 4 & 6
|
||||||
|
|
||||||
Player :: holes :: points
|
Player :: holes :: points
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,12 @@ pub struct GameState {
|
||||||
pub history: Vec<GameEvent>,
|
pub history: Vec<GameEvent>,
|
||||||
/// last dice pair rolled
|
/// last dice pair rolled
|
||||||
pub dice: Dice,
|
pub dice: Dice,
|
||||||
|
/// players points computed for the last dice pair rolled
|
||||||
|
dice_points: (u8, u8),
|
||||||
/// true if player needs to roll first
|
/// true if player needs to roll first
|
||||||
roll_first: bool,
|
roll_first: bool,
|
||||||
|
// NOTE: add to a Setting struct if other fields needed
|
||||||
|
pub schools_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// implement Display trait
|
// implement Display trait
|
||||||
|
|
@ -71,15 +75,33 @@ impl Default for GameState {
|
||||||
players: HashMap::new(),
|
players: HashMap::new(),
|
||||||
history: Vec::new(),
|
history: Vec::new(),
|
||||||
dice: Dice::default(),
|
dice: Dice::default(),
|
||||||
|
dice_points: (0, 0),
|
||||||
roll_first: true,
|
roll_first: true,
|
||||||
|
schools_enabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameState {
|
impl GameState {
|
||||||
/// Create a new default game
|
/// Create a new default game
|
||||||
pub fn new() -> Self {
|
pub fn new(schools_enabled: bool) -> Self {
|
||||||
GameState::default()
|
let mut gs = GameState::default();
|
||||||
|
gs.set_schools_enabled(schools_enabled);
|
||||||
|
gs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_schools_enabled(&mut self, schools_enabled: bool) {
|
||||||
|
self.schools_enabled = schools_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_opponent_id(&self) -> Option<PlayerId> {
|
||||||
|
self.players
|
||||||
|
.keys()
|
||||||
|
.map(|k| *k)
|
||||||
|
.filter(|k| k != &self.active_player_id)
|
||||||
|
.collect::<Vec<PlayerId>>()
|
||||||
|
.first()
|
||||||
|
.copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
@ -358,11 +380,30 @@ impl GameState {
|
||||||
self.players.remove(player_id);
|
self.players.remove(player_id);
|
||||||
}
|
}
|
||||||
Roll { player_id: _ } => {
|
Roll { player_id: _ } => {
|
||||||
|
// Opponent has moved, we can mark pending points earned during opponent's turn
|
||||||
|
self.mark_points(self.active_player_id, self.dice_points.1);
|
||||||
|
if self.stage != Stage::Ended {
|
||||||
self.turn_stage = TurnStage::RollWaiting;
|
self.turn_stage = TurnStage::RollWaiting;
|
||||||
}
|
}
|
||||||
RollResult { player_id: _, dice } => {
|
}
|
||||||
|
RollResult { player_id, dice } => {
|
||||||
self.dice = *dice;
|
self.dice = *dice;
|
||||||
self.turn_stage = TurnStage::MarkPoints;
|
self.turn_stage = TurnStage::MarkPoints;
|
||||||
|
// We compute points for the move
|
||||||
|
let points_rules = PointsRules::new(
|
||||||
|
&self.player_color_by_id(&self.active_player_id).unwrap(),
|
||||||
|
&self.board,
|
||||||
|
*dice,
|
||||||
|
);
|
||||||
|
self.dice_points = points_rules.get_points();
|
||||||
|
if !self.schools_enabled {
|
||||||
|
// Schools are not enabled. We mark points automatically
|
||||||
|
// the points earned by the opponent will be marked on its turn
|
||||||
|
self.mark_points(self.active_player_id, self.dice_points.0);
|
||||||
|
if self.stage != Stage::Ended {
|
||||||
|
self.turn_stage = TurnStage::Move;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Mark { player_id, points } => {
|
Mark { player_id, points } => {
|
||||||
self.mark_points(*player_id, *points);
|
self.mark_points(*player_id, *points);
|
||||||
|
|
@ -379,7 +420,11 @@ impl GameState {
|
||||||
self.board.move_checker(&player.color, moves.0).unwrap();
|
self.board.move_checker(&player.color, moves.0).unwrap();
|
||||||
self.board.move_checker(&player.color, moves.1).unwrap();
|
self.board.move_checker(&player.color, moves.1).unwrap();
|
||||||
self.active_player_id = *self.players.keys().find(|id| *id != player_id).unwrap();
|
self.active_player_id = *self.players.keys().find(|id| *id != player_id).unwrap();
|
||||||
self.turn_stage = TurnStage::MarkAdvPoints;
|
self.turn_stage = if self.schools_enabled {
|
||||||
|
TurnStage::MarkAdvPoints
|
||||||
|
} else {
|
||||||
|
TurnStage::RollDice
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -393,7 +438,9 @@ impl GameState {
|
||||||
|
|
||||||
fn mark_points(&mut self, player_id: PlayerId, points: u8) {
|
fn mark_points(&mut self, player_id: PlayerId, points: u8) {
|
||||||
self.players.get_mut(&player_id).map(|p| {
|
self.players.get_mut(&player_id).map(|p| {
|
||||||
p.points += points;
|
let sum_points = p.points + points;
|
||||||
|
p.points = sum_points % 12;
|
||||||
|
p.holes += sum_points / 12;
|
||||||
p
|
p
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -443,10 +443,13 @@ impl PointsRules {
|
||||||
|
|
||||||
pub fn get_points(&self) -> (u8, u8) {
|
pub fn get_points(&self) -> (u8, u8) {
|
||||||
let jans = self.get_jans(&self.board);
|
let jans = self.get_jans(&self.board);
|
||||||
|
// if !jans.is_empty() {
|
||||||
|
// println!("get points : {:?}", jans);
|
||||||
|
// }
|
||||||
let (points, adv_points) = jans
|
let (points, adv_points) = jans
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold((0, 0), |acc: (i8, i8), (jan, moves)| {
|
.fold((0, 0), |acc: (i8, i8), (jan, moves)| {
|
||||||
println!("get_points : {:?}", jan);
|
// println!("get_points : {:?}", jan);
|
||||||
let is_double = if jan == Jan::HelplessMan {
|
let is_double = if jan == Jan::HelplessMan {
|
||||||
moves[0] == (CheckerMove::default(), CheckerMove::default())
|
moves[0] == (CheckerMove::default(), CheckerMove::default())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue