diff --git a/Cargo.lock b/Cargo.lock index 3dfd350..ac90b9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,7 @@ version = "0.0.1" dependencies = [ "env_logger", "log", + "rand", "uuid", ] @@ -100,12 +101,32 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + [[package]] name = "colorchoice" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "defmt" version = "1.1.1" @@ -205,6 +226,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", + "rand_core", "wasip2", "wasip3", ] @@ -398,6 +420,23 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "regex" version = "1.13.1" diff --git a/Cargo.toml b/Cargo.toml index c7eaa2f..632801c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ edition = "2024" [dependencies] env_logger = "0.11.11" log = "0.4.33" +rand = "0.10.2" [dependencies.uuid] version = "1.24.0" diff --git a/src/logic/board/board.rs b/src/logic/board/board.rs index 3919680..b639186 100644 --- a/src/logic/board/board.rs +++ b/src/logic/board/board.rs @@ -186,7 +186,11 @@ impl Board { } } - Some(available_moves) + if available_moves.is_empty() { + None + } else { + Some(available_moves) + } } fn can_capture( @@ -197,19 +201,30 @@ impl Board { already_captured: &Vec, pawn: &Pawn, ) -> bool { + debug!("=== Checkinf if pawn can capture from: {} to {}", from, to); + if !self.is_player_owner_of_the_pawn(player, &pawn) { + debug!("Player wasn't owner of the pawn..."); + return false; + } + + if !to.is_in_range(self.size) { + debug!("Position was out of range..."); return false; } if already_captured.contains(&to) { + debug!("Pawn was already captured..."); return false; } let Some(captured_pawn) = &self[to].pawn else { + debug!("There was no pawn there..."); return false; }; if self.is_player_owner_of_the_pawn(player, captured_pawn) { + debug!("Player tried capturing his own pawn! Idiot"); return false; } @@ -336,11 +351,13 @@ impl Board { Some(available_captures) } - pub fn capture(&mut self, path: &CapturePath, capturing_player: &Player) { + pub fn capture(&mut self, path: &CapturePath, capturing_player: &Player) -> bool { /* debug!("Capturing: {}", path); */ + // TODO! Maybe return false ?? + let mut from = path.from; for (next_pos, enemy_path) in path.iter() { @@ -348,6 +365,8 @@ impl Board { self.move_pawn_anywhere(capturing_player, from, *next_pos); from = *next_pos; } + + true } pub fn get_player_pawns_positions(&self, player: &Player) -> Vec { diff --git a/src/logic/game_master.rs b/src/logic/game_master.rs index abfdaf0..9b5f1b5 100644 --- a/src/logic/game_master.rs +++ b/src/logic/game_master.rs @@ -1,8 +1,11 @@ +use log::warn; + use crate::logic::{ board::{ board::Board, pawn::{CapturePath, MovePath}, }, + math::position::Position, player::Player, }; @@ -82,9 +85,10 @@ impl GameMaster { let player_pawns = self.board.get_player_pawns_positions(player); player_pawns.len() == 0 - || player_pawns - .iter() - .all(|pos| self.board.get_available_moves(*pos, player).is_none()) + || player_pawns.iter().all(|pos| { + self.board.get_available_moves(*pos, player).is_none() + && self.board.get_available_captures(*pos, player).is_none() + }) } pub fn get_game_result(&self) -> Option { @@ -104,4 +108,101 @@ impl GameMaster { None } } + + pub fn move_pawn(&mut self, from: Position, to: Position) -> bool { + if self.get_current_player_moves().is_empty() { + warn!( + "Player: {} tried moving, but they don't have any moves available!", + self.players.get_current_turn().id + ); + return false; + } + + if !self.get_current_player_captures().is_empty() { + warn!( + "Player: {} tried moving, but he has captures available!", + self.players.get_current_turn().id + ); + return false; + } + + if self + .board + .move_pawn(self.players.get_current_turn(), from, to) + { + self.players.change_turn(); + return true; + } + false + } + + pub fn capture(&mut self, path: &CapturePath) -> bool { + if self.get_current_player_captures().is_empty() { + warn!( + "Player: {} tried capturing, but he doesn't have any captures available!", + self.players.get_current_turn().id + ); + return false; + } + + if self.board.capture(path, self.players.get_current_turn()) { + self.players.change_turn(); + return true; + } + + false + } +} + +#[cfg(test)] +mod tests { + use super::*; + use log::info; + use rand::seq::IndexedMutRandom; + use rand::seq::IndexedRandom; + use rand::seq::SliceRandom; + + #[test] + fn test_game_flow() { + let mut master: GameMaster = GameMaster::new("Morbius".to_string(), "Milo".to_string()); + let mut turns = 0; + let max_turns = 2000; + + while turns < max_turns { + if let Some(result) = master.get_game_result() { + match result { + GameResult::Lost(loser_id) => { + info!("Player: {} lost! Ending the loop", loser_id); + } + GameResult::Draw => { + info!("Game ended in a draw! Ending the loop"); + } + } + break; + } + + let mut rng = rand::rng(); + + let available_captures = master.get_current_player_captures(); + + if !available_captures.is_empty() { + let capture = available_captures.choose(&mut rng).unwrap(); + master.capture(capture); + turns += 1; + continue; + } + + let mut available_moves = master.get_current_player_moves(); + if !available_moves.is_empty() { + let path = available_moves.choose_mut(&mut rng).unwrap(); + let from = path.from; + let to = path.available_steps.choose_mut(&mut rng).unwrap(); + + master.move_pawn(from, *to); + turns += 1; + } + } + + assert!(turns < max_turns); + } }