diff --git a/src/data/boats_layout.rs b/src/data/boats_layout.rs new file mode 100644 index 0000000..a186990 --- /dev/null +++ b/src/data/boats_layout.rs @@ -0,0 +1,92 @@ +use crate::data::GameRules; + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy)] +pub enum BoatDirection { + Left, + Right, + Top, + Bottom, +} + +impl BoatDirection { + pub fn shift_coordinates(&self, coordinates: Coordinates, nth: usize) -> Coordinates { + let shift = match self { + BoatDirection::Left => (1, 0), + BoatDirection::Right => (-1, 0), + BoatDirection::Top => (0, -1), + BoatDirection::Bottom => (0, 1), + }; + + Coordinates::new( + coordinates.x + shift.0 * nth as i32, + coordinates.y + shift.1 * nth as i32, + ) + } +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, Eq, PartialEq)] +pub struct Coordinates { + x: i32, + y: i32, +} + +impl Coordinates { + pub fn new(x: E, y: E) -> Self + where + E: Into, + { + Self { + x: x.into(), + y: y.into(), + } + } +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy)] +pub struct BoatPosition { + start: Coordinates, + len: usize, + direction: BoatDirection, +} + +impl BoatPosition { + pub fn all_coordinates(&self) -> Vec { + let mut positions = Vec::with_capacity(self.len); + for i in 0..self.len { + positions.push(self.direction.shift_coordinates(self.start, i)); + } + positions + } +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct BoatsLayout(Vec); + +impl BoatsLayout { + pub fn gen_random_for_rules(rules: &GameRules) -> Self { + todo!() + } +} + +#[cfg(test)] +mod test { + use crate::data::boats_layout::{BoatDirection, BoatPosition, Coordinates}; + + #[test] + fn get_boat_coordinates() { + let position = BoatPosition { + start: Coordinates { x: 1, y: 1 }, + len: 3, + direction: BoatDirection::Bottom, + }; + let coordinates = position.all_coordinates(); + assert_eq!( + coordinates, + vec![ + Coordinates::new(1, 1), + Coordinates::new(1, 2), + Coordinates::new(1, 3), + ] + ) + } +} diff --git a/src/data/game_map.rs b/src/data/game_map.rs new file mode 100644 index 0000000..7d2e552 --- /dev/null +++ b/src/data/game_map.rs @@ -0,0 +1,50 @@ +use crate::data::boats_layout::BoatsLayout; +use crate::data::GameRules; + +enum MapCellContent { + Invalid, + Nothing, + TouchedBoat, + Boat, + FailedStrike, +} + +impl MapCellContent { + fn letter(&self) -> &'static str { + match self { + MapCellContent::Invalid => "!", + MapCellContent::Nothing => " ", + MapCellContent::TouchedBoat => "T", + MapCellContent::Boat => "B", + MapCellContent::FailedStrike => "X", + } + } +} + +pub struct GameMap { + rules: GameRules, + boats_config: BoatsLayout, +} + +impl GameMap { + pub fn new(rules: GameRules, boats_config: BoatsLayout) -> Self { + Self { + rules, + boats_config, + } + } + + pub fn get_cell_content(&self, x: usize, y: usize) -> MapCellContent { + // TODO : improve this + return MapCellContent::Nothing; + } + + 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(x, y).letter()); + } + println!(); + } + } +} diff --git a/src/data.rs b/src/data/game_rules.rs similarity index 64% rename from src/data.rs rename to src/data/game_rules.rs index bbf4705..8335553 100644 --- a/src/data.rs +++ b/src/data/game_rules.rs @@ -1,48 +1,5 @@ use crate::consts::*; - -/// Specifies the kind of boat to use -#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)] -pub enum BotType { - Random, -} - -#[derive(serde::Serialize)] -struct BotDescription { - r#type: BotType, - description: String, -} - -#[derive(serde::Serialize)] -pub struct PlayConfiguration { - min_boat_len: usize, - max_boat_len: usize, - min_map_width: usize, - max_map_width: usize, - min_map_height: usize, - max_map_height: usize, - min_boats_number: usize, - max_boats_number: usize, - bot_types: Vec, -} - -impl Default for PlayConfiguration { - fn default() -> Self { - Self { - min_boat_len: MIN_BOATS_LENGTH, - max_boat_len: MAX_BOATS_LENGTH, - min_map_width: MIN_MAP_WIDTH, - max_map_width: MAX_MAP_WIDTH, - min_map_height: MIN_MAP_HEIGHT, - 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(), - }], - } - } -} +use crate::data::{BotType, PlayConfiguration}; #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct GameRules { diff --git a/src/data/mod.rs b/src/data/mod.rs new file mode 100644 index 0000000..827074f --- /dev/null +++ b/src/data/mod.rs @@ -0,0 +1,7 @@ +pub use game_rules::*; +pub use play_config::*; + +mod boats_layout; +mod game_map; +mod game_rules; +mod play_config; diff --git a/src/data/play_config.rs b/src/data/play_config.rs new file mode 100644 index 0000000..c73e7a2 --- /dev/null +++ b/src/data/play_config.rs @@ -0,0 +1,45 @@ +use crate::consts::*; + +/// Specifies the kind of boat to use +#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)] +pub enum BotType { + Random, +} + +#[derive(serde::Serialize)] +pub struct BotDescription { + r#type: BotType, + description: String, +} + +#[derive(serde::Serialize)] +pub struct PlayConfiguration { + pub min_boat_len: usize, + pub max_boat_len: usize, + pub min_map_width: usize, + pub max_map_width: usize, + pub min_map_height: usize, + pub max_map_height: usize, + pub min_boats_number: usize, + pub max_boats_number: usize, + pub bot_types: Vec, +} + +impl Default for PlayConfiguration { + fn default() -> Self { + Self { + min_boat_len: MIN_BOATS_LENGTH, + max_boat_len: MAX_BOATS_LENGTH, + min_map_width: MIN_MAP_WIDTH, + max_map_width: MAX_MAP_WIDTH, + min_map_height: MIN_MAP_HEIGHT, + 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(), + }], + } + } +} diff --git a/src/human_player_ws.rs b/src/human_player_ws.rs index 0d31478..9f61369 100644 --- a/src/human_player_ws.rs +++ b/src/human_player_ws.rs @@ -30,8 +30,10 @@ pub enum ClientMessage { #[derive(serde::Serialize, Debug)] #[serde(tag = "type")] pub enum ServerMessage { - WaitingForOtherPlayer, + WaitingForAnotherPlayer, QueryBoatsLayout { rules: GameRules }, + WaitingForOtherPlayerConfiguration, + OtherPlayerReady, } #[derive(Default)] @@ -51,7 +53,7 @@ impl Actor for HumanPlayerWS { type Context = WebsocketContext; fn started(&mut self, ctx: &mut Self::Context) { - self.send_message(ServerMessage::WaitingForOtherPlayer, ctx); + self.send_message(ServerMessage::WaitingForAnotherPlayer, ctx); // Start game, according to appropriate start mode match &self.start_mode {