use crate::consts::*; use crate::data::{BotType, PlayConfiguration}; #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq)] pub struct GameRules { pub map_width: usize, pub map_height: usize, pub boats_str: String, pub boats_can_touch: bool, pub player_continue_on_hit: bool, pub bot_type: BotType, } impl Default for GameRules { fn default() -> Self { Self::random_players_rules() } } impl GameRules { pub fn random_players_rules() -> Self { Self { map_width: MULTI_PLAYER_MAP_WIDTH, map_height: MULTI_PLAYER_MAP_HEIGHT, boats_str: MULTI_PLAYER_PLAYER_BOATS .iter() .map(usize::to_string) .collect::>() .join(","), boats_can_touch: MULTI_PLAYER_BOATS_CAN_TOUCH, player_continue_on_hit: MULTI_PLAYER_PLAYER_CAN_CONTINUE_AFTER_HIT, bot_type: BotType::Random, } } pub fn with_bot_type(mut self, t: BotType) -> Self { self.bot_type = t; 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 .iter() .map(usize::to_string) .collect::>() .join(","); } /// Get the list of boats for this configuration pub fn boats_list(&self) -> Vec { self.boats_str .split(',') .map(|s| s.parse::().unwrap_or_default()) .collect() } /// Remove last boat pub fn pop_boat(&mut self) -> usize { let list = self.boats_list(); self.set_boats_list(&list[0..list.len() - 1]); *list.last().unwrap() } /// Add a boat to the list of boats pub fn add_boat(&mut self, len: usize) { let mut list = self.boats_list(); list.push(len); self.set_boats_list(&list[0..list.len() - 1]); } /// Check game rules errors pub fn get_errors(&self) -> Vec<&str> { let config = PlayConfiguration::default(); let mut errors = vec![]; if self.map_width < config.min_map_width || self.map_width > config.max_map_width { errors.push("Map width is outside bounds!"); } if self.map_height < config.min_map_height || self.map_height > config.max_map_height { errors.push("Map height is outside bounds!"); } if self.boats_list().len() < config.min_boats_number || self.boats_list().len() > config.max_boats_number { errors.push("Number of boats is invalid!"); } for boat in self.boats_list() { if boat < config.min_boat_len || boat > config.max_boat_len { errors.push("A boat has an invalid length"); } } errors } } #[cfg(test)] mod test { use crate::data::GameRules; #[test] fn multi_players_config() { assert!(GameRules::random_players_rules().get_errors().is_empty()); } }