This commit is contained in:
Henri Bourcereau 2024-03-11 20:45:36 +01:00
parent 44c040b414
commit a886526fcf
5 changed files with 205 additions and 97 deletions

View file

@ -1,39 +1,60 @@
use pretty_assertions::assert_eq;
use store::{CheckerMove, GameEvent, GameState, PlayerId};
use store::{CheckerMove, Dice, DiceRoller, GameEvent, GameState, PlayerId};
#[derive(Debug, Default)]
pub struct AppArgs {
pub seed: Option<u32>,
}
// Application Game
#[derive(Debug, Default)]
pub struct Game {
pub state: GameState,
pub dice_roller: DiceRoller,
first_move: Option<CheckerMove>,
player_id: Option<PlayerId>,
}
impl Game {
// Constructs a new instance of [`App`].
pub fn new(seed: Option<u64>) -> Self {
let mut state = GameState::default();
// local : player
let player_id: Option<PlayerId> = state.init_player("myself");
state.init_player("adversary");
state.consume(&GameEvent::BeginGame {
goes_first: player_id.unwrap(),
});
Self {
state,
dice_roller: DiceRoller::new(seed),
first_move: None,
player_id,
}
}
}
// Application.
#[derive(Debug, Default)]
pub struct App {
// should the application exit?
pub should_quit: bool,
pub game: GameState,
first_move: Option<CheckerMove>,
player_id: Option<PlayerId>,
pub game: Game,
}
impl App {
// Constructs a new instance of [`App`].
pub fn new() -> Self {
// 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);
pub fn new(args: AppArgs) -> Self {
Self {
game: state,
game: Game::new(args.seed.map(|s| s as u64)),
should_quit: false,
first_move: None,
player_id,
}
}
fn get_my_player(&mut self) {}
// Constructs a new instance of [`App`].
pub fn start(&mut self) {
self.game = GameState::new();
self.game.state = GameState::new();
}
pub fn input(&mut self, input: &str) {
@ -52,17 +73,19 @@ impl App {
}
fn roll_dice(&mut self) {
if self.player_id.is_none() {
if self.game.player_id.is_none() {
println!("player_id not set ");
return;
}
self.game.consume(&GameEvent::Roll {
player_id: self.player_id.unwrap(),
let dice = self.game.dice_roller.roll();
self.game.state.consume(&GameEvent::RollResult {
player_id: self.game.player_id.unwrap(),
dice,
});
}
fn add_move(&mut self, input: &str) {
if self.player_id.is_none() {
if self.game.player_id.is_none() {
println!("player_id not set ");
return;
}
@ -73,20 +96,20 @@ impl App {
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() {
if self.game.first_move.is_some() {
let move_event = GameEvent::Move {
player_id: self.player_id.unwrap(),
moves: (self.first_move.unwrap(), checker_move.unwrap()),
player_id: self.game.player_id.unwrap(),
moves: (self.game.first_move.unwrap(), checker_move.unwrap()),
};
if !self.game.validate(&move_event) {
if !self.game.state.validate(&move_event) {
println!("Move invalid");
self.first_move = None;
self.game.first_move = None;
return;
}
self.game.consume(&move_event);
self.first_move = None;
self.game.state.consume(&move_event);
self.game.first_move = None;
} else {
self.first_move = Some(checker_move.unwrap());
self.game.first_move = Some(checker_move.unwrap());
}
return;
}
@ -96,9 +119,9 @@ impl App {
pub fn display(&mut self) -> String {
let mut output = "-------------------------------".to_owned();
output = output + "\nRolled dice : " + &self.game.dices.to_display_string();
output = output + "\nRolled dice : " + &self.game.state.dice.to_display_string();
output = output + "\n-------------------------------";
output = output + "\n" + &self.game.board.to_display_grid(9);
output = output + "\n" + &self.game.state.board.to_display_grid(9);
output
}
}
@ -144,7 +167,7 @@ Rolled dice : 0 & 0
#[test]
fn test_move() {
let expected = "-------------------------------
Rolled dice : 0 & 0
Rolled dice : 2 & 3
-------------------------------
13 14 15 16 17 18 19 20 21 22 23 24
@ -167,13 +190,14 @@ Rolled dice : 0 & 0
| | | 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();
let mut app = App::new(AppArgs { seed: Some(1327) });
app.input("roll");
app.input("1 3");
app.input("1 4");
app.input("1 5");
self::assert_eq!(app.display(), expected);
}
}

View file

@ -2,12 +2,38 @@
pub mod app;
use anyhow::Result;
use app::App;
use app::{App, AppArgs};
use std::io;
// see pico-args example at https://github.com/RazrFalcon/pico-args/blob/master/examples/app.rs
const HELP: &str = "\
Trictrac CLI
USAGE:
trictrac-cli [OPTIONS]
FLAGS:
-h, --help Prints help information
OPTIONS:
--seed SEED Sets the random generator seed
ARGS:
<INPUT>
";
fn main() -> Result<()> {
let args = match parse_args() {
Ok(v) => v,
Err(e) => {
eprintln!("Error: {}.", e);
std::process::exit(1);
}
};
// println!("{:#?}", args);
// Create an application.
let mut app = App::new();
let mut app = App::new(args);
// Start the main loop.
while !app.should_quit {
@ -19,3 +45,32 @@ fn main() -> Result<()> {
Ok(())
}
fn parse_args() -> Result<AppArgs, pico_args::Error> {
let mut pargs = pico_args::Arguments::from_env();
// Help has a higher priority and should be handled separately.
if pargs.contains(["-h", "--help"]) {
print!("{}", HELP);
std::process::exit(0);
}
let args = AppArgs {
// Parses an optional value that implements `FromStr`.
seed: pargs.opt_value_from_str("--seed")?,
// Parses an optional value from `&str` using a specified function.
// width: pargs.opt_value_from_fn("--width", parse_width)?.unwrap_or(10),
};
// It's up to the caller what to do with the remaining arguments.
let remaining = pargs.finish();
if !remaining.is_empty() {
eprintln!("Warning: unused arguments left: {:?}.", remaining);
}
Ok(args)
}
// fn parse_width(s: &str) -> Result<u32, &'static str> {
// s.parse().map_err(|_| "not a number")
// }