Can fire
This commit is contained in:
		@@ -67,6 +67,16 @@ pub async fn run_client(server: &str, rules: &GameRules) -> Result<(), Box<dyn E
 | 
			
		||||
            }
 | 
			
		||||
            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::RequestFire { status } => {
 | 
			
		||||
                let location = status.find_valid_random_fire_location();
 | 
			
		||||
                log::debug!("Will fire at {:?}", location);
 | 
			
		||||
                socket
 | 
			
		||||
                    .send(Message::Text(serde_json::to_string(
 | 
			
		||||
                        &ClientMessage::Fire { location },
 | 
			
		||||
                    )?))
 | 
			
		||||
                    .await?;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								src/data/current_game_status.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/data/current_game_status.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
use crate::data::{Coordinates, GameRules};
 | 
			
		||||
use rand::RngCore;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
			
		||||
pub struct CurrentGameStatus {
 | 
			
		||||
    pub rules: GameRules,
 | 
			
		||||
    // TODO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CurrentGameStatus {
 | 
			
		||||
    /// Check if user can fire at a given location
 | 
			
		||||
    pub fn can_fire_at_location(&self, _location: Coordinates) -> bool {
 | 
			
		||||
        // TODO
 | 
			
		||||
        true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Find valid random fire location. Loop until one is found
 | 
			
		||||
    pub fn find_valid_random_fire_location(&self) -> Coordinates {
 | 
			
		||||
        let mut rng = rand::thread_rng();
 | 
			
		||||
        loop {
 | 
			
		||||
            let coordinates = Coordinates::new(
 | 
			
		||||
                (rng.next_u32() % self.rules.map_width as u32) as i32,
 | 
			
		||||
                (rng.next_u32() % self.rules.map_height as u32) as i32,
 | 
			
		||||
            );
 | 
			
		||||
            if coordinates.is_valid(&self.rules) && self.can_fire_at_location(coordinates) {
 | 
			
		||||
                return coordinates;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,9 +1,11 @@
 | 
			
		||||
pub use boats_layout::*;
 | 
			
		||||
pub use current_game_status::*;
 | 
			
		||||
pub use game_map::*;
 | 
			
		||||
pub use game_rules::*;
 | 
			
		||||
pub use play_config::*;
 | 
			
		||||
 | 
			
		||||
mod boats_layout;
 | 
			
		||||
mod current_game_status;
 | 
			
		||||
mod game_map;
 | 
			
		||||
mod game_rules;
 | 
			
		||||
mod play_config;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								src/game.rs
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								src/game.rs
									
									
									
									
									
								
							@@ -4,7 +4,7 @@ use actix::prelude::*;
 | 
			
		||||
use actix::{Actor, Context, Handler};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
use crate::data::{BoatsLayout, GameMap, GameRules};
 | 
			
		||||
use crate::data::*;
 | 
			
		||||
 | 
			
		||||
pub trait Player {
 | 
			
		||||
    fn get_name(&self) -> &str;
 | 
			
		||||
@@ -16,6 +16,10 @@ pub trait Player {
 | 
			
		||||
    fn notify_other_player_ready(&self);
 | 
			
		||||
 | 
			
		||||
    fn notify_game_starting(&self);
 | 
			
		||||
 | 
			
		||||
    fn request_fire(&self, status: CurrentGameStatus);
 | 
			
		||||
 | 
			
		||||
    fn other_player_must_fire(&self, status: CurrentGameStatus);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn opponent(index: usize) -> usize {
 | 
			
		||||
@@ -40,6 +44,7 @@ pub struct Game {
 | 
			
		||||
    status: GameStatus,
 | 
			
		||||
    map_0: Option<GameMap>,
 | 
			
		||||
    map_1: Option<GameMap>,
 | 
			
		||||
    turn: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Game {
 | 
			
		||||
@@ -50,6 +55,7 @@ impl Game {
 | 
			
		||||
            status: GameStatus::Created,
 | 
			
		||||
            map_0: None,
 | 
			
		||||
            map_1: None,
 | 
			
		||||
            turn: 0,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -75,7 +81,22 @@ impl Game {
 | 
			
		||||
    /// Start fires exchange
 | 
			
		||||
    fn start_fire_exchanges(&mut self) {
 | 
			
		||||
        self.status = GameStatus::Started;
 | 
			
		||||
        log::debug!("Start fire exchanges");
 | 
			
		||||
        log::debug!(
 | 
			
		||||
            "Start fire exchanges. Player {}#{} goes first",
 | 
			
		||||
            self.players[self.turn].get_name(),
 | 
			
		||||
            self.turn
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        self.players[self.turn].request_fire(self.get_game_status_for_player(self.turn));
 | 
			
		||||
        self.players[opponent(self.turn)]
 | 
			
		||||
            .request_fire(self.get_game_status_for_player(opponent(self.turn)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get current game status for a specific player
 | 
			
		||||
    fn get_game_status_for_player(&self, _id: usize) -> CurrentGameStatus {
 | 
			
		||||
        CurrentGameStatus {
 | 
			
		||||
            rules: self.rules.clone(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -113,7 +134,11 @@ impl Handler<SetBoatsLayout> for Game {
 | 
			
		||||
 | 
			
		||||
    /// Receive game configuration of a player
 | 
			
		||||
    fn handle(&mut self, msg: SetBoatsLayout, _ctx: &mut Self::Context) -> Self::Result {
 | 
			
		||||
        assert_eq!(self.status, GameStatus::WaitingForBoatsDisposition);
 | 
			
		||||
        if self.status != GameStatus::WaitingForBoatsDisposition {
 | 
			
		||||
            log::error!("Player attempted to set boat configuration on invalid step!");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let player_index = self.player_id_by_uuid(msg.0);
 | 
			
		||||
        log::debug!("Got boat disposition for player {}", player_index);
 | 
			
		||||
        match player_index {
 | 
			
		||||
@@ -130,3 +155,15 @@ impl Handler<SetBoatsLayout> for Game {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Message, Debug)]
 | 
			
		||||
#[rtype(result = "()")]
 | 
			
		||||
pub struct Fire(pub Uuid, pub Coordinates);
 | 
			
		||||
 | 
			
		||||
impl Handler<Fire> for Game {
 | 
			
		||||
    type Result = ();
 | 
			
		||||
 | 
			
		||||
    fn handle(&mut self, msg: Fire, _ctx: &mut Self::Context) -> Self::Result {
 | 
			
		||||
        log::debug!("FIRE ===> {:?}", msg);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
use actix::Addr;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
use crate::data::GameRules;
 | 
			
		||||
use crate::game::{Game, Player, SetBoatsLayout};
 | 
			
		||||
use crate::data::{CurrentGameStatus, GameRules};
 | 
			
		||||
use crate::game::{Fire, Game, Player, SetBoatsLayout};
 | 
			
		||||
use crate::human_player_ws::{ClientMessage, HumanPlayerWS, ServerMessage};
 | 
			
		||||
 | 
			
		||||
pub struct HumanPlayer {
 | 
			
		||||
@@ -34,6 +34,15 @@ impl Player for HumanPlayer {
 | 
			
		||||
    fn notify_game_starting(&self) {
 | 
			
		||||
        self.player.do_send(ServerMessage::GameStarting);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn request_fire(&self, status: CurrentGameStatus) {
 | 
			
		||||
        self.player.do_send(ServerMessage::RequestFire { status });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn other_player_must_fire(&self, status: CurrentGameStatus) {
 | 
			
		||||
        self.player
 | 
			
		||||
            .do_send(ServerMessage::OtherPlayerMustFire { status });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl HumanPlayer {
 | 
			
		||||
@@ -45,6 +54,7 @@ impl HumanPlayer {
 | 
			
		||||
            ClientMessage::BoatsLayout { layout } => {
 | 
			
		||||
                self.game.do_send(SetBoatsLayout(self.uuid, layout))
 | 
			
		||||
            }
 | 
			
		||||
            ClientMessage::Fire { location } => self.game.do_send(Fire(self.uuid, location)),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ use actix_web_actors::ws;
 | 
			
		||||
use actix_web_actors::ws::{CloseCode, CloseReason, Message, ProtocolError, WebsocketContext};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
use crate::data::{BoatsLayout, BotType, GameRules};
 | 
			
		||||
use crate::data::{BoatsLayout, BotType, Coordinates, CurrentGameStatus, GameRules};
 | 
			
		||||
use crate::game::{AddPlayer, Game};
 | 
			
		||||
use crate::human_player::HumanPlayer;
 | 
			
		||||
use crate::random_bot::RandomBot;
 | 
			
		||||
@@ -24,6 +24,7 @@ pub enum StartMode {
 | 
			
		||||
pub enum ClientMessage {
 | 
			
		||||
    StopGame,
 | 
			
		||||
    BoatsLayout { layout: BoatsLayout },
 | 
			
		||||
    Fire { location: Coordinates },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Message)]
 | 
			
		||||
@@ -36,6 +37,8 @@ pub enum ServerMessage {
 | 
			
		||||
    WaitingForOtherPlayerConfiguration,
 | 
			
		||||
    OtherPlayerReady,
 | 
			
		||||
    GameStarting,
 | 
			
		||||
    OtherPlayerMustFire { status: CurrentGameStatus },
 | 
			
		||||
    RequestFire { status: CurrentGameStatus },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Default)]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
use actix::Addr;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
use crate::data::{BoatsLayout, GameRules};
 | 
			
		||||
use crate::game::{Game, Player, SetBoatsLayout};
 | 
			
		||||
use crate::data::{BoatsLayout, CurrentGameStatus, GameRules};
 | 
			
		||||
use crate::game::{Fire, Game, Player, SetBoatsLayout};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct RandomBot {
 | 
			
		||||
@@ -42,4 +42,11 @@ impl Player for RandomBot {
 | 
			
		||||
    fn notify_other_player_ready(&self) {}
 | 
			
		||||
 | 
			
		||||
    fn notify_game_starting(&self) {}
 | 
			
		||||
 | 
			
		||||
    fn request_fire(&self, status: CurrentGameStatus) {
 | 
			
		||||
        self.game
 | 
			
		||||
            .do_send(Fire(self.uuid, status.find_valid_random_fire_location()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn other_player_must_fire(&self, _status: CurrentGameStatus) {}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user