roll bot dice

This commit is contained in:
Henri Bourcereau 2024-03-27 21:10:15 +01:00
parent dff9f7f3e1
commit 6ceefe01ab
4 changed files with 98 additions and 59 deletions

View file

@ -5,7 +5,7 @@ use store::{CheckerMove, Color, Dice, GameEvent, GameState, Player, PlayerId, St
#[derive(Debug)] #[derive(Debug)]
pub struct Bot { pub struct Bot {
pub game: GameState, pub game: GameState,
player_id: PlayerId, pub player_id: PlayerId,
color: Color, color: Color,
} }
@ -46,7 +46,8 @@ impl Bot {
pub fn consume(&mut self, event: &GameEvent) -> Option<GameEvent> { pub fn consume(&mut self, event: &GameEvent) -> Option<GameEvent> {
self.game.consume(event); self.game.consume(event);
// println!("{:?}", self.game); println!("bot game {:?}", self.game);
println!("bot player_id {:?}", self.player_id);
if self.game.active_player_id == self.player_id { if self.game.active_player_id == self.player_id {
return match self.game.turn_stage { return match self.game.turn_stage {
TurnStage::RollDice => Some(GameEvent::Roll { TurnStage::RollDice => Some(GameEvent::Roll {
@ -60,6 +61,7 @@ impl Bot {
player_id: self.player_id, player_id: self.player_id,
moves: self.choose_move(), moves: self.choose_move(),
}), }),
_ => None,
}; };
} }
None None

View file

@ -1,6 +1,6 @@
use bot::Bot; use bot::Bot;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use store::{CheckerMove, Color, Dice, DiceRoller, GameEvent, GameState, PlayerId}; use store::{CheckerMove, Color, Dice, DiceRoller, GameEvent, GameState, PlayerId, TurnStage};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct AppArgs { pub struct AppArgs {
@ -43,15 +43,31 @@ impl Game {
pub fn consume(&mut self, event: &GameEvent) -> Option<GameEvent> { pub fn consume(&mut self, event: &GameEvent) -> Option<GameEvent> {
if self.state.validate(event) { if self.state.validate(event) {
println!("consuming {:?}", event);
self.state.consume(event); self.state.consume(event);
return self // chain all successive bot actions
let bot_event = self
.bot .bot
.consume(event) .consume(event)
.map(|evt| self.consume(&evt)) .map(|evt| self.consume(&evt))
.flatten(); .flatten();
// roll dice for bot if needed
if self.bot_needs_dice_roll() {
let dice = self.dice_roller.roll();
return self.consume(&GameEvent::RollResult {
player_id: self.bot.player_id,
dice,
});
}
return bot_event;
} }
None None
} }
fn bot_needs_dice_roll(&self) -> bool {
self.state.active_player_id == self.bot.player_id
&& self.state.turn_stage == TurnStage::RollWaiting
}
} }
// Application. // Application.
@ -167,7 +183,7 @@ Rolled dice : 0 & 0
| | | X | | | | X |
| | | X | | | | X |
| | | 15 | | | | 15 |
|----------------------------- | | ------------------------------| |------------------------------ | | -----------------------------|
| | | 15 | | | | 15 |
| | | O | | | | O |
| | | O | | | | O |
@ -187,11 +203,12 @@ Rolled dice : 0 & 0
#[test] #[test]
fn test_move() { fn test_move() {
let expected = "------------------------------- let expected = "-------------------------------
Rolled dice : 2 & 3 Rolled dice : 4 & 6
------------------------------- -------------------------------
13 14 15 16 17 18 19 20 21 22 23 24 13 14 15 16 17 18 19 20 21 22 23 24
---------------------------------------------------------------- ----------------------------------------------------------------
| X | | X X |
| | | X | | | | X |
| | | X | | | | X |
| | | X | | | | X |
@ -199,9 +216,8 @@ Rolled dice : 2 & 3
| | | X | | | | X |
| | | X | | | | X |
| | | X | | | | X |
| | | X | | | | 13 |
| | | 15 | |------------------------------ | | -----------------------------|
|----------------------------- | | ------------------------------|
| | | 13 | | | | 13 |
| | | O | | | | O |
| | | O | | | | O |

View file

@ -35,9 +35,10 @@ impl CheckerMove {
return Err(Error::FieldInvalid); return Err(Error::FieldInvalid);
} }
// check that the destination is after the origin field // check that the destination is after the origin field
if to < from && to != 0 { // --> not applicable for black moves
return Err(Error::MoveInvalid); // if to < from && to != 0 {
} // return Err(Error::MoveInvalid);
// }
Ok(Self { from, to }) Ok(Self { from, to })
} }
@ -188,13 +189,13 @@ impl Board {
.to_owned(); .to_owned();
for mut line in upper { for mut line in upper {
// add middle bar // add middle bar
line.replace_range(30..30, "| |"); line.replace_range(31..31, "| |");
output = output + " |" + &line + " |\n"; output = output + " |" + &line + " |\n";
} }
output = output + " |----------------------------- | | ------------------------------|\n"; output = output + " |------------------------------ | | -----------------------------|\n";
for mut line in lower { for mut line in lower {
// add middle bar // add middle bar
line.replace_range(30..30, "| |"); line.replace_range(31..31, "| |");
output = output + " |" + &line + " |\n"; output = output + " |" + &line + " |\n";
} }
output = output output = output
@ -345,7 +346,11 @@ impl Board {
if Some(color) != checker_color { if Some(color) != checker_color {
return Err(Error::FieldInvalid); return Err(Error::FieldInvalid);
} }
self.positions[field - 1] -= 1; let unit = match color {
Color::White => 1,
Color::Black => -1,
};
self.positions[field - 1] -= unit;
Ok(()) Ok(())
} }
@ -355,7 +360,11 @@ impl Board {
if None != checker_color && Some(color) != checker_color { if None != checker_color && Some(color) != checker_color {
return Err(Error::FieldInvalid); return Err(Error::FieldInvalid);
} }
self.positions[field - 1] += 1; let unit = match color {
Color::White => 1,
Color::Black => -1,
};
self.positions[field - 1] += unit;
Ok(()) Ok(())
} }
} }

View file

@ -25,6 +25,7 @@ pub enum Stage {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum TurnStage { pub enum TurnStage {
RollDice, RollDice,
RollWaiting,
MarkPoints, MarkPoints,
Move, Move,
} }
@ -102,9 +103,10 @@ impl GameState {
// step -> 2 bits // step -> 2 bits
let step_bits = match self.turn_stage { let step_bits = match self.turn_stage {
TurnStage::RollWaiting => "00",
TurnStage::RollDice => "01", TurnStage::RollDice => "01",
TurnStage::MarkPoints => "01", TurnStage::MarkPoints => "10",
TurnStage::Move => "10", TurnStage::Move => "11",
}; };
pos_bits.push_str(step_bits); pos_bits.push_str(step_bits);
@ -288,8 +290,8 @@ impl GameState {
fn moves_follows_dices(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool { fn moves_follows_dices(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool {
let (dice1, dice2) = self.dice.values; let (dice1, dice2) = self.dice.values;
let (move1, move2): &(CheckerMove, CheckerMove) = moves.into(); let (move1, move2): &(CheckerMove, CheckerMove) = moves.into();
let dist1 = (move1.get_to() - move1.get_from()) as u8; let dist1 = (move1.get_to() as i8 - move1.get_from() as i8).abs() as u8;
let dist2 = (move2.get_to() - move2.get_from()) as u8; let dist2 = (move2.get_to() as i8 - move2.get_from() as i8).abs() as u8;
print!("{}, {}, {}, {}", dist1, dist2, dice1, dice2); print!("{}, {}, {}, {}", dist1, dist2, dice1, dice2);
// basic : same number // basic : same number
if cmp::min(dist1, dist2) != cmp::min(dice1, dice2) if cmp::min(dist1, dist2) != cmp::min(dice1, dice2)
@ -415,7 +417,9 @@ impl GameState {
PlayerDisconnected { player_id } => { PlayerDisconnected { player_id } => {
self.players.remove(player_id); self.players.remove(player_id);
} }
Roll { player_id: _ } => {} Roll { player_id: _ } => {
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;
@ -436,6 +440,7 @@ impl GameState {
.find(|id| *id != player_id) .find(|id| *id != player_id)
.unwrap() .unwrap()
.clone(); .clone();
self.turn_stage = TurnStage::RollDice;
} }
} }
@ -585,6 +590,13 @@ mod tests {
CheckerMove::new(6, 9).unwrap(), CheckerMove::new(6, 9).unwrap(),
); );
assert!(!state.moves_possible(&Color::White, &moves)); assert!(!state.moves_possible(&Color::White, &moves));
// black moves
let moves = (
CheckerMove::new(24, 20).unwrap(),
CheckerMove::new(20, 19).unwrap(),
);
assert!(state.moves_possible(&Color::Black, &moves));
} }
#[test] #[test]