This commit is contained in:
Pierre HUBERT 2022-09-14 18:30:33 +02:00
parent 54f7566016
commit a0eae4c93d
7 changed files with 107 additions and 8 deletions

View File

@ -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?;
}
}
}

View 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;
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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