diff --git a/Cargo.lock b/Cargo.lock index 8c5d4fc..7ff8537 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1243,6 +1243,7 @@ dependencies = [ "anyhow", "bincode", "pico-args", + "pretty_assertions", "renet", "store", ] @@ -1512,6 +1513,12 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "dispatch" version = "0.2.0" @@ -2839,6 +2846,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -3263,8 +3280,15 @@ dependencies = [ "log", "rand", "serde", + "transpose", ] +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + [[package]] name = "strum" version = "0.25.0" @@ -3510,6 +3534,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "transpose" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6522d49d03727ffb138ae4cbc1283d3774f0d10aa7f9bf52e6784c45daf9b23" +dependencies = [ + "num-integer", + "strength_reduce", +] + [[package]] name = "trictrac-client" version = "0.1.0" @@ -4128,6 +4162,12 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "zerocopy" version = "0.7.18" diff --git a/client_cli/Cargo.toml b/client_cli/Cargo.toml index d2bed0c..1b08baa 100644 --- a/client_cli/Cargo.toml +++ b/client_cli/Cargo.toml @@ -9,5 +9,6 @@ edition = "2021" anyhow = "1.0.75" bincode = "1.3.3" pico-args = "0.5.0" +pretty_assertions = "1.4.0" renet = "0.0.13" store = { path = "../store" } diff --git a/client_cli/src/app.rs b/client_cli/src/app.rs index 103fb7c..21aa9b9 100644 --- a/client_cli/src/app.rs +++ b/client_cli/src/app.rs @@ -1,3 +1,4 @@ +use pretty_assertions::assert_eq; use store::GameState; // Application. @@ -33,20 +34,9 @@ impl App { } pub fn display(&mut self) -> String { - let mut board = " - 24 23 22 21 20 19 18 17 16 15 14 13 --------------------------------------------------------------------" - .to_owned(); - board = board - + "------------------------------------------------------------------- - 1 2 3 4 5 6 7 8 9 10 11 12 "; - - // ligne 1 à 8 : positions 24 à 13 - // ligne 9 nombre exact - // ligne 10 --- - // lignes 11 à 18 : positions 1 à 12 + let mut board = "".to_owned(); + board = board + &self.game.board.to_display_grid(9); board - // self.game.to_string() } } @@ -57,30 +47,31 @@ mod tests { #[test] fn test_display() { let expected = " - 24 23 22 21 20 19 18 17 16 15 14 13 -------------------------------------------------------------------- -| | | X | -| | | X | -| | | X | -| | | X | -| | | X | -| | | X | -| | | X | -| | | X | -| | | 15 | -|------------------------------ | | ------------------------------| -| | | 15 | -| | | O | -| | | O | -| | | O | -| | | O | -| | | O | -| | | O | -| | | O | -| | | O | -------------------------------------------------------------------- - 1 2 3 4 5 6 7 8 9 10 11 12 "; + 13 14 15 16 17 18 19 20 21 22 23 24 + ---------------------------------------------------------------- + | | | X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | X | + | | | 15 | + |----------------------------- | | ------------------------------| + | | | 15 | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O | + | | | O | + ---------------------------------------------------------------- + 12 11 10 9 8 7 6 5 4 3 2 1 +"; let mut app = App::default(); - assert_eq!(app.display(), expected); + self::assert_eq!(app.display(), expected); } } diff --git a/store/Cargo.toml b/store/Cargo.toml index d474ce3..4fef1f8 100644 --- a/store/Cargo.toml +++ b/store/Cargo.toml @@ -10,3 +10,4 @@ base64 = "0.21.7" log = "0.4.20" rand = "0.8.5" serde = { version = "1.0", features = ["derive"] } +transpose = "0.2.2" diff --git a/store/src/board.rs b/store/src/board.rs index 3bc7023..703298e 100644 --- a/store/src/board.rs +++ b/store/src/board.rs @@ -1,6 +1,7 @@ use crate::player::{Color, Player}; use crate::Error; use serde::{Deserialize, Serialize}; +use std::cmp; use std::fmt; /// field (aka 'point') position on the board (from 0 to 24, 0 being 'outside') @@ -12,6 +13,19 @@ pub struct CheckerMove { to: Field, } +fn transpose(matrix: Vec>) -> Vec> { + let num_cols = matrix.first().unwrap().len(); + let mut row_iters: Vec<_> = matrix.into_iter().map(Vec::into_iter).collect(); + let mut out: Vec> = (0..num_cols).map(|_| Vec::new()).collect(); + + for out_row in out.iter_mut() { + for it in row_iters.iter_mut() { + out_row.push(it.next().unwrap()); + } + } + out +} + impl CheckerMove { pub fn new(from: Field, to: Field) -> Result { // check if the field is on the board @@ -113,6 +127,81 @@ impl Board { pos_bits.iter().collect::() } + /// format positions to a grid of symbols + pub fn to_display_grid(&self, col_size: usize) -> String { + // convert numbers to columns of chars + let mut columns: Vec> = self + .positions + .iter() + .map(|count| { + let char = if *count > 0 { "O" } else { "X" }; + let men_count = count.abs(); + let mut cells = vec!["".to_owned(); col_size]; + cells[0..(cmp::min(men_count, col_size as i8) as usize)].fill(char.to_owned()); + if men_count as usize > col_size { + cells[col_size - 1] = men_count.to_string(); + } + cells + }) + .collect(); + + // upper columns (13 to 24) + let upper_positions: Vec> = columns.split_off(12).into_iter().collect(); + + // lower columns (12 to 1) + let mut lower_positions: Vec> = columns + .into_iter() + .map(|mut col| { + col.reverse(); + col + }) + .collect(); + lower_positions.reverse(); + + // display board columns + let upper: Vec = transpose(upper_positions) + .into_iter() + .map(|cells| { + cells + .into_iter() + .map(|cell| format!("{:>5}", cell)) + .collect::>() + .join("") + }) + .collect(); + + let lower: Vec = transpose(lower_positions) + .into_iter() + .map(|cells| { + cells + .into_iter() + .map(|cell| format!("{:>5}", cell)) + .collect::>() + .join("") + }) + .collect(); + + let mut output = " + 13 14 15 16 17 18 19 20 21 22 23 24 + ----------------------------------------------------------------\n" + .to_owned(); + for mut line in upper { + // add middle bar + line.replace_range(30..30, "| |"); + output = output + " |" + &line + " |\n"; + } + output = output + " |----------------------------- | | ------------------------------|\n"; + for mut line in lower { + // add middle bar + line.replace_range(30..30, "| |"); + output = output + " |" + &line + " |\n"; + } + output = output + + " ---------------------------------------------------------------- + 12 11 10 9 8 7 6 5 4 3 2 1 \n"; + output + } + /// 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