Players get live game status updates

This commit is contained in:
Pierre HUBERT 2022-09-15 20:13:06 +02:00
parent 8fac31e97b
commit a6040fe89c
8 changed files with 61 additions and 10 deletions

View File

@ -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),
} }
} }

View File

@ -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()));

View File

@ -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

View File

@ -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(),

View File

@ -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),
} }
} }
} }

View File

@ -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(),

View File

@ -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,
}, },

View File

@ -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)),