diff --git a/sea_battle_backend/src/bot_client.rs b/sea_battle_backend/src/bot_client.rs index bf62244..2e073fa 100644 --- a/sea_battle_backend/src/bot_client.rs +++ b/sea_battle_backend/src/bot_client.rs @@ -34,7 +34,7 @@ pub async fn run_client( while let Some(chunk) = socket.next().await { let message = match chunk? { Message::Text(message) => { - log::debug!("TEXT message from server: {}", message); + log::trace!("TEXT message from server: {}", message); let msg: ServerMessage = serde_json::from_str(&message)?; msg @@ -79,8 +79,13 @@ pub async fn run_client( } ServerMessage::OtherPlayerReady => log::debug!("Other player is ready!"), ServerMessage::GameStarting => log::debug!("The game is starting..."), - ServerMessage::OtherPlayerMustFire { .. } => log::debug!("Other player must fire!"), + ServerMessage::OtherPlayerMustFire { status } => { + assert_eq!(status.opponent_map.boats.number_of_boats(), 0); + log::debug!("Other player must fire!") + } ServerMessage::RequestFire { status } => { + assert_eq!(status.opponent_map.boats.number_of_boats(), 0); + let location = status.find_valid_random_fire_location(); log::debug!("Will fire at {:?}", location); socket @@ -119,6 +124,7 @@ pub async fn run_client( log::warn!("Rejected boat layout: {:?}", errors); return Ok(ClientEndResult::InvalidBoatsLayout); } + ServerMessage::SetOpponentName { name } => log::debug!("Opponent name: {}", name), } } diff --git a/sea_battle_backend/src/data/boats_layout.rs b/sea_battle_backend/src/data/boats_layout.rs index a2b20aa..0dc65e5 100644 --- a/sea_battle_backend/src/data/boats_layout.rs +++ b/sea_battle_backend/src/data/boats_layout.rs @@ -151,6 +151,11 @@ impl BoatPosition { pub struct BoatsLayout(Vec); impl BoatsLayout { + /// Generate a new invalid (empty) boats layout + pub fn new_invalid() -> Self { + Self(vec![]) + } + /// Generate random boats layout for given game rules pub fn gen_random_for_rules(rules: &GameRules) -> std::io::Result { let mut boats = Self(Vec::with_capacity(rules.boats_list().len())); diff --git a/sea_battle_backend/src/data/current_game_status.rs b/sea_battle_backend/src/data/current_game_status.rs index 3d570df..5f592ff 100644 --- a/sea_battle_backend/src/data/current_game_status.rs +++ b/sea_battle_backend/src/data/current_game_status.rs @@ -1,17 +1,27 @@ -use crate::data::{Coordinates, GameRules}; use rand::RngCore; +use crate::data::{BoatPosition, BoatsLayout, Coordinates, GameRules}; + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct CurrentGameMapStatus { + pub boats: BoatsLayout, + pub successful_strikes: Vec, + pub failed_strikes: Vec, + pub sunk_boats: Vec, +} + #[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct CurrentGameStatus { pub rules: GameRules, - //TODO + pub your_map: CurrentGameMapStatus, + pub opponent_map: CurrentGameMapStatus, } impl CurrentGameStatus { - /// Check if user can fire at a given location - pub fn can_fire_at_location(&self, _location: Coordinates) -> bool { - //TODO - true + /// Check if opponent can fire at a given location + pub fn can_fire_at_location(&self, location: Coordinates) -> bool { + !self.opponent_map.successful_strikes.contains(&location) + && !self.opponent_map.failed_strikes.contains(&location) } /// Find valid random fire location. Loop until one is found diff --git a/sea_battle_backend/src/data/game_map.rs b/sea_battle_backend/src/data/game_map.rs index 01ad39a..2556f41 100644 --- a/sea_battle_backend/src/data/game_map.rs +++ b/sea_battle_backend/src/data/game_map.rs @@ -1,5 +1,5 @@ use crate::data::boats_layout::{BoatsLayout, Coordinates}; -use crate::data::{BoatPosition, EndGameMap, GameRules}; +use crate::data::{BoatPosition, CurrentGameMapStatus, EndGameMap, GameRules}; #[derive(Debug, Copy, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] pub enum FireResult { @@ -133,6 +133,18 @@ impl GameMap { } } + pub fn current_map_status(&self, for_opponent: bool) -> CurrentGameMapStatus { + CurrentGameMapStatus { + boats: match for_opponent { + true => BoatsLayout::new_invalid(), + false => self.boats_config.clone(), + }, + successful_strikes: self.successful_strikes.clone(), + failed_strikes: self.failed_strikes.clone(), + sunk_boats: self.sunk_boats.clone(), + } + } + pub fn final_map(&self) -> EndGameMap { EndGameMap { boats: self.boats_config.clone(), diff --git a/sea_battle_backend/src/game.rs b/sea_battle_backend/src/game.rs index 189dfaf..939513e 100644 --- a/sea_battle_backend/src/game.rs +++ b/sea_battle_backend/src/game.rs @@ -11,6 +11,8 @@ pub trait Player { fn get_uid(&self) -> Uuid; + fn set_other_player_name(&self, name: &str); + fn query_boats_layout(&self, rules: &GameRules); fn rejected_boats_layout(&self, errors: Vec<&'static str>); @@ -82,6 +84,9 @@ impl Game { /// Once the two player has been registered, the game may start fn query_boats_disposition(&mut self) { + self.players[0].set_other_player_name(self.players[1].get_name()); + self.players[1].set_other_player_name(self.players[0].get_name()); + log::debug!("Query boats disposition"); assert_eq!(self.status, GameStatus::Created); self.status = GameStatus::WaitingForBoatsDisposition; @@ -160,9 +165,11 @@ impl Game { } /// Get current game status for a specific player - fn get_game_status_for_player(&self, _id: usize) -> CurrentGameStatus { + fn get_game_status_for_player(&self, id: usize) -> CurrentGameStatus { CurrentGameStatus { rules: self.rules.clone(), + your_map: self.player_map(id).current_map_status(false), + opponent_map: self.player_map(opponent(id)).current_map_status(true), } } } diff --git a/sea_battle_backend/src/human_player.rs b/sea_battle_backend/src/human_player.rs index d0f244f..73c220e 100644 --- a/sea_battle_backend/src/human_player.rs +++ b/sea_battle_backend/src/human_player.rs @@ -21,6 +21,12 @@ impl Player for HumanPlayer { self.uuid } + fn set_other_player_name(&self, name: &str) { + self.player.do_send(ServerMessage::SetOpponentName { + name: name.to_string(), + }); + } + fn query_boats_layout(&self, rules: &GameRules) { self.player.do_send(ServerMessage::QueryBoatsLayout { rules: rules.clone(), diff --git a/sea_battle_backend/src/human_player_ws.rs b/sea_battle_backend/src/human_player_ws.rs index 70e9250..ba7057a 100644 --- a/sea_battle_backend/src/human_player_ws.rs +++ b/sea_battle_backend/src/human_player_ws.rs @@ -41,6 +41,9 @@ pub enum ClientMessage { #[serde(tag = "type")] pub enum ServerMessage { WaitingForAnotherPlayer, + SetOpponentName { + name: String, + }, QueryBoatsLayout { rules: GameRules, }, diff --git a/sea_battle_backend/src/random_bot.rs b/sea_battle_backend/src/random_bot.rs index 9b000e3..5d2e94e 100644 --- a/sea_battle_backend/src/random_bot.rs +++ b/sea_battle_backend/src/random_bot.rs @@ -28,6 +28,8 @@ impl Player for RandomBot { self.uuid } + fn set_other_player_name(&self, _name: &str) {} + fn query_boats_layout(&self, rules: &GameRules) { match BoatsLayout::gen_random_for_rules(rules) { Ok(layout) => self.game.do_send(SetBoatsLayout(self.uuid, layout)),