cli move checkers

This commit is contained in:
Henri Bourcereau 2024-03-09 22:20:11 +01:00
parent 68d361b562
commit be0264f9a7
5 changed files with 120 additions and 15 deletions

View file

@ -1,5 +1,5 @@
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use store::GameState; use store::{CheckerMove, GameEvent, GameState, PlayerId};
// Application. // Application.
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -7,14 +7,30 @@ pub struct App {
// should the application exit? // should the application exit?
pub should_quit: bool, pub should_quit: bool,
pub game: GameState, pub game: GameState,
first_move: Option<CheckerMove>,
player_id: Option<PlayerId>,
} }
impl App { impl App {
// Constructs a new instance of [`App`]. // Constructs a new instance of [`App`].
pub fn new() -> Self { pub fn new() -> Self {
Self::default() // Self::default()
let mut state = GameState::default();
// local : player
let player_id: Option<PlayerId> = state.init_player("myself");
state.init_player("adversary");
println!("player_id ? {:?}", player_id);
Self {
game: state,
should_quit: false,
first_move: None,
player_id,
}
} }
fn get_my_player(&mut self) {}
// Constructs a new instance of [`App`]. // Constructs a new instance of [`App`].
pub fn start(&mut self) { pub fn start(&mut self) {
self.game = GameState::new(); self.game = GameState::new();
@ -22,10 +38,12 @@ impl App {
pub fn input(&mut self, input: &str) { pub fn input(&mut self, input: &str) {
println!("'{}'", input); println!("'{}'", input);
println!("'{}'", self.display()); match input {
if input == "quit" { "quit" => self.quit(),
self.quit(); "roll" => self.roll_dice(),
_ => self.add_move(input),
} }
println!("{}", self.display());
} }
// Set running to false to quit the application. // Set running to false to quit the application.
@ -33,6 +51,36 @@ impl App {
self.should_quit = true; self.should_quit = true;
} }
// Set running to false to quit the application.
fn roll_dice(&mut self) {}
fn add_move(&mut self, input: &str) {
if self.player_id.is_none() {
println!("player_id not set ");
return;
}
let positions: Vec<usize> = input
.split(' ')
.map(|str| str.parse().unwrap_or(0))
.collect();
if positions.len() == 2 && positions[0] != 0 && positions[1] != 0 {
let checker_move = CheckerMove::new(positions[0], positions[1]);
if checker_move.is_ok() {
if self.first_move.is_some() {
self.game.consume(&GameEvent::Move {
player_id: self.player_id.unwrap(),
moves: (self.first_move.unwrap(), checker_move.unwrap()),
});
self.first_move = None;
} else {
self.first_move = Some(checker_move.unwrap());
}
return;
}
}
println!("invalid move : {}", input);
}
pub fn display(&mut self) -> String { pub fn display(&mut self) -> String {
let mut board = "".to_owned(); let mut board = "".to_owned();
board = board + &self.game.board.to_display_grid(9); board = board + &self.game.board.to_display_grid(9);
@ -74,4 +122,37 @@ mod tests {
let mut app = App::default(); let mut app = App::default();
self::assert_eq!(app.display(), expected); self::assert_eq!(app.display(), expected);
} }
#[test]
fn test_move() {
let expected = "
13 14 15 16 17 18 19 20 21 22 23 24
----------------------------------------------------------------
| | | X |
| | | X |
| | | X |
| | | X |
| | | X |
| | | X |
| | | X |
| | | X |
| | | 15 |
|----------------------------- | | ------------------------------|
| | | 13 |
| | | O |
| | | O |
| | | O |
| | | O |
| | | O |
| | | O |
| | | O |
| | | O O O |
----------------------------------------------------------------
12 11 10 9 8 7 6 5 4 3 2 1
";
let mut app = App::new();
app.input("1 4");
app.input("1 5");
self::assert_eq!(app.display(), expected);
}
} }

View file

@ -323,7 +323,7 @@ impl Board {
if Some(color) != checker_color { if Some(color) != checker_color {
return Err(Error::FieldInvalid); return Err(Error::FieldInvalid);
} }
self.positions[field] -= 1; self.positions[field - 1] -= 1;
Ok(()) Ok(())
} }
@ -333,7 +333,7 @@ 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; self.positions[field - 1] += 1;
Ok(()) Ok(())
} }
} }

View file

@ -334,6 +334,24 @@ impl GameState {
// State updates // State updates
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
pub fn init_player(&mut self, player_name: &str) -> Option<PlayerId> {
if self.players.len() > 2 {
println!("more than two players");
return None;
}
let player_id = self.players.len() + 1;
println!("player_id {}", player_id);
let color = if player_id == 1 {
Color::White
} else {
Color::Black
};
let player = Player::new(player_name.into(), color);
self.players.insert(player_id as PlayerId, player);
Some(player_id as PlayerId)
}
fn add_player(&mut self, player_id: PlayerId, player: Player) { fn add_player(&mut self, player_id: PlayerId, player: Player) {
self.players.insert(player_id, player); self.players.insert(player_id, player);
} }

View file

@ -2,7 +2,7 @@ mod game;
pub use game::{EndGameReason, GameEvent, GameState, Stage}; pub use game::{EndGameReason, GameEvent, GameState, Stage};
mod player; mod player;
pub use player::{Player, Color}; pub use player::{Color, Player, PlayerId};
mod error; mod error;
pub use error::Error; pub use error::Error;

View file

@ -1,11 +1,10 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt; use std::fmt;
// This just makes it easier to dissern between a player id and any ol' u64 // This just makes it easier to dissern between a player id and any ol' u64
pub type PlayerId = u64; pub type PlayerId = u64;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Copy, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Color { pub enum Color {
White, White,
Black, Black,
@ -23,7 +22,6 @@ pub struct Player {
} }
impl Player { impl Player {
pub fn new(name: String, color: Color) -> Self { pub fn new(name: String, color: Color) -> Self {
Player { Player {
name, name,
@ -36,9 +34,11 @@ impl Player {
} }
pub fn to_bits_string(&self) -> String { pub fn to_bits_string(&self) -> String {
format!("{:0>4b}{:0>4b}{:b}{:b}", self.points, self.holes, self.can_bredouille as u8, self.can_big_bredouille as u8) format!(
"{:0>4b}{:0>4b}{:b}{:b}",
self.points, self.holes, self.can_bredouille as u8, self.can_big_bredouille as u8
)
} }
} }
/// Represents a player in the game. /// Represents a player in the game.
@ -97,9 +97,15 @@ mod tests {
#[test] #[test]
fn test_to_bits_string() { fn test_to_bits_string() {
let player = Player { name: "Edgar".into(), color: Color::White, points: 11, holes: 3, can_bredouille: true, can_big_bredouille: false }; let player = Player {
name: "Edgar".into(),
color: Color::White,
points: 11,
holes: 3,
can_bredouille: true,
can_big_bredouille: false,
};
println!("{}", player.to_bits_string()); println!("{}", player.to_bits_string());
assert!(player.to_bits_string() == "1011001110"); assert!(player.to_bits_string() == "1011001110");
} }
} }