store : validation : check dices

This commit is contained in:
Henri Bourcereau 2024-02-03 22:16:14 +01:00
parent 41647ebd1b
commit 8c99b228d3
2 changed files with 90 additions and 24 deletions

View file

@ -19,9 +19,7 @@ impl Dices {
let v = (between.sample(&mut rng), between.sample(&mut rng)); let v = (between.sample(&mut rng), between.sample(&mut rng));
Dices { Dices { values: (v.0, v.1) }
values: (v.0, v.1),
}
} }
/// Heads or tails /// Heads or tails
@ -31,7 +29,6 @@ impl Dices {
between.sample(&mut rng) == 1 between.sample(&mut rng) == 1
} }
pub fn to_bits_string(self) -> String { pub fn to_bits_string(self) -> String {
format!("{:0>3b}{:0>3b}", self.values.0, self.values.1) format!("{:0>3b}{:0>3b}", self.values.0, self.values.1)
} }
@ -51,7 +48,7 @@ impl Dices {
/// Trait to roll the dices /// Trait to roll the dices
pub trait Roll { pub trait Roll {
/// Roll the dices /// Roll the dices
fn roll(&mut self) -> Result<&mut Self, Error>; fn roll(&mut self) -> &mut Self;
} }
#[cfg(test)] #[cfg(test)]
@ -70,5 +67,4 @@ mod tests {
let dices = Dices { values: (4, 2) }; let dices = Dices { values: (4, 2) };
assert!(dices.to_bits_string() == "100010"); assert!(dices.to_bits_string() == "100010");
} }
} }

View file

