Add tests for no replay after hit rule
This commit is contained in:
parent
7cfd7a4899
commit
6832aebedb
@ -1,7 +1,7 @@
|
||||
use actix::Addr;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::data::{BoatsLayout, Coordinates, CurrentGameStatus, EndGameMap, FireResult, GameRules};
|
||||
use crate::data::{BoatsLayout, Coordinates, CurrentGameStatus, FireResult, GameRules};
|
||||
use crate::game::{Fire, Game, Player, RespondRequestRematch, SetBoatsLayout};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -64,9 +64,9 @@ impl Player for LinearBot {
|
||||
|
||||
fn other_player_strike_result(&self, _c: Coordinates, _res: FireResult) {}
|
||||
|
||||
fn lost_game(&self, _your_map: EndGameMap, _opponent_map: EndGameMap) {}
|
||||
fn lost_game(&self, _status: CurrentGameStatus) {}
|
||||
|
||||
fn won_game(&self, _your_map: EndGameMap, _opponent_map: EndGameMap) {}
|
||||
fn won_game(&self, _status: CurrentGameStatus) {}
|
||||
|
||||
fn opponent_requested_rematch(&self) {
|
||||
self.game.do_send(RespondRequestRematch(self.uuid, true));
|
||||
|
@ -1,7 +1,7 @@
|
||||
use actix::Addr;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::data::{BoatsLayout, Coordinates, CurrentGameStatus, EndGameMap, FireResult, GameRules};
|
||||
use crate::data::{BoatsLayout, Coordinates, CurrentGameStatus, FireResult, GameRules};
|
||||
use crate::game::{Fire, Game, Player, RespondRequestRematch, SetBoatsLayout};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -64,9 +64,9 @@ impl Player for RandomBot {
|
||||
|
||||
fn other_player_strike_result(&self, _c: Coordinates, _res: FireResult) {}
|
||||
|
||||
fn lost_game(&self, _your_map: EndGameMap, _opponent_map: EndGameMap) {}
|
||||
fn lost_game(&self, _status: CurrentGameStatus) {}
|
||||
|
||||
fn won_game(&self, _your_map: EndGameMap, _opponent_map: EndGameMap) {}
|
||||
fn won_game(&self, _status: CurrentGameStatus) {}
|
||||
|
||||
fn opponent_requested_rematch(&self) {
|
||||
self.game.do_send(RespondRequestRematch(self.uuid, true));
|
||||
|
@ -213,6 +213,42 @@ impl BoatsLayout {
|
||||
Ok(boats)
|
||||
}
|
||||
|
||||
/// Generate boats layout that put boats at the beginning of the map
|
||||
pub fn layout_for_boats_at_beginning_of_map(rules: &GameRules) -> std::io::Result<Self> {
|
||||
let mut boats = Self(Vec::with_capacity(rules.boats_list().len()));
|
||||
let mut list = rules.boats_list();
|
||||
list.sort();
|
||||
list.reverse();
|
||||
|
||||
for y in 0..rules.map_height {
|
||||
for x in 0..rules.map_width {
|
||||
if list.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
let position = BoatPosition {
|
||||
start: Coordinates::new(x as i32, y as i32),
|
||||
len: list[0],
|
||||
direction: BoatDirection::Right,
|
||||
};
|
||||
|
||||
if boats.is_acceptable_boat_position(&position, rules) {
|
||||
list.remove(0);
|
||||
boats.0.push(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !list.is_empty() {
|
||||
return Err(std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
"Un-usable game rules!",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(boats)
|
||||
}
|
||||
|
||||
fn is_acceptable_boat_position(&self, pos: &BoatPosition, rules: &GameRules) -> bool {
|
||||
// Check if boat coordinates are valid
|
||||
if pos.all_coordinates().iter().any(|c| !c.is_valid(rules)) {
|
||||
|
@ -16,6 +16,10 @@ impl CurrentGameMapStatus {
|
||||
pub fn did_fire_at_location(&self, c: Coordinates) -> bool {
|
||||
self.successful_strikes.contains(&c) || self.failed_strikes.contains(&c)
|
||||
}
|
||||
|
||||
pub fn number_of_fires(&self) -> usize {
|
||||
self.successful_strikes.len() + self.failed_strikes.len()
|
||||
}
|
||||
}
|
||||
|
||||
struct PrintableCurrentGameMapStatus(GameRules, CurrentGameMapStatus);
|
||||
@ -207,12 +211,20 @@ impl CurrentGameStatus {
|
||||
boats_size.first().cloned()
|
||||
}
|
||||
|
||||
pub fn get_your_map(&self) -> String {
|
||||
PrintableCurrentGameMapStatus(self.rules.clone(), self.your_map.clone()).get_map()
|
||||
}
|
||||
|
||||
pub fn get_opponent_map(&self) -> String {
|
||||
PrintableCurrentGameMapStatus(self.rules.clone(), self.opponent_map.clone()).get_map()
|
||||
}
|
||||
|
||||
pub fn print_your_map(&self) {
|
||||
PrintableCurrentGameMapStatus(self.rules.clone(), self.your_map.clone()).print_map()
|
||||
print!("{}", self.get_your_map());
|
||||
}
|
||||
|
||||
pub fn print_opponent_map(&self) {
|
||||
PrintableCurrentGameMapStatus(self.rules.clone(), self.opponent_map.clone()).print_map()
|
||||
print!("{}", self.get_opponent_map());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,22 +0,0 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use crate::data::{BoatsLayout, MapCellContent};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct EndGameMap {
|
||||
pub boats: BoatsLayout,
|
||||
pub grid: Vec<Vec<MapCellContent>>,
|
||||
}
|
||||
|
||||
impl EndGameMap {
|
||||
pub fn get_map(&self) -> String {
|
||||
let mut s = String::new();
|
||||
for row in &self.grid {
|
||||
for col in row {
|
||||
write!(&mut s, "{} ", col.letter()).unwrap();
|
||||
}
|
||||
s.push('\n');
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
use crate::data::boats_layout::{BoatsLayout, Coordinates};
|
||||
use crate::data::{
|
||||
BoatPosition, CurrentGameMapStatus, EndGameMap, GameRules, MapCellContent, PrintableMap,
|
||||
};
|
||||
use crate::data::*;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub enum FireResult {
|
||||
@ -110,19 +108,6 @@ impl GameMap {
|
||||
sunk_boats: self.sunk_boats.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn final_map(&self) -> EndGameMap {
|
||||
EndGameMap {
|
||||
boats: self.boats_config.clone(),
|
||||
grid: (0..self.rules.map_height)
|
||||
.map(|y| {
|
||||
(0..self.rules.map_width)
|
||||
.map(|x| self.get_cell_content(Coordinates::new(x as i32, y as i32)))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrintableMap for GameMap {
|
||||
|
@ -38,6 +38,11 @@ impl GameRules {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_player_continue_on_hit(mut self, c: bool) -> Self {
|
||||
self.player_continue_on_hit = c;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the list of boats for this configuration
|
||||
pub fn set_boats_list(&mut self, boats: &[usize]) {
|
||||
self.boats_str = boats
|
||||
|
@ -1,6 +1,5 @@
|
||||
pub use boats_layout::*;
|
||||
pub use current_game_status::*;
|
||||
pub use end_game_map::*;
|
||||
pub use game_map::*;
|
||||
pub use game_rules::*;
|
||||
pub use play_config::*;
|
||||
@ -8,7 +7,6 @@ pub use printable_map::*;
|
||||
|
||||
mod boats_layout;
|
||||
mod current_game_status;
|
||||
mod end_game_map;
|
||||
mod game_map;
|
||||
mod game_rules;
|
||||
mod play_config;
|
||||
|
@ -1,3 +1,6 @@
|
||||
use std::fmt::Write;
|
||||
use std::string::String;
|
||||
|
||||
use crate::data::Coordinates;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
@ -27,6 +30,12 @@ pub trait PrintableMap {
|
||||
fn map_cell_content(&self, c: Coordinates) -> MapCellContent;
|
||||
|
||||
fn print_map(&self) {
|
||||
print!("{}", self.get_map());
|
||||
}
|
||||
|
||||
fn get_map(&self) -> String {
|
||||
let mut out = String::with_capacity(100);
|
||||
|
||||
let mut y = 0;
|
||||
let mut x;
|
||||
loop {
|
||||
@ -38,11 +47,11 @@ pub trait PrintableMap {
|
||||
break;
|
||||
}
|
||||
|
||||
print!("{} ", content.letter());
|
||||
write!(out, "{} ", content.letter()).unwrap();
|
||||
x += 1;
|
||||
}
|
||||
|
||||
println!();
|
||||
out.push('\n');
|
||||
|
||||
// x == 0 <=> we reached the end of the map
|
||||
if x == 0 {
|
||||
@ -51,5 +60,7 @@ pub trait PrintableMap {
|
||||
|
||||
y += 1;
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
}
|
||||
|
@ -32,9 +32,9 @@ pub trait Player {
|
||||
|
||||
fn other_player_strike_result(&self, c: Coordinates, res: FireResult);
|
||||
|
||||
fn lost_game(&self, your_map: EndGameMap, opponent_map: EndGameMap);
|
||||
fn lost_game(&self, status: CurrentGameStatus);
|
||||
|
||||
fn won_game(&self, your_map: EndGameMap, opponent_map: EndGameMap);
|
||||
fn won_game(&self, status: CurrentGameStatus);
|
||||
|
||||
fn opponent_requested_rematch(&self);
|
||||
|
||||
@ -163,11 +163,9 @@ impl Game {
|
||||
{
|
||||
self.status = GameStatus::Finished;
|
||||
|
||||
let winner_map = self.player_map(self.turn).final_map();
|
||||
let looser_map = self.player_map(opponent(self.turn)).final_map();
|
||||
|
||||
self.players[self.turn].won_game(winner_map.clone(), looser_map.clone());
|
||||
self.players[opponent(self.turn)].lost_game(looser_map, winner_map);
|
||||
self.players[self.turn].won_game(self.get_game_status_for_player(self.turn));
|
||||
self.players[opponent(self.turn)]
|
||||
.lost_game(self.get_game_status_for_player(opponent(self.turn)));
|
||||
|
||||
return;
|
||||
}
|
||||
@ -215,7 +213,9 @@ impl Game {
|
||||
CurrentGameStatus {
|
||||
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),
|
||||
opponent_map: self
|
||||
.player_map(opponent(id))
|
||||
.current_map_status(self.status != GameStatus::Finished),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use actix::Addr;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::data::{Coordinates, CurrentGameStatus, EndGameMap, FireResult, GameRules};
|
||||
use crate::data::*;
|
||||
use crate::game::*;
|
||||
use crate::human_player_ws::{ClientMessage, HumanPlayerWS, ServerMessage};
|
||||
|
||||
@ -74,18 +74,12 @@ impl Player for HumanPlayer {
|
||||
});
|
||||
}
|
||||
|
||||
fn lost_game(&self, your_map: EndGameMap, opponent_map: EndGameMap) {
|
||||
self.player.do_send(ServerMessage::LostGame {
|
||||
your_map,
|
||||
opponent_map,
|
||||
});
|
||||
fn lost_game(&self, status: CurrentGameStatus) {
|
||||
self.player.do_send(ServerMessage::LostGame { status });
|
||||
}
|
||||
|
||||
fn won_game(&self, your_map: EndGameMap, opponent_map: EndGameMap) {
|
||||
self.player.do_send(ServerMessage::WonGame {
|
||||
your_map,
|
||||
opponent_map,
|
||||
});
|
||||
fn won_game(&self, status: CurrentGameStatus) {
|
||||
self.player.do_send(ServerMessage::WonGame { status });
|
||||
}
|
||||
|
||||
fn opponent_requested_rematch(&self) {
|
||||
|
@ -1,17 +1,15 @@
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crate::bots::linear_bot::LinearBot;
|
||||
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;
|
||||
|
||||
use crate::bots::linear_bot::LinearBot;
|
||||
use crate::bots::random_bot::RandomBot;
|
||||
use crate::data::{
|
||||
BoatsLayout, BotType, Coordinates, CurrentGameStatus, EndGameMap, FireResult, GameRules,
|
||||
};
|
||||
use crate::data::{BoatsLayout, BotType, Coordinates, CurrentGameStatus, FireResult, GameRules};
|
||||
use crate::game::{AddPlayer, Game};
|
||||
use crate::human_player::HumanPlayer;
|
||||
|
||||
@ -73,12 +71,10 @@ pub enum ServerMessage {
|
||||
result: FireResult,
|
||||
},
|
||||
LostGame {
|
||||
your_map: EndGameMap,
|
||||
opponent_map: EndGameMap,
|
||||
status: CurrentGameStatus,
|
||||
},
|
||||
WonGame {
|
||||
your_map: EndGameMap,
|
||||
opponent_map: EndGameMap,
|
||||
status: CurrentGameStatus,
|
||||
},
|
||||
OpponentRequestedRematch,
|
||||
OpponentAcceptedRematch,
|
||||
|
@ -160,13 +160,10 @@ impl BotClient {
|
||||
pos.human_print(),
|
||||
result
|
||||
),
|
||||
ServerMessage::LostGame {
|
||||
your_map,
|
||||
opponent_map,
|
||||
} => {
|
||||
ServerMessage::LostGame { status } => {
|
||||
log::debug!("We lost game :(");
|
||||
log::debug!("Other game:\n{}\n", opponent_map.get_map());
|
||||
log::debug!("Our game:\n{}\n", your_map.get_map());
|
||||
log::debug!("Opponent map:\n{}", status.get_opponent_map());
|
||||
log::debug!("Our map:\n{}\n", status.get_your_map());
|
||||
|
||||
if remaining_games > 0 {
|
||||
socket
|
||||
@ -178,13 +175,10 @@ impl BotClient {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ServerMessage::WonGame {
|
||||
your_map,
|
||||
opponent_map,
|
||||
} => {
|
||||
ServerMessage::WonGame { status } => {
|
||||
log::debug!("We won the game !!!!");
|
||||
log::debug!("Other game:\n{}\n", opponent_map.get_map());
|
||||
log::debug!("Our game:\n{}\n", your_map.get_map());
|
||||
log::debug!("Opponent map:\n{}\n", status.get_opponent_map());
|
||||
log::debug!("Our map:\n{}\n", status.get_your_map());
|
||||
|
||||
if remaining_games > 0 {
|
||||
socket
|
||||
|
@ -1,11 +1,12 @@
|
||||
use tokio::task;
|
||||
|
||||
use crate::args::Args;
|
||||
use crate::data::{BotType, Coordinates, GameRules};
|
||||
use crate::data::{BoatsLayout, BotType, Coordinates, GameRules};
|
||||
use crate::human_player_ws::ServerMessage;
|
||||
use crate::server::start_server;
|
||||
use crate::test::bot_client::ClientEndResult;
|
||||
use crate::test::network_utils::wait_for_port;
|
||||
use crate::test::play_utils::check_no_replay_on_hit;
|
||||
use crate::test::{bot_client, TestPort};
|
||||
|
||||
fn check_strikes_are_linear(msg: &ServerMessage) {
|
||||
@ -49,3 +50,95 @@ async fn full_game() {
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn full_game_no_replay_on_hit() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
let local_set = task::LocalSet::new();
|
||||
local_set
|
||||
.run_until(async move {
|
||||
task::spawn_local(start_server(Args::for_test(
|
||||
TestPort::LinearBotNoReplayOnHit,
|
||||
)));
|
||||
wait_for_port(TestPort::LinearBotNoReplayOnHit.port()).await;
|
||||
|
||||
let res = bot_client::BotClient::new(TestPort::LinearBotNoReplayOnHit.as_url())
|
||||
.with_rules(
|
||||
GameRules::random_players_rules()
|
||||
.with_player_continue_on_hit(false)
|
||||
.with_bot_type(BotType::Linear),
|
||||
)
|
||||
.with_server_msg_callback(check_no_replay_on_hit)
|
||||
.run_client()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res, ClientEndResult::Finished);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn full_game_no_replay_on_hit_two() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
let local_set = task::LocalSet::new();
|
||||
local_set
|
||||
.run_until(async move {
|
||||
task::spawn_local(start_server(Args::for_test(
|
||||
TestPort::LinearBotNoReplayOnHit,
|
||||
)));
|
||||
wait_for_port(TestPort::LinearBotNoReplayOnHit.port()).await;
|
||||
|
||||
let rules = GameRules::random_players_rules()
|
||||
.with_player_continue_on_hit(false)
|
||||
.with_bot_type(BotType::Linear);
|
||||
let layout = BoatsLayout::layout_for_boats_at_beginning_of_map(&rules).unwrap();
|
||||
let res = bot_client::BotClient::new(TestPort::LinearBotNoReplayOnHit.as_url())
|
||||
.with_rules(rules.clone())
|
||||
.with_layout(layout)
|
||||
.with_server_msg_callback(check_no_replay_on_hit)
|
||||
.run_client()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res, ClientEndResult::Finished);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn full_game_with_replay_on_hit() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
let local_set = task::LocalSet::new();
|
||||
local_set
|
||||
.run_until(async move {
|
||||
task::spawn_local(start_server(Args::for_test(
|
||||
TestPort::LinearBotNoReplayOnHit,
|
||||
)));
|
||||
wait_for_port(TestPort::LinearBotNoReplayOnHit.port()).await;
|
||||
|
||||
let rules = GameRules::random_players_rules()
|
||||
.with_player_continue_on_hit(true)
|
||||
.with_bot_type(BotType::Linear);
|
||||
let layout = BoatsLayout::layout_for_boats_at_beginning_of_map(&rules).unwrap();
|
||||
let res = bot_client::BotClient::new(TestPort::LinearBotNoReplayOnHit.as_url())
|
||||
.with_rules(rules.clone())
|
||||
.with_layout(layout)
|
||||
.with_server_msg_callback(|msg| {
|
||||
if let ServerMessage::LostGame { status } | ServerMessage::WonGame { status } =
|
||||
msg
|
||||
{
|
||||
assert!(
|
||||
status.opponent_map.number_of_fires()
|
||||
< status.your_map.number_of_fires()
|
||||
);
|
||||
}
|
||||
})
|
||||
.run_client()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res, ClientEndResult::Finished);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
@ -6,13 +6,14 @@ use crate::server::start_server;
|
||||
use crate::test::bot_client;
|
||||
use crate::test::bot_client::ClientEndResult;
|
||||
use crate::test::network_utils::wait_for_port;
|
||||
use crate::test::play_utils::check_no_replay_on_hit;
|
||||
use crate::test::TestPort;
|
||||
|
||||
#[tokio::test]
|
||||
async fn invalid_port() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
bot_client::BotClient::new(TestPort::ClientInvalidPort.as_url())
|
||||
bot_client::BotClient::new(TestPort::RandomBotClientInvalidPort.as_url())
|
||||
.run_client()
|
||||
.await
|
||||
.unwrap_err();
|
||||
@ -28,10 +29,12 @@ async fn invalid_rules() {
|
||||
let mut rules = GameRules::random_players_rules();
|
||||
rules.map_width = 0;
|
||||
|
||||
task::spawn_local(start_server(Args::for_test(TestPort::ClientInvalidRules)));
|
||||
wait_for_port(TestPort::ClientInvalidRules.port()).await;
|
||||
task::spawn_local(start_server(Args::for_test(
|
||||
TestPort::RandomBotClientInvalidRules,
|
||||
)));
|
||||
wait_for_port(TestPort::RandomBotClientInvalidRules.port()).await;
|
||||
|
||||
bot_client::BotClient::new(TestPort::ClientInvalidRules.as_url())
|
||||
bot_client::BotClient::new(TestPort::RandomBotClientInvalidRules.as_url())
|
||||
.with_rules(rules.clone())
|
||||
.with_layout(
|
||||
BoatsLayout::gen_random_for_rules(&GameRules::random_players_rules()).unwrap(),
|
||||
@ -50,10 +53,10 @@ async fn full_game() {
|
||||
let local_set = task::LocalSet::new();
|
||||
local_set
|
||||
.run_until(async move {
|
||||
task::spawn_local(start_server(Args::for_test(TestPort::FullGame)));
|
||||
wait_for_port(TestPort::FullGame.port()).await;
|
||||
task::spawn_local(start_server(Args::for_test(TestPort::RandomBotFullGame)));
|
||||
wait_for_port(TestPort::RandomBotFullGame.port()).await;
|
||||
|
||||
let res = bot_client::BotClient::new(TestPort::FullGame.as_url())
|
||||
let res = bot_client::BotClient::new(TestPort::RandomBotFullGame.as_url())
|
||||
.run_client()
|
||||
.await
|
||||
.unwrap();
|
||||
@ -72,11 +75,12 @@ async fn full_game_no_touching_boats() {
|
||||
let mut rules = GameRules::random_players_rules();
|
||||
rules.boats_can_touch = false;
|
||||
task::spawn_local(start_server(Args::for_test(
|
||||
TestPort::FullGameNoTouchingBoats,
|
||||
TestPort::RandomBotFullGameNoTouchingBoats,
|
||||
)));
|
||||
wait_for_port(TestPort::FullGameNoTouchingBoats.port()).await;
|
||||
wait_for_port(TestPort::RandomBotFullGameNoTouchingBoats.port()).await;
|
||||
|
||||
let res = bot_client::BotClient::new(TestPort::FullGameNoTouchingBoats.as_url())
|
||||
let res =
|
||||
bot_client::BotClient::new(TestPort::RandomBotFullGameNoTouchingBoats.as_url())
|
||||
.with_rules(rules)
|
||||
.run_client()
|
||||
.await
|
||||
@ -97,16 +101,17 @@ async fn invalid_boats_layout_number_of_boats() {
|
||||
let mut rules = GameRules::random_players_rules();
|
||||
rules.boats_can_touch = false;
|
||||
task::spawn_local(start_server(Args::for_test(
|
||||
TestPort::InvalidBoatsLayoutNumberOfBoats,
|
||||
TestPort::RandomBotInvalidBoatsLayoutNumberOfBoats,
|
||||
)));
|
||||
wait_for_port(TestPort::InvalidBoatsLayoutNumberOfBoats.port()).await;
|
||||
wait_for_port(TestPort::RandomBotInvalidBoatsLayoutNumberOfBoats.port()).await;
|
||||
|
||||
let mut rules_modified = rules.clone();
|
||||
rules_modified.pop_boat();
|
||||
let layout = BoatsLayout::gen_random_for_rules(&rules_modified).unwrap();
|
||||
|
||||
let res =
|
||||
bot_client::BotClient::new(&TestPort::InvalidBoatsLayoutNumberOfBoats.as_url())
|
||||
let res = bot_client::BotClient::new(
|
||||
&TestPort::RandomBotInvalidBoatsLayoutNumberOfBoats.as_url(),
|
||||
)
|
||||
.with_rules(rules)
|
||||
.with_layout(layout)
|
||||
.run_client()
|
||||
@ -128,16 +133,18 @@ async fn invalid_boats_layout_len_of_a_boat() {
|
||||
let mut rules = GameRules::random_players_rules();
|
||||
rules.boats_can_touch = false;
|
||||
task::spawn_local(start_server(Args::for_test(
|
||||
TestPort::InvalidBoatsLayoutLenOfABoat,
|
||||
TestPort::RandomBotInvalidBoatsLayoutLenOfABoat,
|
||||
)));
|
||||
wait_for_port(TestPort::InvalidBoatsLayoutLenOfABoat.port()).await;
|
||||
wait_for_port(TestPort::RandomBotInvalidBoatsLayoutLenOfABoat.port()).await;
|
||||
|
||||
let mut rules_modified = rules.clone();
|
||||
let previous = rules_modified.pop_boat();
|
||||
rules_modified.add_boat(previous - 1);
|
||||
let layout = BoatsLayout::gen_random_for_rules(&rules_modified).unwrap();
|
||||
|
||||
let res = bot_client::BotClient::new(&TestPort::InvalidBoatsLayoutLenOfABoat.as_url())
|
||||
let res = bot_client::BotClient::new(
|
||||
&TestPort::RandomBotInvalidBoatsLayoutLenOfABoat.as_url(),
|
||||
)
|
||||
.with_rules(rules)
|
||||
.with_layout(layout)
|
||||
.run_client()
|
||||
@ -157,11 +164,12 @@ async fn full_game_multiple_rematches() {
|
||||
local_set
|
||||
.run_until(async move {
|
||||
task::spawn_local(start_server(Args::for_test(
|
||||
TestPort::FullGameMultipleRematch,
|
||||
TestPort::RandomBotFullGameMultipleRematch,
|
||||
)));
|
||||
wait_for_port(TestPort::FullGameMultipleRematch.port()).await;
|
||||
wait_for_port(TestPort::RandomBotFullGameMultipleRematch.port()).await;
|
||||
|
||||
let res = bot_client::BotClient::new(TestPort::FullGameMultipleRematch.as_url())
|
||||
let res =
|
||||
bot_client::BotClient::new(TestPort::RandomBotFullGameMultipleRematch.as_url())
|
||||
.with_number_plays(5)
|
||||
.run_client()
|
||||
.await
|
||||
@ -170,3 +178,26 @@ async fn full_game_multiple_rematches() {
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn full_game_no_replay_on_hit() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
let local_set = task::LocalSet::new();
|
||||
local_set
|
||||
.run_until(async move {
|
||||
task::spawn_local(start_server(Args::for_test(
|
||||
TestPort::RandomBotNoReplayOnHit,
|
||||
)));
|
||||
wait_for_port(TestPort::RandomBotNoReplayOnHit.port()).await;
|
||||
|
||||
let res = bot_client::BotClient::new(TestPort::RandomBotNoReplayOnHit.as_url())
|
||||
.with_rules(GameRules::random_players_rules().with_player_continue_on_hit(false))
|
||||
.with_server_msg_callback(check_no_replay_on_hit)
|
||||
.run_client()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res, ClientEndResult::Finished);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
@ -2,14 +2,16 @@ use crate::args::Args;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum TestPort {
|
||||
ClientInvalidPort = 20000,
|
||||
ClientInvalidRules,
|
||||
FullGame,
|
||||
FullGameNoTouchingBoats,
|
||||
InvalidBoatsLayoutNumberOfBoats,
|
||||
InvalidBoatsLayoutLenOfABoat,
|
||||
FullGameMultipleRematch,
|
||||
RandomBotClientInvalidPort = 20000,
|
||||
RandomBotClientInvalidRules,
|
||||
RandomBotFullGame,
|
||||
RandomBotFullGameNoTouchingBoats,
|
||||
RandomBotInvalidBoatsLayoutNumberOfBoats,
|
||||
RandomBotInvalidBoatsLayoutLenOfABoat,
|
||||
RandomBotFullGameMultipleRematch,
|
||||
RandomBotNoReplayOnHit,
|
||||
LinearBotFullGame,
|
||||
LinearBotNoReplayOnHit,
|
||||
}
|
||||
|
||||
impl TestPort {
|
||||
@ -36,3 +38,4 @@ pub mod bot_client;
|
||||
mod bot_client_bot_linear_play;
|
||||
mod bot_client_bot_random_play;
|
||||
mod network_utils;
|
||||
mod play_utils;
|
||||
|
12
sea_battle_backend/src/test/play_utils.rs
Normal file
12
sea_battle_backend/src/test/play_utils.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use crate::human_player_ws::ServerMessage;
|
||||
|
||||
/// Make sure player can not replay after successful hit
|
||||
pub fn check_no_replay_on_hit(msg: &ServerMessage) {
|
||||
if let ServerMessage::OpponentMustFire { status } | ServerMessage::RequestFire { status } = msg
|
||||
{
|
||||
let diff =
|
||||
status.opponent_map.number_of_fires() as i32 - status.your_map.number_of_fires() as i32;
|
||||
|
||||
assert!(diff <= 1);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user