Ready to implement boats layout check
This commit is contained in:
parent
007fe3b773
commit
d3d5feda4f
@ -6,11 +6,21 @@ use tokio_tungstenite::tungstenite::Message;
|
||||
use crate::data::{BoatsLayout, GameRules};
|
||||
use crate::human_player_ws::{ClientMessage, ServerMessage};
|
||||
|
||||
pub async fn run_client(server: &str, rules: &GameRules) -> Result<(), Box<dyn Error>> {
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum ClientEndResult {
|
||||
Finished,
|
||||
InvalidLayout,
|
||||
}
|
||||
|
||||
pub async fn run_client(
|
||||
server: &str,
|
||||
requested_rules: &GameRules,
|
||||
layout: BoatsLayout,
|
||||
) -> Result<ClientEndResult, Box<dyn Error>> {
|
||||
let url = format!(
|
||||
"{}/play/bot?{}",
|
||||
server.replace("http", "ws"),
|
||||
serde_urlencoded::to_string(rules).unwrap()
|
||||
serde_urlencoded::to_string(requested_rules).unwrap()
|
||||
);
|
||||
log::debug!("Connecting to {}...", url);
|
||||
let (mut socket, _) = match tokio_tungstenite::connect_async(url).await {
|
||||
@ -54,11 +64,13 @@ pub async fn run_client(server: &str, rules: &GameRules) -> Result<(), Box<dyn E
|
||||
match message {
|
||||
ServerMessage::WaitingForAnotherPlayer => log::debug!("Waiting for other player..."),
|
||||
ServerMessage::QueryBoatsLayout { rules } => {
|
||||
assert_eq!(&rules, requested_rules);
|
||||
log::debug!("Server requested boats layout");
|
||||
let layout = BoatsLayout::gen_random_for_rules(&rules)?;
|
||||
socket
|
||||
.send(Message::Text(serde_json::to_string(
|
||||
&ClientMessage::BoatsLayout { layout },
|
||||
&ClientMessage::BoatsLayout {
|
||||
layout: layout.clone(),
|
||||
},
|
||||
)?))
|
||||
.await?;
|
||||
}
|
||||
@ -103,8 +115,12 @@ pub async fn run_client(server: &str, rules: &GameRules) -> Result<(), Box<dyn E
|
||||
log::debug!("Our game:\n{}\n", your_map.get_map());
|
||||
break;
|
||||
}
|
||||
ServerMessage::RejectedBoatsLayout { errors } => {
|
||||
log::warn!("Rejected boat layout: {:?}", errors);
|
||||
return Ok(ClientEndResult::InvalidLayout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(ClientEndResult::Finished)
|
||||
}
|
||||
|
@ -272,6 +272,12 @@ impl BoatsLayout {
|
||||
pub fn number_of_boats(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// Check for layout invalid configuration
|
||||
pub fn layouts_errors(&self, _rules: &GameRules) -> Vec<&'static str> {
|
||||
//TODO : implement
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -4,13 +4,13 @@ use rand::RngCore;
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct CurrentGameStatus {
|
||||
pub rules: GameRules,
|
||||
// TODO
|
||||
//TODO
|
||||
}
|
||||
|
||||
impl CurrentGameStatus {
|
||||
/// Check if user can fire at a given location
|
||||
pub fn can_fire_at_location(&self, _location: Coordinates) -> bool {
|
||||
// TODO
|
||||
//TODO
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::consts::*;
|
||||
use crate::data::{BotType, PlayConfiguration};
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||
pub struct GameRules {
|
||||
pub map_width: usize,
|
||||
pub map_height: usize,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::consts::*;
|
||||
|
||||
/// Specifies the kind of boat to use
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum BotType {
|
||||
Random,
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ pub trait Player {
|
||||
|
||||
fn query_boats_layout(&self, rules: &GameRules);
|
||||
|
||||
fn rejected_boats_layout(&self, errors: Vec<&'static str>);
|
||||
|
||||
fn notify_other_player_ready(&self);
|
||||
|
||||
fn notify_game_starting(&self);
|
||||
@ -205,6 +207,15 @@ impl Handler<SetBoatsLayout> for Game {
|
||||
}
|
||||
|
||||
let player_index = self.player_id_by_uuid(msg.0);
|
||||
|
||||
let errors = msg.1.layouts_errors(&self.rules);
|
||||
if !errors.is_empty() {
|
||||
log::error!("Got invalid boats layou!");
|
||||
self.players[player_index].rejected_boats_layout(errors);
|
||||
self.players[player_index].query_boats_layout(&self.rules);
|
||||
return;
|
||||
}
|
||||
|
||||
log::debug!("Got boat disposition for player {}", player_index);
|
||||
match player_index {
|
||||
0 => self.map_0 = Some(GameMap::new(self.rules.clone(), msg.1)),
|
||||
|
@ -27,6 +27,12 @@ impl Player for HumanPlayer {
|
||||
});
|
||||
}
|
||||
|
||||
fn rejected_boats_layout(&self, errors: Vec<&'static str>) {
|
||||
self.player.do_send(ServerMessage::RejectedBoatsLayout {
|
||||
errors: errors.iter().map(|s| s.to_string()).collect(),
|
||||
});
|
||||
}
|
||||
|
||||
fn notify_other_player_ready(&self) {
|
||||
self.player.do_send(ServerMessage::OtherPlayerReady);
|
||||
}
|
||||
@ -80,7 +86,6 @@ impl HumanPlayer {
|
||||
// TODO : do something
|
||||
}
|
||||
ClientMessage::BoatsLayout { layout } => {
|
||||
// TODO : check boat layout validity
|
||||
self.game.do_send(SetBoatsLayout(self.uuid, layout))
|
||||
}
|
||||
ClientMessage::Fire { location } => self.game.do_send(Fire(self.uuid, location)),
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use actix::{Actor, Handler, StreamHandler};
|
||||
use actix::prelude::*;
|
||||
use actix::{Actor, Handler, StreamHandler};
|
||||
use actix_web_actors::ws;
|
||||
use actix_web_actors::ws::{CloseCode, CloseReason, Message, ProtocolError, WebsocketContext};
|
||||
use uuid::Uuid;
|
||||
@ -44,6 +44,9 @@ pub enum ServerMessage {
|
||||
QueryBoatsLayout {
|
||||
rules: GameRules,
|
||||
},
|
||||
RejectedBoatsLayout {
|
||||
errors: Vec<String>,
|
||||
},
|
||||
WaitingForOtherPlayerConfiguration,
|
||||
OtherPlayerReady,
|
||||
GameStarting,
|
||||
@ -87,7 +90,6 @@ impl Default for HumanPlayerWS {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl HumanPlayerWS {
|
||||
/// helper method that sends ping to client every second.
|
||||
///
|
||||
|
@ -39,6 +39,10 @@ impl Player for RandomBot {
|
||||
}
|
||||
}
|
||||
|
||||
fn rejected_boats_layout(&self, _errors: Vec<&'static str>) {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn notify_other_player_ready(&self) {}
|
||||
|
||||
fn notify_game_starting(&self) {}
|
||||
|
@ -2,7 +2,8 @@ use tokio::task;
|
||||
|
||||
use crate::args::Args;
|
||||
use crate::bot_client;
|
||||
use crate::data::GameRules;
|
||||
use crate::bot_client::ClientEndResult;
|
||||
use crate::data::{BoatsLayout, GameRules};
|
||||
use crate::server::start_server;
|
||||
use crate::test::network_utils::wait_for_port;
|
||||
use crate::test::TestPort;
|
||||
@ -11,9 +12,11 @@ use crate::test::TestPort;
|
||||
async fn invalid_port() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
let rules = GameRules::random_players_rules();
|
||||
bot_client::run_client(
|
||||
&TestPort::ClientInvalidPort.as_url(),
|
||||
&GameRules::random_players_rules(),
|
||||
&rules,
|
||||
BoatsLayout::gen_random_for_rules(&rules).unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
@ -32,7 +35,11 @@ async fn invalid_rules() {
|
||||
task::spawn_local(start_server(Args::for_test(TestPort::ClientInvalidRules)));
|
||||
wait_for_port(TestPort::ClientInvalidRules.port()).await;
|
||||
|
||||
bot_client::run_client(&TestPort::ClientInvalidRules.as_url(), &rules)
|
||||
bot_client::run_client(
|
||||
&TestPort::ClientInvalidRules.as_url(),
|
||||
&rules,
|
||||
BoatsLayout::gen_random_for_rules(&GameRules::random_players_rules()).unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
})
|
||||
@ -50,9 +57,14 @@ async fn full_game() {
|
||||
task::spawn_local(start_server(Args::for_test(TestPort::FullGame)));
|
||||
wait_for_port(TestPort::FullGame.port()).await;
|
||||
|
||||
bot_client::run_client(&TestPort::FullGame.as_url(), &rules)
|
||||
let res = bot_client::run_client(
|
||||
&TestPort::FullGame.as_url(),
|
||||
&rules,
|
||||
BoatsLayout::gen_random_for_rules(&rules).unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res, ClientEndResult::Finished);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@ -71,9 +83,15 @@ async fn full_game_no_touching_boats() {
|
||||
)));
|
||||
wait_for_port(TestPort::FullGameTouchingBoats.port()).await;
|
||||
|
||||
bot_client::run_client(&TestPort::FullGameTouchingBoats.as_url(), &rules)
|
||||
let res = bot_client::run_client(
|
||||
&TestPort::FullGameTouchingBoats.as_url(),
|
||||
&rules,
|
||||
BoatsLayout::gen_random_for_rules(&rules).unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(res, ClientEndResult::Finished);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user