@ -75,9 +75,9 @@ impl GameState {
GameState::default() GameState::default()
} }
fn add_player(&mut self, player_id: PlayerId, player: Player) { // -------------------------------------------------------------------------
self.players.insert(player_id, player); // accessors
} // -------------------------------------------------------------------------
/// Calculate game state id : /// Calculate game state id :
pub fn to_string_id(&self) -> String { pub fn to_string_id(&self) -> String {
@ -148,16 +148,6 @@ impl GameState {
.next() .next()
} }
pub fn switch_active_player(&mut self) {
let other_player_id = self
.players
.iter()
.filter(|(id, _player)| **id != self.active_player_id)
.map(|(id, _player)| *id)
.next();
self.active_player_id = other_player_id.unwrap_or(0);
}
pub fn player_id_by_color(&self, color: Color) -> Option<&PlayerId> { pub fn player_id_by_color(&self, color: Color) -> Option<&PlayerId> {
self.players self.players
.iter() .iter()
@ -174,6 +164,10 @@ impl GameState {
.next() .next()
} }
// ----------------------------------------------------------------------------------
// Rules checks
// ----------------------------------------------------------------------------------
/// Determines whether an event is valid considering the current GameState /// Determines whether an event is valid considering the current GameState
pub fn validate(&self, event: &GameEvent) -> bool { pub fn validate(&self, event: &GameEvent) -> bool {
use GameEvent::*; use GameEvent::*;
@ -220,6 +214,16 @@ impl GameState {
return false; return false;
} }
} }
Mark { player_id, points } => {
// Check player exists
if !self.players.contains_key(player_id) {
return false;
}
// Check player is currently the one making their move
if self.active_player_id != *player_id {
return false;
}
}
Move { player_id, moves } => { Move { player_id, moves } => {
// Check player exists // Check player exists
if !self.players.contains_key(player_id) { if !self.players.contains_key(player_id) {
@ -231,9 +235,14 @@ impl GameState {
error!("Player not active : {}", self.active_player_id); error!("Player not active : {}", self.active_player_id);
return false; return false;
} }
let color = &self.players[player_id].color;
// Check moves conforms to the dices
if !self.moves_follows_dices(color, moves) {
return false;
}
// Check move is physically possible // Check move is physically possible
let color = &self.players[player_id].color;
if !self.board.move_possible(color, &moves.0) { if !self.board.move_possible(color, &moves.0) {
return false; return false;
} }
@ -259,6 +268,14 @@ impl GameState {
true true
} }
fn moves_follows_dices(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool {
// basic : same number
// prise de coin par puissance
// sorties
// no rule was broken
false
}
fn moves_allowed(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool { fn moves_allowed(&self, color: &Color, moves: &(CheckerMove, CheckerMove)) -> bool {
// ------- corner rules ---------- // ------- corner rules ----------
let corner_field: Field = self.board.get_color_corner(color); let corner_field: Field = self.board.get_color_corner(color);
@ -294,6 +311,23 @@ impl GameState {
true true
} }
// ----------------------------------------------------------------------------------
// State updates
// ----------------------------------------------------------------------------------
fn add_player(&mut self, player_id: PlayerId, player: Player) {
self.players.insert(player_id, player);
}
pub fn switch_active_player(&mut self) {
let other_player_id = self
.players
.iter()
.filter(|(id, _player)| **id != self.active_player_id)
.map(|(id, _player)| *id)
.next();
self.active_player_id = other_player_id.unwrap_or(0);
}
/// Consumes an event, modifying the GameState and adding the event to its history /// Consumes an event, modifying the GameState and adding the event to its history
/// NOTE: consume assumes the event to have already been validated and will accept *any* event passed to it /// NOTE: consume assumes the event to have already been validated and will accept *any* event passed to it
pub fn consume(&mut self, valid_event: &GameEvent) { pub fn consume(&mut self, valid_event: &GameEvent) {
@ -302,6 +336,7 @@ impl GameState {
BeginGame { goes_first } => { BeginGame { goes_first } => {
self.active_player_id = *goes_first; self.active_player_id = *goes_first;
self.stage = Stage::InGame; self.stage = Stage::InGame;
self.turn_stage = TurnStage::RollDice;
} }
EndGame { reason: _ } => self.stage = Stage::Ended, EndGame { reason: _ } => self.stage = Stage::Ended,
PlayerJoined { player_id, name } => { PlayerJoined { player_id, name } => {
@ -325,7 +360,16 @@ 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.roll();
self.turn_stage = TurnStage::MarkPoints;
}
Mark { player_id, points } => {
self.mark_points(*player_id, *points);
if self.stage != Stage::Ended {
self.turn_stage = TurnStage::Move;
}
}
Move { player_id, moves } => { Move { player_id, moves } => {
let player = self.players.get(player_id).unwrap(); let player = self.players.get(player_id).unwrap();
self.board.move_checker(&player.color, moves.0).unwrap(); self.board.move_checker(&player.color, moves.0).unwrap();
@ -346,6 +390,10 @@ impl GameState {
pub fn determine_winner(&self) -> Option<PlayerId> { pub fn determine_winner(&self) -> Option<PlayerId> {
None None
} }
fn mark_points(&mut self, player_id: PlayerId, points: u8) {
todo!()
}
} }
/// The reasons why a game could end /// The reasons why a game could end
@ -376,6 +424,10 @@ pub enum GameEvent {
Roll { Roll {
player_id: PlayerId, player_id: PlayerId,
}, },
Mark {
player_id: PlayerId,
points: u8,
},
Move { Move {
player_id: PlayerId, player_id: PlayerId,
moves: (CheckerMove, CheckerMove), moves: (CheckerMove, CheckerMove),
@ -383,7 +435,7 @@ pub enum GameEvent {
} }
impl Roll for GameState { impl Roll for GameState {
fn roll(&mut self) -> Result<&mut Self, Error> { fn roll(&mut self) -> &mut Self {
self.dices = self.dices.roll(); self.dices = self.dices.roll();
if self.who_plays().is_none() { if self.who_plays().is_none() {
let active_color = match self.dices.coin() { let active_color = match self.dices.coin() {
@ -395,7 +447,7 @@ impl Roll for GameState {
self.active_player_id = *color_player_id.unwrap(); self.active_player_id = *color_player_id.unwrap();
} }
} }
Ok(self) self
} }
} }
@ -490,4 +542,22 @@ mod tests {
let event: GameEvent = GameEvent::Move { player_id, moves }; let event: GameEvent = GameEvent::Move { player_id, moves };
assert!(!state.validate(&event)); assert!(!state.validate(&event));
} }
#[test]
fn test_moves_follow_dices() {
let mut state = GameState::default();
let player1 = Player::new("player1".into(), Color::White);
let player_id = 1;
state.add_player(player_id, player1);
state.add_player(2, Player::new("player2".into(), Color::Black));
state.consume(&GameEvent::BeginGame {
goes_first: player_id,
});
state.consume(&GameEvent::Roll { player_id });
let moves = (
CheckerMove::new(1, 5).unwrap(),
CheckerMove::new(6, 9).unwrap(),
);
assert!(state.moves_follows_dices(&Color::White, &moves));
}
} }