SeaBattle/rust/sea_battle_backend/src/data/game_map.rs

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)
}
}