use crate::logic::{ pawn::Pawn, player::Player, utils::{Field, Position}, }; use std::ops::Index; use log::{debug, info}; pub struct Board { board: Vec, pub size: usize, } impl Board { /// Board is always a square. Size parameter is a side of this rectangle. Defaults to 8 pub fn new(player1: &Player, player2: &Player, size: Option) -> Self { let size = size.unwrap_or(8); info!("Creating new board of size: {}", size); let board: Vec = (0..size) .flat_map(|row| { (0..size).map(move |column| { let is_row_even: bool = row % 2 == 0; let is_column_even: bool = column % 2 == 0; let is_valid_place_for_a_pawn: bool = is_row_even ^ is_column_even; let position: Position = Position { row, column }; // first player's pawns if row < 3 && is_valid_place_for_a_pawn { debug!("Placing new pawn at: {}, owned by: {}", position, player1); Field { position, pawn: Some(Pawn::new(position, &player1)), } } else if row >= size - 3 && is_valid_place_for_a_pawn { debug!("Placing new pawn at: {}, owned by: {}", position, player2); Field { position, pawn: Some(Pawn::new(position, &player2)), } } else { // no pawn debug!("Not placing any pawn at: {}", position); Field { position, pawn: None, } } }) }) .collect(); Board { board, size } } } impl Index for Board { type Output = [Field]; fn index<'a>(&'a self, i: usize) -> &'a [Field] { let start = i * &self.size; let end: usize = start + &self.size; &self.board[start..end] } } #[cfg(test)] mod tests { use uuid::Uuid; use crate::logic::pawn::PawnState; use super::*; fn init_logger() { let _ = env_logger::builder().is_test(true).try_init(); } #[test] fn new_board_test() { init_logger(); let player1: Player = Player { name: String::from("Morbius"), id: Uuid::new_v4(), }; let player2: Player = Player { name: String::from("Milo"), id: Uuid::new_v4(), }; let test_board: Board = Board::new(&player1, &player2, None); let size: usize = test_board.size; for row in 0..size { for column in 0..size { assert_eq!(test_board[row][column].position.row, row); assert_eq!(test_board[row][column].position.column, column); } } for row in 0..size { for column in 0..size { let is_row_even: bool = row % 2 == 0; let is_column_even: bool = column % 2 == 0; let is_valid_place_for_a_pawn: bool = (is_row_even ^ is_column_even) && (row < 3 || row >= size - 3); if is_valid_place_for_a_pawn { assert!(test_board[row][column].pawn.is_some()); // we unwrap, because some value has to be here, if it's not then something is wrong // beside we check for that in the assert above assert!( test_board[row][column].pawn.as_ref().unwrap().state == PawnState::Man(Position { row, column }) ); if row < 3 { assert_eq!( test_board[row][column].pawn.as_ref().unwrap().owner, player1.id ) } else if row >= size - 3 { assert_eq!( test_board[row][column].pawn.as_ref().unwrap().owner, player2.id ) } } else { assert!(test_board[row][column].pawn.is_none()); } } } } }