118 lines
3.2 KiB
Rust
118 lines
3.2 KiB
Rust
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<Coordinates>,
|
|
successful_strikes: Vec<Coordinates>,
|
|
sunk_boats: Vec<BoatPosition>,
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|