Players get live game status updates
This commit is contained in:
		@@ -34,7 +34,7 @@ pub async fn run_client(
 | 
				
			|||||||
    while let Some(chunk) = socket.next().await {
 | 
					    while let Some(chunk) = socket.next().await {
 | 
				
			||||||
        let message = match chunk? {
 | 
					        let message = match chunk? {
 | 
				
			||||||
            Message::Text(message) => {
 | 
					            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)?;
 | 
					                let msg: ServerMessage = serde_json::from_str(&message)?;
 | 
				
			||||||
                msg
 | 
					                msg
 | 
				
			||||||
@@ -79,8 +79,13 @@ pub async fn run_client(
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            ServerMessage::OtherPlayerReady => log::debug!("Other player is ready!"),
 | 
					            ServerMessage::OtherPlayerReady => log::debug!("Other player is ready!"),
 | 
				
			||||||
            ServerMessage::GameStarting => log::debug!("The game is starting..."),
 | 
					            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 } => {
 | 
					            ServerMessage::RequestFire { status } => {
 | 
				
			||||||
 | 
					                assert_eq!(status.opponent_map.boats.number_of_boats(), 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let location = status.find_valid_random_fire_location();
 | 
					                let location = status.find_valid_random_fire_location();
 | 
				
			||||||
                log::debug!("Will fire at {:?}", location);
 | 
					                log::debug!("Will fire at {:?}", location);
 | 
				
			||||||
                socket
 | 
					                socket
 | 
				
			||||||
@@ -119,6 +124,7 @@ pub async fn run_client(
 | 
				
			|||||||
                log::warn!("Rejected boat layout: {:?}", errors);
 | 
					                log::warn!("Rejected boat layout: {:?}", errors);
 | 
				
			||||||
                return Ok(ClientEndResult::InvalidBoatsLayout);
 | 
					                return Ok(ClientEndResult::InvalidBoatsLayout);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            ServerMessage::SetOpponentName { name } => log::debug!("Opponent name: {}", name),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -151,6 +151,11 @@ impl BoatPosition {
 | 
				
			|||||||
pub struct BoatsLayout(Vec<BoatPosition>);
 | 
					pub struct BoatsLayout(Vec<BoatPosition>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl BoatsLayout {
 | 
					impl BoatsLayout {
 | 
				
			||||||
 | 
					    /// Generate a new invalid (empty) boats layout
 | 
				
			||||||
 | 
					    pub fn new_invalid() -> Self {
 | 
				
			||||||
 | 
					        Self(vec![])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Generate random boats layout for given game rules
 | 
					    /// Generate random boats layout for given game rules
 | 
				
			||||||
    pub fn gen_random_for_rules(rules: &GameRules) -> std::io::Result<Self> {
 | 
					    pub fn gen_random_for_rules(rules: &GameRules) -> std::io::Result<Self> {
 | 
				
			||||||
        let mut boats = Self(Vec::with_capacity(rules.boats_list().len()));
 | 
					        let mut boats = Self(Vec::with_capacity(rules.boats_list().len()));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,27 @@
 | 
				
			|||||||
use crate::data::{Coordinates, GameRules};
 | 
					 | 
				
			||||||
use rand::RngCore;
 | 
					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<Coordinates>,
 | 
				
			||||||
 | 
					    pub failed_strikes: Vec<Coordinates>,
 | 
				
			||||||
 | 
					    pub sunk_boats: Vec<BoatPosition>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
pub struct CurrentGameStatus {
 | 
					pub struct CurrentGameStatus {
 | 
				
			||||||
    pub rules: GameRules,
 | 
					    pub rules: GameRules,
 | 
				
			||||||
    //TODO
 | 
					    pub your_map: CurrentGameMapStatus,
 | 
				
			||||||
 | 
					    pub opponent_map: CurrentGameMapStatus,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl CurrentGameStatus {
 | 
					impl CurrentGameStatus {
 | 
				
			||||||
    /// Check if user can fire at a given location
 | 
					    /// Check if opponent can fire at a given location
 | 
				
			||||||
    pub fn can_fire_at_location(&self, _location: Coordinates) -> bool {
 | 
					    pub fn can_fire_at_location(&self, location: Coordinates) -> bool {
 | 
				
			||||||
        //TODO
 | 
					        !self.opponent_map.successful_strikes.contains(&location)
 | 
				
			||||||
        true
 | 
					            && !self.opponent_map.failed_strikes.contains(&location)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Find valid random fire location. Loop until one is found
 | 
					    /// Find valid random fire location. Loop until one is found
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
use crate::data::boats_layout::{BoatsLayout, Coordinates};
 | 
					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)]
 | 
					#[derive(Debug, Copy, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
pub enum FireResult {
 | 
					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 {
 | 
					    pub fn final_map(&self) -> EndGameMap {
 | 
				
			||||||
        EndGameMap {
 | 
					        EndGameMap {
 | 
				
			||||||
            boats: self.boats_config.clone(),
 | 
					            boats: self.boats_config.clone(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,8 @@ pub trait Player {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    fn get_uid(&self) -> Uuid;
 | 
					    fn get_uid(&self) -> Uuid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn set_other_player_name(&self, name: &str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn query_boats_layout(&self, rules: &GameRules);
 | 
					    fn query_boats_layout(&self, rules: &GameRules);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn rejected_boats_layout(&self, errors: Vec<&'static str>);
 | 
					    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
 | 
					    /// Once the two player has been registered, the game may start
 | 
				
			||||||
    fn query_boats_disposition(&mut self) {
 | 
					    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");
 | 
					        log::debug!("Query boats disposition");
 | 
				
			||||||
        assert_eq!(self.status, GameStatus::Created);
 | 
					        assert_eq!(self.status, GameStatus::Created);
 | 
				
			||||||
        self.status = GameStatus::WaitingForBoatsDisposition;
 | 
					        self.status = GameStatus::WaitingForBoatsDisposition;
 | 
				
			||||||
@@ -160,9 +165,11 @@ impl Game {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Get current game status for a specific player
 | 
					    /// 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 {
 | 
					        CurrentGameStatus {
 | 
				
			||||||
            rules: self.rules.clone(),
 | 
					            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),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,12 @@ impl Player for HumanPlayer {
 | 
				
			|||||||
        self.uuid
 | 
					        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) {
 | 
					    fn query_boats_layout(&self, rules: &GameRules) {
 | 
				
			||||||
        self.player.do_send(ServerMessage::QueryBoatsLayout {
 | 
					        self.player.do_send(ServerMessage::QueryBoatsLayout {
 | 
				
			||||||
            rules: rules.clone(),
 | 
					            rules: rules.clone(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,6 +41,9 @@ pub enum ClientMessage {
 | 
				
			|||||||
#[serde(tag = "type")]
 | 
					#[serde(tag = "type")]
 | 
				
			||||||
pub enum ServerMessage {
 | 
					pub enum ServerMessage {
 | 
				
			||||||
    WaitingForAnotherPlayer,
 | 
					    WaitingForAnotherPlayer,
 | 
				
			||||||
 | 
					    SetOpponentName {
 | 
				
			||||||
 | 
					        name: String,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    QueryBoatsLayout {
 | 
					    QueryBoatsLayout {
 | 
				
			||||||
        rules: GameRules,
 | 
					        rules: GameRules,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,8 @@ impl Player for RandomBot {
 | 
				
			|||||||
        self.uuid
 | 
					        self.uuid
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn set_other_player_name(&self, _name: &str) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn query_boats_layout(&self, rules: &GameRules) {
 | 
					    fn query_boats_layout(&self, rules: &GameRules) {
 | 
				
			||||||
        match BoatsLayout::gen_random_for_rules(rules) {
 | 
					        match BoatsLayout::gen_random_for_rules(rules) {
 | 
				
			||||||
            Ok(layout) => self.game.do_send(SetBoatsLayout(self.uuid, layout)),
 | 
					            Ok(layout) => self.game.do_send(SetBoatsLayout(self.uuid, layout)),
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user