use crate::data::boats_layout::{BoatsLayout, Coordinates}; use crate::data::*; #[derive(Debug, Copy, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] pub enum FireResult { Missed, Hit, Sunk(BoatPosition), Rejected, AlreadyTargetedPosition, } pub struct GameMap { rules: GameRules, boats_config: BoatsLayout, failed_strikes: Vec, successful_strikes: Vec, sunk_boats: Vec, } impl GameMap { pub fn new(rules: GameRules, boats_config: BoatsLayout) -> Self { Self { rules, boats_config, failed_strikes: vec![], successful_strikes: vec![], sunk_boats: vec![], } } pub fn get_cell_content(&self, c: Coordinates) -> MapCellContent { if !c.is_valid(&self.rules) { return MapCellContent::Invalid; } if self.failed_strikes.contains(&c) { return MapCellContent::FailedStrike; } if let Some(b) = self.boats_config.find_boat_at_position(c) { if !self.successful_strikes.contains(&c) { return MapCellContent::Boat; } if self.sunk_boats.contains(b) { return MapCellContent::SunkBoat; } return MapCellContent::TouchedBoat; } MapCellContent::Nothing } pub fn fire(&mut self, c: Coordinates) -> FireResult { if !c.is_valid(&self.rules) { return FireResult::Rejected; } if self.failed_strikes.contains(&c) || self.successful_strikes.contains(&c) { return FireResult::AlreadyTargetedPosition; } match self.boats_config.find_boat_at_position(c) { None => { self.failed_strikes.push(c); FireResult::Missed } Some(b) => { self.successful_strikes.push(c); if !b .all_coordinates() .iter() .all(|c| self.successful_strikes.contains(c)) { return FireResult::Hit; } self.sunk_boats.push(*b); if !self.rules.boats_can_touch { for c in b.neighbor_coordinates(&self.rules) { if !self.failed_strikes.contains(&c) { self.failed_strikes.push(c); } } } FireResult::Sunk(*b) } } } pub fn are_all_boat_sunk(&self) -> bool { self.sunk_boats.len() == self.boats_config.number_of_boats() } pub fn current_map_status(&self, for_opponent: bool) -> CurrentGameMapStatus { CurrentGameMapStatus { boats: match for_opponent { true => BoatsLayout::new_invalid(), false => self.boats_config.clone(), }, successful_strikes: self.successful_strikes.clone(), failed_strikes: self.failed_strikes.clone(), sunk_boats: self.sunk_boats.clone(), } } } impl PrintableMap for GameMap { fn map_cell_content(&self, c: Coordinates) -> MapCellContent { self.get_cell_content(c) } }