From 23ab9666024114a313a0a5d99c4bc44d8dd6999a Mon Sep 17 00:00:00 2001 From: Henri Bourcereau Date: Tue, 9 Jan 2024 17:58:10 +0100 Subject: [PATCH] wip board --- doc/backlog.md | 3 +- doc/journal.md | 10 ++ store/src/board.rs | 345 ++++++++++++++++++++++++++++----------------- 3 files changed, 227 insertions(+), 131 deletions(-) diff --git a/doc/backlog.md b/doc/backlog.md index 95763bc..33e1aaa 100644 --- a/doc/backlog.md +++ b/doc/backlog.md @@ -30,9 +30,10 @@ cf. https://blessed.rs/crates ## Backgammon existing projects * go : https://bgammon.org/blog/20240101-hello-world/ + - protocole de communication : https://code.rocket9labs.com/tslocum/bgammon/src/branch/main/PROTOCOL.md * lib rust backgammon - - https://docs.rs/crate/backgammon/0.4.0 + - https://github.com/carlostrub/backgammon - https://github.com/marktani/backgammon * network webtarot * front ? diff --git a/doc/journal.md b/doc/journal.md index db5eccc..4585824 100644 --- a/doc/journal.md +++ b/doc/journal.md @@ -9,3 +9,13 @@ cargo add pico-args Organisation store / server / client selon https://herluf-ba.github.io/making-a-turn-based-multiplayer-game-in-rust-01-whats-a-turn-based-game-anyway _store_ est la bibliothèque contenant le _reducer_ qui transforme l'état du jeu en fonction les évènements. Elle est utilisée par le _server_ et le _client_. Seuls les évènements sont transmis entre clients et serveur. + +## Organisation du store + +lib + - game::GameState + - error + - dice + - board + - user + - user diff --git a/store/src/board.rs b/store/src/board.rs index 4ef9714..dc57cb3 100644 --- a/store/src/board.rs +++ b/store/src/board.rs @@ -1,42 +1,21 @@ -use crate::player::{Player, Color}; +use crate::player::{Color, Player}; use crate::Error; use serde::{Deserialize, Serialize}; /// Represents the Tric Trac board -/// -/// A Tric-Trac board consists of 24 fields, each of which can hold 0 or more checkers. -/// -/// ``` -/// # fn foo() {} -/// // +12-11-10--9--8--7-------6--5--4--3--2--1-+ -/// // | X O | | O X | +-------+ -/// // | X O | | O X | | OFF O | -/// // | X O | | O | +-------+ -/// // | X | | O | -/// // | X | | O | -/// // | | | | -/// // | O | | X | -/// // | O | | X | -/// // | O X | | X | +-------+ -/// // | O X | | X O | | OFF X | -/// // | O X | | X O | +-------+ -/// // +13-14-15-16-17-18------19-20-21-22-23-24-+ -/// ``` - -#[derive(Debug, Clone, Serialize, PartialEq, Deserialize, Default)] -pub struct Board { - raw_board: (PlayerBoard, PlayerBoard), +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +struct Board { + board: [i8; 24], } -/// Represents the Backgammon board for both players (to be used for graphical representation). -#[derive(Debug, Serialize, PartialEq, Deserialize)] -pub struct BoardDisplay { - /// The board represented as an array of 24 fields, each of which can hold 0 or more checkers. - /// Positive amounts represent checkers of player 0, negative amounts represent checkers of - /// player 1. - pub board: [i8; 24], - /// The off for both players - pub off: (u8, u8), +impl Default for Board { + fn default() -> Self { + Board { + board: [ + 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, + ], + } + } } impl Board { @@ -45,43 +24,17 @@ impl Board { Board::default() } - /// Get the board for both players. Use for graphical representation of the board. - /// - /// This method outputs a tuple with three values: - /// - /// 1. the board represented as an array of 24 fields, each of which can hold 0 or more - /// checkers. Positive amounts represent checkers of player 0, negative amounts represent - /// checkers of player 1. - /// 3. the off for both players - pub fn get(&self) -> BoardDisplay { - let mut board: [i8; 24] = [0; 24]; - - for (i, val) in board.iter_mut().enumerate() { - *val = self.raw_board.0.board[i] as i8 - self.raw_board.1.board[23 - i] as i8; - } - - BoardDisplay { - board, - off: self.get_off(), - } - } - - /// Get the off for both players - fn get_off(&self) -> (u8, u8) { - (self.raw_board.0.off, self.raw_board.1.off) - } - /// Set checkers for a player on a field /// /// This method adds the amount of checkers for a player on a field. The field is numbered from - /// 0 to 23, starting from the last field of each player in the home board, the most far away - /// field for each player is number 23. + /// 1 to 24, starting from the first field of each player in the home board, the most far away + /// field for each player is number 24. /// /// If the field is blocked for the player, an error is returned. If the field is not blocked, /// but there is already one checker from the other player on the field, that checker is hit and /// moved to the bar. pub fn set(&mut self, player: &Player, field: usize, amount: i8) -> Result<(), Error> { - if field > 23 { + if field > 24 { return Err(Error::FieldInvalid); } @@ -91,20 +44,20 @@ impl Board { match player.color { Color::White => { - let new = self.raw_board.0.board[field] as i8 + amount; + let new = self.board[field - 1] + amount; if new < 0 { return Err(Error::MoveInvalid); } - self.raw_board.0.board[field] = new as u8; + self.board[field - 1] = new; Ok(()) } Color::Black => { - let new = self.raw_board.1.board[field] as i8 + amount; - if new < 0 { + let new = self.board[24 - field] - amount; + if new > 0 { return Err(Error::MoveInvalid); } - self.raw_board.1.board[field] = new as u8; + self.board[24 - field] = new; Ok(()) } @@ -113,13 +66,13 @@ impl Board { /// Check if a field is blocked for a player pub fn blocked(&self, player: &Player, field: usize) -> Result { - if field > 23 { + if field > 24 { return Err(Error::FieldInvalid); } match player.color { Color::White => { - if self.raw_board.1.board[23 - field] > 1 { + if self.board[field - 1] < 0 { Ok(true) } else { Ok(false) @@ -134,41 +87,6 @@ impl Board { } } } - - /// Set checkers for a player off the board. This method adds amount to the already existing - /// checkers there. - pub fn set_off(&mut self, player: &Player, amount: u8) -> Result<(), Error> { - match player.color { - Color::White => { - let new = self.raw_board.0.off + amount; - self.raw_board.0.off = new; - Ok(()) - } - Color::Black => { - let new = self.raw_board.1.off + amount; - self.raw_board.1.off = new; - Ok(()) - } - } - } -} - -/// Represents the Backgammon board for one player -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -struct PlayerBoard { - board: [u8; 24], - off: u8, -} - -impl Default for PlayerBoard { - fn default() -> Self { - PlayerBoard { - board: [ - 0, 0, 0, 0, 0, 5, 0, 3, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, - ], - off: 0, - } - } } /// Trait to move checkers @@ -228,7 +146,10 @@ mod tests { #[test] fn set_player0() -> Result<(), Error> { let mut board = Board::new(); - let player = Player {name: "".into(), color: Color::White}; + let player = Player { + name: "".into(), + color: Color::White, + }; board.set(&player, 1, 1)?; assert_eq!(board.get().board[1], 1); Ok(()) @@ -237,7 +158,10 @@ mod tests { #[test] fn set_player1() -> Result<(), Error> { let mut board = Board::new(); - let player = Player {name: "".into(), color: Color::Black}; + let player = Player { + name: "".into(), + color: Color::Black, + }; board.set(&player, 2, 1)?; assert_eq!(board.get().board[21], -1); Ok(()) @@ -246,7 +170,10 @@ mod tests { #[test] fn set_player0_off() -> Result<(), Error> { let mut board = Board::new(); - let player = Player {name: "".into(), color: Color::White}; + let player = Player { + name: "".into(), + color: Color::White, + }; board.set_off(player, 1)?; assert_eq!(board.get().off.0, 1); Ok(()) @@ -255,7 +182,10 @@ mod tests { #[test] fn set_player1_off() -> Result<(), Error> { let mut board = Board::new(); - let player = Player {name: "".into(), color: Color::Black}; + let player = Player { + name: "".into(), + color: Color::Black, + }; board.set_off(player, 1)?; assert_eq!(board.get().off.1, 1); Ok(()) @@ -264,7 +194,10 @@ mod tests { #[test] fn set_player1_off1() -> Result<(), Error> { let mut board = Board::new(); - let player = Player {name: "".into(), color: Color::Black}; + let player = Player { + name: "".into(), + color: Color::Black, + }; board.set_off(player, 1)?; board.set_off(player, 1)?; assert_eq!(board.get().off.1, 2); @@ -274,44 +207,104 @@ mod tests { #[test] fn blocked_player0() -> Result<(), Error> { let board = Board::new(); - assert!(board.blocked(&Player { name:"".into(), color: Color::White }, 0)?); + assert!(board.blocked( + &Player { + name: "".into(), + color: Color::White + }, + 0 + )?); Ok(()) } #[test] fn blocked_player1() -> Result<(), Error> { let board = Board::new(); - assert!(board.blocked(&Player { name:"".into(), color: Color::Black }, 0)?); + assert!(board.blocked( + &Player { + name: "".into(), + color: Color::Black + }, + 0 + )?); Ok(()) } #[test] fn blocked_player0_a() -> Result<(), Error> { let mut board = Board::new(); - board.set(&Player { name:"".into(), color: Color::Black }, 1, 2)?; - assert!(board.blocked(&Player { name:"".into(), color: Color::White }, 22)?); + board.set( + &Player { + name: "".into(), + color: Color::Black, + }, + 1, + 2, + )?; + assert!(board.blocked( + &Player { + name: "".into(), + color: Color::White + }, + 22 + )?); Ok(()) } #[test] fn blocked_player1_a() -> Result<(), Error> { let mut board = Board::new(); - board.set(&Player { name:"".into(), color: Color::White }, 1, 2)?; - assert!(board.blocked(&Player { name:"".into(), color: Color::Black }, 22)?); + board.set( + &Player { + name: "".into(), + color: Color::White, + }, + 1, + 2, + )?; + assert!(board.blocked( + &Player { + name: "".into(), + color: Color::Black + }, + 22 + )?); Ok(()) } #[test] fn blocked_invalid_field() { let board = Board::new(); - assert!(board.blocked(&Player { name:"".into(), color: Color::White }, 24).is_err()); + assert!(board + .blocked( + &Player { + name: "".into(), + color: Color::White + }, + 24 + ) + .is_err()); } #[test] fn set_field_with_1_checker_player0_a() -> Result<(), Error> { let mut board = Board::new(); - board.set(&Player { name:"".into(), color: Color::White }, 1, 1)?; - board.set(&Player { name:"".into(), color: Color::Black }, 22, 1)?; + board.set( + &Player { + name: "".into(), + color: Color::White, + }, + 1, + 1, + )?; + board.set( + &Player { + name: "".into(), + color: Color::Black, + }, + 22, + 1, + )?; assert_eq!(board.get().board[1], -1); Ok(()) } @@ -319,8 +312,22 @@ mod tests { #[test] fn set_field_with_1_checker_player0_b() -> Result<(), Error> { let mut board = Board::new(); - board.set(&Player { name:"".into(), color: Color::White }, 1, 1)?; - board.set(&Player { name:"".into(), color: Color::Black }, 22, 1)?; + board.set( + &Player { + name: "".into(), + color: Color::White, + }, + 1, + 1, + )?; + board.set( + &Player { + name: "".into(), + color: Color::Black, + }, + 22, + 1, + )?; assert_eq!(board.get().board[1], -1); Ok(()) } @@ -328,8 +335,22 @@ mod tests { #[test] fn set_field_with_1_checker_player1_a() -> Result<(), Error> { let mut board = Board::new(); - board.set(&Player { name:"".into(), color: Color::Black }, 1, 1)?; - board.set(&Player { name:"".into(), color: Color::White }, 22, 1)?; + board.set( + &Player { + name: "".into(), + color: Color::Black, + }, + 1, + 1, + )?; + board.set( + &Player { + name: "".into(), + color: Color::White, + }, + 22, + 1, + )?; assert_eq!(board.get().board[22], 1); Ok(()) } @@ -337,8 +358,22 @@ mod tests { #[test] fn set_field_with_1_checker_player1_b() -> Result<(), Error> { let mut board = Board::new(); - board.set(&Player { name:"".into(), color: Color::Black }, 1, 1)?; - board.set(&Player { name:"".into(), color: Color::White }, 22, 1)?; + board.set( + &Player { + name: "".into(), + color: Color::Black, + }, + 1, + 1, + )?; + board.set( + &Player { + name: "".into(), + color: Color::White, + }, + 22, + 1, + )?; assert_eq!(board.get().board[22], 1); Ok(()) } @@ -346,7 +381,14 @@ mod tests { #[test] fn set_field_with_2_checkers_player0_a() -> Result<(), Error> { let mut board = Board::new(); - board.set(&Player { name:"".into(), color: Color::White }, 23, 2)?; + board.set( + &Player { + name: "".into(), + color: Color::White, + }, + 23, + 2, + )?; assert_eq!(board.get().board[23], 4); Ok(()) } @@ -354,7 +396,14 @@ mod tests { #[test] fn set_field_with_2_checkers_player0_b() -> Result<(), Error> { let mut board = Board::new(); - board.set(&Player { name:"".into(), color: Color::White }, 23, -1)?; + board.set( + &Player { + name: "".into(), + color: Color::White, + }, + 23, + -1, + )?; assert_eq!(board.get().board[23], 1); Ok(()) } @@ -362,24 +411,60 @@ mod tests { #[test] fn set_field_blocked() { let mut board = Board::new(); - assert!(board.set(&Player { name:"".into(), color: Color::White }, 0, 2).is_err()); + assert!(board + .set( + &Player { + name: "".into(), + color: Color::White + }, + 0, + 2 + ) + .is_err()); } #[test] fn set_wrong_field1() { let mut board = Board::new(); - assert!(board.set(&Player { name:"".into(), color: Color::White }, 50, 2).is_err()); + assert!(board + .set( + &Player { + name: "".into(), + color: Color::White + }, + 50, + 2 + ) + .is_err()); } #[test] fn set_wrong_amount0() { let mut board = Board::new(); - assert!(board.set(&Player { name:"".into(), color: Color::White }, 23, -3).is_err()); + assert!(board + .set( + &Player { + name: "".into(), + color: Color::White + }, + 23, + -3 + ) + .is_err()); } #[test] fn set_wrong_amount1() { let mut board = Board::new(); - assert!(board.set(&Player { name:"".into(), color: Color::Black }, 23, -3).is_err()); + assert!(board + .set( + &Player { + name: "".into(), + color: Color::Black + }, + 23, + -3 + ) + .is_err()); } }