From d1e8efc7647a0297ce1e5f50b4c5509cbd852fc8 Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Sat, 17 Sep 2022 12:02:13 +0200 Subject: [PATCH] Add support for linear bots --- sea_battle_backend/src/bots/linear_bot.rs | 87 +++++++++++++++++++ sea_battle_backend/src/bots/mod.rs | 2 + .../src/{ => bots}/random_bot.rs | 0 sea_battle_backend/src/data/boats_layout.rs | 2 +- .../src/data/current_game_status.rs | 69 ++++++++++++++- sea_battle_backend/src/data/game_map.rs | 46 ++-------- sea_battle_backend/src/data/game_rules.rs | 5 ++ sea_battle_backend/src/data/mod.rs | 2 + sea_battle_backend/src/data/play_config.rs | 16 ++-- sea_battle_backend/src/data/printable_map.rs | 55 ++++++++++++ sea_battle_backend/src/game.rs | 2 +- sea_battle_backend/src/human_player_ws.rs | 8 +- sea_battle_backend/src/lib.rs | 2 +- sea_battle_backend/src/server.rs | 9 +- sea_battle_backend/src/test/bot_client.rs | 14 +++ .../src/test/bot_client_bot_linear_play.rs | 51 +++++++++++ ..._play.rs => bot_client_bot_random_play.rs} | 37 ++++---- sea_battle_backend/src/test/mod.rs | 9 +- 18 files changed, 344 insertions(+), 72 deletions(-) create mode 100644 sea_battle_backend/src/bots/linear_bot.rs create mode 100644 sea_battle_backend/src/bots/mod.rs rename sea_battle_backend/src/{ => bots}/random_bot.rs (100%) create mode 100644 sea_battle_backend/src/data/printable_map.rs create mode 100644 sea_battle_backend/src/test/bot_client_bot_linear_play.rs rename sea_battle_backend/src/test/{bot_client_bot_play.rs => bot_client_bot_random_play.rs} (81%) diff --git a/sea_battle_backend/src/bots/linear_bot.rs b/sea_battle_backend/src/bots/linear_bot.rs new file mode 100644 index 0000000..fc77159 --- /dev/null +++ b/sea_battle_backend/src/bots/linear_bot.rs @@ -0,0 +1,87 @@ +use actix::Addr; +use uuid::Uuid; + +use crate::data::{BoatsLayout, Coordinates, CurrentGameStatus, EndGameMap, FireResult, GameRules}; +use crate::game::{Fire, Game, Player, RespondRequestRematch, SetBoatsLayout}; + +#[derive(Clone)] +pub struct LinearBot { + game: Addr, + uuid: Uuid, +} + +impl LinearBot { + pub fn new(game: Addr) -> Self { + Self { + game, + uuid: Uuid::new_v4(), + } + } +} + +impl Player for LinearBot { + fn get_name(&self) -> &str { + "Linear Bot" + } + + fn get_uid(&self) -> Uuid { + self.uuid + } + + fn is_bot(&self) -> bool { + true + } + + fn set_other_player_name(&self, _name: &str) {} + + fn query_boats_layout(&self, rules: &GameRules) { + match BoatsLayout::gen_random_for_rules(rules) { + Ok(layout) => self.game.do_send(SetBoatsLayout(self.uuid, layout)), + + Err(e) => log::error!( + "Failed to use game rules to construct boats layout: {:?}", + e + ), + } + } + + fn rejected_boats_layout(&self, _errors: Vec<&'static str>) { + unreachable!() + } + + 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_first_valid_fire_location())); + } + + fn opponent_must_fire(&self, _status: CurrentGameStatus) {} + + fn strike_result(&self, _c: Coordinates, _res: FireResult) {} + + fn other_player_strike_result(&self, _c: Coordinates, _res: FireResult) {} + + fn lost_game(&self, _your_map: EndGameMap, _opponent_map: EndGameMap) {} + + fn won_game(&self, _your_map: EndGameMap, _opponent_map: EndGameMap) {} + + fn opponent_requested_rematch(&self) { + self.game.do_send(RespondRequestRematch(self.uuid, true)); + } + + fn opponent_rejected_rematch(&self) {} + + fn opponent_accepted_rematch(&self) {} + + fn opponent_left_game(&self) { + // Human are not reliable lol + } + + fn opponent_replaced_by_bot(&self) { + // Not such a good idea. will panic, just in case + panic!("Bot shall not play against each other (it is completely useless)"); + } +} diff --git a/sea_battle_backend/src/bots/mod.rs b/sea_battle_backend/src/bots/mod.rs new file mode 100644 index 0000000..6a1ea0f --- /dev/null +++ b/sea_battle_backend/src/bots/mod.rs @@ -0,0 +1,2 @@ +pub mod linear_bot; +pub mod random_bot; diff --git a/sea_battle_backend/src/random_bot.rs b/sea_battle_backend/src/bots/random_bot.rs similarity index 100% rename from sea_battle_backend/src/random_bot.rs rename to sea_battle_backend/src/bots/random_bot.rs diff --git a/sea_battle_backend/src/data/boats_layout.rs b/sea_battle_backend/src/data/boats_layout.rs index 0dc65e5..d093821 100644 --- a/sea_battle_backend/src/data/boats_layout.rs +++ b/sea_battle_backend/src/data/boats_layout.rs @@ -284,7 +284,7 @@ impl BoatsLayout { mod test { use crate::data::boats_layout::{BoatDirection, BoatPosition, BoatsLayout, Coordinates}; use crate::data::game_map::GameMap; - use crate::data::{BotType, GameRules, PlayConfiguration}; + use crate::data::{BotType, GameRules, PlayConfiguration, PrintableMap}; #[test] fn get_boat_coordinates() { diff --git a/sea_battle_backend/src/data/current_game_status.rs b/sea_battle_backend/src/data/current_game_status.rs index 5f592ff..d8316e3 100644 --- a/sea_battle_backend/src/data/current_game_status.rs +++ b/sea_battle_backend/src/data/current_game_status.rs @@ -1,8 +1,10 @@ use rand::RngCore; -use crate::data::{BoatPosition, BoatsLayout, Coordinates, GameRules}; +use crate::data::{ + BoatPosition, BoatsLayout, Coordinates, GameRules, MapCellContent, PrintableMap, +}; -#[derive(Debug, serde::Serialize, serde::Deserialize)] +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] pub struct CurrentGameMapStatus { pub boats: BoatsLayout, pub successful_strikes: Vec, @@ -10,7 +12,46 @@ pub struct CurrentGameMapStatus { pub sunk_boats: Vec, } -#[derive(Debug, serde::Serialize, serde::Deserialize)] +impl CurrentGameMapStatus { + pub fn did_fire_at_location(&self, c: Coordinates) -> bool { + self.successful_strikes.contains(&c) || self.failed_strikes.contains(&c) + } +} + +struct PrintableCurrentGameMapStatus(GameRules, CurrentGameMapStatus); + +impl PrintableMap for PrintableCurrentGameMapStatus { + fn map_cell_content(&self, c: Coordinates) -> MapCellContent { + if !c.is_valid(&self.0) { + return MapCellContent::Invalid; + } + + if self.1.failed_strikes.contains(&c) { + return MapCellContent::FailedStrike; + } + + if self + .1 + .sunk_boats + .iter() + .any(|b| b.all_coordinates().contains(&c)) + { + return MapCellContent::SunkBoat; + } + + if self.1.successful_strikes.contains(&c) { + return MapCellContent::TouchedBoat; + } + + if self.1.boats.find_boat_at_position(c).is_some() { + return MapCellContent::Boat; + } + + MapCellContent::Nothing + } +} + +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] pub struct CurrentGameStatus { pub rules: GameRules, pub your_map: CurrentGameMapStatus, @@ -37,4 +78,26 @@ impl CurrentGameStatus { } } } + + /// Find valid linear fire location. Loop until one is found + pub fn find_first_valid_fire_location(&self) -> Coordinates { + for y in 0..self.rules.map_height { + for x in 0..self.rules.map_width { + let coordinates = Coordinates::new(x as i32, y as i32); + if self.can_fire_at_location(coordinates) { + return coordinates; + } + } + } + + panic!("Could not find fire location!") + } + + pub fn print_your_map(&self) { + PrintableCurrentGameMapStatus(self.rules.clone(), self.your_map.clone()).print_map() + } + + pub fn print_opponent_map(&self) { + PrintableCurrentGameMapStatus(self.rules.clone(), self.opponent_map.clone()).print_map() + } } diff --git a/sea_battle_backend/src/data/game_map.rs b/sea_battle_backend/src/data/game_map.rs index 4d9f7d7..b772659 100644 --- a/sea_battle_backend/src/data/game_map.rs +++ b/sea_battle_backend/src/data/game_map.rs @@ -1,5 +1,7 @@ use crate::data::boats_layout::{BoatsLayout, Coordinates}; -use crate::data::{BoatPosition, CurrentGameMapStatus, EndGameMap, GameRules}; +use crate::data::{ + BoatPosition, CurrentGameMapStatus, EndGameMap, GameRules, MapCellContent, PrintableMap, +}; #[derive(Debug, Copy, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] pub enum FireResult { @@ -10,29 +12,6 @@ pub enum FireResult { AlreadyTargetedPosition, } -#[derive(Debug, Copy, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] -pub enum MapCellContent { - Invalid, - Nothing, - TouchedBoat, - SunkBoat, - Boat, - FailedStrike, -} - -impl MapCellContent { - pub fn letter(&self) -> &'static str { - match self { - MapCellContent::Invalid => "!", - MapCellContent::Nothing => ".", - MapCellContent::TouchedBoat => "T", - MapCellContent::SunkBoat => "S", - MapCellContent::Boat => "B", - MapCellContent::FailedStrike => "x", - } - } -} - pub struct GameMap { rules: GameRules, boats_config: BoatsLayout, @@ -120,19 +99,6 @@ impl GameMap { self.sunk_boats.len() == self.boats_config.number_of_boats() } - pub fn print_map(&self) { - for y in 0..self.rules.map_height { - for x in 0..self.rules.map_width { - print!( - "{} ", - self.get_cell_content(Coordinates::new(x as i32, y as i32)) - .letter() - ); - } - println!(); - } - } - pub fn current_map_status(&self, for_opponent: bool) -> CurrentGameMapStatus { CurrentGameMapStatus { boats: match for_opponent { @@ -158,3 +124,9 @@ impl GameMap { } } } + +impl PrintableMap for GameMap { + fn map_cell_content(&self, c: Coordinates) -> MapCellContent { + self.get_cell_content(c) + } +} diff --git a/sea_battle_backend/src/data/game_rules.rs b/sea_battle_backend/src/data/game_rules.rs index 6f4a118..9c82867 100644 --- a/sea_battle_backend/src/data/game_rules.rs +++ b/sea_battle_backend/src/data/game_rules.rs @@ -27,6 +27,11 @@ impl GameRules { } } + pub fn with_bot_type(mut self, t: BotType) -> Self { + self.bot_type = t; + self + } + /// Set the list of boats for this configuration pub fn set_boats_list(&mut self, boats: &[usize]) { self.boats_str = boats diff --git a/sea_battle_backend/src/data/mod.rs b/sea_battle_backend/src/data/mod.rs index 04c7de0..425bfe8 100644 --- a/sea_battle_backend/src/data/mod.rs +++ b/sea_battle_backend/src/data/mod.rs @@ -4,6 +4,7 @@ pub use end_game_map::*; pub use game_map::*; pub use game_rules::*; pub use play_config::*; +pub use printable_map::*; mod boats_layout; mod current_game_status; @@ -11,3 +12,4 @@ mod end_game_map; mod game_map; mod game_rules; mod play_config; +mod printable_map; diff --git a/sea_battle_backend/src/data/play_config.rs b/sea_battle_backend/src/data/play_config.rs index 346db15..05b93fd 100644 --- a/sea_battle_backend/src/data/play_config.rs +++ b/sea_battle_backend/src/data/play_config.rs @@ -4,7 +4,7 @@ use crate::consts::*; #[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone, Eq, PartialEq)] pub enum BotType { Random, - // TODO : LinearShooting + Linear, // TODO : GridBot // TODO : SmartBot } @@ -40,10 +40,16 @@ impl Default for PlayConfiguration { max_map_height: MAX_MAP_HEIGHT, min_boats_number: MIN_BOATS_NUMBER, max_boats_number: MAX_BOATS_NUMBER, - bot_types: vec![BotDescription { - r#type: BotType::Random, - description: "Random strike. All the time.".to_string(), - }], + bot_types: vec![ + BotDescription { + r#type: BotType::Linear, + description: "Linear strike. Shoot A1, A2, A3, ..., B1, B2, ...".to_string(), + }, + BotDescription { + r#type: BotType::Random, + description: "Random strike. All the time.".to_string(), + }, + ], ordinate_alphabet: ALPHABET, } } diff --git a/sea_battle_backend/src/data/printable_map.rs b/sea_battle_backend/src/data/printable_map.rs new file mode 100644 index 0000000..3e26b95 --- /dev/null +++ b/sea_battle_backend/src/data/printable_map.rs @@ -0,0 +1,55 @@ +use crate::data::Coordinates; + +#[derive(Debug, Copy, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub enum MapCellContent { + Invalid, + Nothing, + TouchedBoat, + SunkBoat, + Boat, + FailedStrike, +} + +impl MapCellContent { + pub fn letter(&self) -> &'static str { + match self { + MapCellContent::Invalid => "!", + MapCellContent::Nothing => ".", + MapCellContent::TouchedBoat => "T", + MapCellContent::SunkBoat => "S", + MapCellContent::Boat => "B", + MapCellContent::FailedStrike => "x", + } + } +} + +pub trait PrintableMap { + fn map_cell_content(&self, c: Coordinates) -> MapCellContent; + + fn print_map(&self) { + let mut y = 0; + let mut x; + loop { + x = 0; + loop { + let content = self.map_cell_content(Coordinates::new(x, y)); + + if content == MapCellContent::Invalid { + break; + } + + print!("{} ", content.letter()); + x += 1; + } + + println!(); + + // x == 0 <=> we reached the end of the map + if x == 0 { + break; + } + + y += 1; + } + } +} diff --git a/sea_battle_backend/src/game.rs b/sea_battle_backend/src/game.rs index 82ef526..87df927 100644 --- a/sea_battle_backend/src/game.rs +++ b/sea_battle_backend/src/game.rs @@ -4,8 +4,8 @@ use actix::prelude::*; use actix::{Actor, Context, Handler}; use uuid::Uuid; +use crate::bots::random_bot::RandomBot; use crate::data::*; -use crate::random_bot::RandomBot; pub trait Player { fn get_name(&self) -> &str; diff --git a/sea_battle_backend/src/human_player_ws.rs b/sea_battle_backend/src/human_player_ws.rs index 9181270..f7aaae5 100644 --- a/sea_battle_backend/src/human_player_ws.rs +++ b/sea_battle_backend/src/human_player_ws.rs @@ -1,18 +1,19 @@ 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::random_bot::RandomBot; use crate::data::{ BoatsLayout, BotType, Coordinates, CurrentGameStatus, EndGameMap, FireResult, GameRules, }; use crate::game::{AddPlayer, Game}; use crate::human_player::HumanPlayer; -use crate::random_bot::RandomBot; /// How often heartbeat pings are sent const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(10); @@ -41,7 +42,7 @@ pub enum ClientMessage { #[derive(Message)] #[rtype(result = "()")] -#[derive(serde::Serialize, serde::Deserialize, Debug)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[serde(tag = "type")] pub enum ServerMessage { WaitingForAnotherPlayer, @@ -147,6 +148,9 @@ impl Actor for HumanPlayerWS { BotType::Random => { game.do_send(AddPlayer(Arc::new(RandomBot::new(game.clone())))); } + BotType::Linear => { + game.do_send(AddPlayer(Arc::new(LinearBot::new(game.clone())))); + } }; let player = Arc::new(HumanPlayer { diff --git a/sea_battle_backend/src/lib.rs b/sea_battle_backend/src/lib.rs index ff7c153..36a05f7 100644 --- a/sea_battle_backend/src/lib.rs +++ b/sea_battle_backend/src/lib.rs @@ -1,12 +1,12 @@ extern crate core; pub mod args; +pub mod bots; pub mod consts; pub mod data; pub mod game; pub mod human_player; pub mod human_player_ws; -pub mod random_bot; pub mod server; #[cfg(test)] mod test; diff --git a/sea_battle_backend/src/server.rs b/sea_battle_backend/src/server.rs index 13f6158..1048568 100644 --- a/sea_battle_backend/src/server.rs +++ b/sea_battle_backend/src/server.rs @@ -1,10 +1,11 @@ -use crate::args::Args; -use crate::data::{GameRules, PlayConfiguration}; -use crate::human_player_ws::{HumanPlayerWS, StartMode}; use actix_cors::Cors; use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; use actix_web_actors::ws; +use crate::args::Args; +use crate::data::{GameRules, PlayConfiguration}; +use crate::human_player_ws::{HumanPlayerWS, StartMode}; + /// The default '/' route async fn index() -> impl Responder { HttpResponse::Ok().json("Sea battle backend") @@ -54,6 +55,8 @@ pub async fn start_server(args: Args) -> std::io::Result<()> { .wrap(cors) .route("/config", web::get().to(game_configuration)) .route("/play/bot", web::get().to(start_bot_play)) + // TODO : create & accept invite + // TODO : join random .route("/", web::get().to(index)) .route("{tail:.*}", web::get().to(not_found)) }) diff --git a/sea_battle_backend/src/test/bot_client.rs b/sea_battle_backend/src/test/bot_client.rs index 78ae655..8abae1f 100644 --- a/sea_battle_backend/src/test/bot_client.rs +++ b/sea_battle_backend/src/test/bot_client.rs @@ -20,6 +20,7 @@ pub struct BotClient { requested_rules: GameRules, layout: Option, number_plays: usize, + server_msg_callback: Option>, } impl BotClient { @@ -32,6 +33,7 @@ impl BotClient { requested_rules: GameRules::random_players_rules(), layout: None, number_plays: 1, + server_msg_callback: None, } } @@ -50,6 +52,14 @@ impl BotClient { self } + pub fn with_server_msg_callback(mut self, cb: F) -> Self + where + F: Fn(&ServerMessage) + 'static, + { + self.server_msg_callback = Some(Box::new(cb)); + self + } + pub async fn run_client(&self) -> Result> { let mut remaining_games = self.number_plays; @@ -97,6 +107,10 @@ impl BotClient { } }; + if let Some(cb) = &self.server_msg_callback { + (cb)(&message) + } + match message { ServerMessage::WaitingForAnotherPlayer => { log::debug!("Waiting for other player...") diff --git a/sea_battle_backend/src/test/bot_client_bot_linear_play.rs b/sea_battle_backend/src/test/bot_client_bot_linear_play.rs new file mode 100644 index 0000000..21d012b --- /dev/null +++ b/sea_battle_backend/src/test/bot_client_bot_linear_play.rs @@ -0,0 +1,51 @@ +use tokio::task; + +use crate::args::Args; +use crate::data::{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::{bot_client, TestPort}; + +fn check_strikes_are_linear(msg: &ServerMessage) { + if let ServerMessage::RequestFire { status } = msg { + let mut in_fire_location = true; + for y in 0..status.rules.map_height { + for x in 0..status.rules.map_width { + let c = Coordinates::new(x as i32, y as i32); + + if in_fire_location { + in_fire_location = status.your_map.did_fire_at_location(c); + } else if status.your_map.did_fire_at_location(c) { + println!("Your map:"); + status.print_your_map(); + println!("Opponent map:"); + status.print_opponent_map(); + panic!("Found invalid fire location for linear bot!"); + } + } + } + } +} + +#[tokio::test] +async fn full_game() { + 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::LinearBotFullGame))); + wait_for_port(TestPort::LinearBotFullGame.port()).await; + + let res = bot_client::BotClient::new(TestPort::LinearBotFullGame.as_url()) + .with_rules(GameRules::random_players_rules().with_bot_type(BotType::Linear)) + .with_server_msg_callback(check_strikes_are_linear) + .run_client() + .await + .unwrap(); + assert_eq!(res, ClientEndResult::Finished); + }) + .await; +} diff --git a/sea_battle_backend/src/test/bot_client_bot_play.rs b/sea_battle_backend/src/test/bot_client_bot_random_play.rs similarity index 81% rename from sea_battle_backend/src/test/bot_client_bot_play.rs rename to sea_battle_backend/src/test/bot_client_bot_random_play.rs index 3eb5f75..cd40756 100644 --- a/sea_battle_backend/src/test/bot_client_bot_play.rs +++ b/sea_battle_backend/src/test/bot_client_bot_random_play.rs @@ -72,11 +72,11 @@ 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::FullGameTouchingBoats, + TestPort::FullGameNoTouchingBoats, ))); - wait_for_port(TestPort::FullGameTouchingBoats.port()).await; + wait_for_port(TestPort::FullGameNoTouchingBoats.port()).await; - let res = bot_client::BotClient::new(TestPort::FullGameTouchingBoats.as_url()) + let res = bot_client::BotClient::new(TestPort::FullGameNoTouchingBoats.as_url()) .with_rules(rules) .run_client() .await @@ -97,20 +97,21 @@ 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::FullGameTouchingBoats, + TestPort::InvalidBoatsLayoutNumberOfBoats, ))); - wait_for_port(TestPort::FullGameTouchingBoats.port()).await; + wait_for_port(TestPort::InvalidBoatsLayoutNumberOfBoats.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::FullGameTouchingBoats.as_url()) - .with_rules(rules) - .with_layout(layout) - .run_client() - .await - .unwrap(); + let res = + bot_client::BotClient::new(&TestPort::InvalidBoatsLayoutNumberOfBoats.as_url()) + .with_rules(rules) + .with_layout(layout) + .run_client() + .await + .unwrap(); assert_eq!(res, ClientEndResult::InvalidBoatsLayout); }) @@ -127,16 +128,16 @@ 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::FullGameTouchingBoats, + TestPort::InvalidBoatsLayoutLenOfABoat, ))); - wait_for_port(TestPort::FullGameTouchingBoats.port()).await; + wait_for_port(TestPort::InvalidBoatsLayoutLenOfABoat.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::FullGameTouchingBoats.as_url()) + let res = bot_client::BotClient::new(&TestPort::InvalidBoatsLayoutLenOfABoat.as_url()) .with_rules(rules) .with_layout(layout) .run_client() @@ -155,10 +156,12 @@ async fn full_game_multiple_rematches() { 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::FullGameMultipleRematch, + ))); + wait_for_port(TestPort::FullGameMultipleRematch.port()).await; - let res = bot_client::BotClient::new(TestPort::FullGame.as_url()) + let res = bot_client::BotClient::new(TestPort::FullGameMultipleRematch.as_url()) .with_number_plays(5) .run_client() .await diff --git a/sea_battle_backend/src/test/mod.rs b/sea_battle_backend/src/test/mod.rs index 795b3db..5b9949c 100644 --- a/sea_battle_backend/src/test/mod.rs +++ b/sea_battle_backend/src/test/mod.rs @@ -5,7 +5,11 @@ enum TestPort { ClientInvalidPort = 20000, ClientInvalidRules, FullGame, - FullGameTouchingBoats, + FullGameNoTouchingBoats, + InvalidBoatsLayoutNumberOfBoats, + InvalidBoatsLayoutLenOfABoat, + FullGameMultipleRematch, + LinearBotFullGame, } impl TestPort { @@ -29,5 +33,6 @@ impl Args { #[cfg(test)] pub mod bot_client; -mod bot_client_bot_play; +mod bot_client_bot_linear_play; +mod bot_client_bot_random_play; mod network_utils;