Add tests for no replay after hit rule

This commit is contained in:
2022-09-19 19:29:11 +02:00
parent 7cfd7a4899
commit 6832aebedb
17 changed files with 280 additions and 132 deletions

View File

@@ -213,6 +213,42 @@ impl BoatsLayout {
Ok(boats)
}
/// Generate boats layout that put boats at the beginning of the map
pub fn layout_for_boats_at_beginning_of_map(rules: &GameRules) -> std::io::Result<Self> {
let mut boats = Self(Vec::with_capacity(rules.boats_list().len()));
let mut list = rules.boats_list();
list.sort();
list.reverse();
for y in 0..rules.map_height {
for x in 0..rules.map_width {
if list.is_empty() {
break;
}
let position = BoatPosition {
start: Coordinates::new(x as i32, y as i32),
len: list[0],
direction: BoatDirection::Right,
};
if boats.is_acceptable_boat_position(&position, rules) {
list.remove(0);
boats.0.push(position);
}
}
}
if !list.is_empty() {
return Err(std::io::Error::new(
ErrorKind::Other,
"Un-usable game rules!",
));
}
Ok(boats)
}
fn is_acceptable_boat_position(&self, pos: &BoatPosition, rules: &GameRules) -> bool {
// Check if boat coordinates are valid
if pos.all_coordinates().iter().any(|c| !c.is_valid(rules)) {

View File

@@ -16,6 +16,10 @@ impl CurrentGameMapStatus {
pub fn did_fire_at_location(&self, c: Coordinates) -> bool {
self.successful_strikes.contains(&c) || self.failed_strikes.contains(&c)
}
pub fn number_of_fires(&self) -> usize {
self.successful_strikes.len() + self.failed_strikes.len()
}
}
struct PrintableCurrentGameMapStatus(GameRules, CurrentGameMapStatus);
@@ -207,12 +211,20 @@ impl CurrentGameStatus {
boats_size.first().cloned()
}
pub fn get_your_map(&self) -> String {
PrintableCurrentGameMapStatus(self.rules.clone(), self.your_map.clone()).get_map()
}
pub fn get_opponent_map(&self) -> String {
PrintableCurrentGameMapStatus(self.rules.clone(), self.opponent_map.clone()).get_map()
}
pub fn print_your_map(&self) {
PrintableCurrentGameMapStatus(self.rules.clone(), self.your_map.clone()).print_map()
print!("{}", self.get_your_map());
}
pub fn print_opponent_map(&self) {
PrintableCurrentGameMapStatus(self.rules.clone(), self.opponent_map.clone()).print_map()
print!("{}", self.get_opponent_map());
}
}

View File

@@ -1,22 +0,0 @@
use std::fmt::Write;
use crate::data::{BoatsLayout, MapCellContent};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct EndGameMap {
pub boats: BoatsLayout,
pub grid: Vec<Vec<MapCellContent>>,
}
impl EndGameMap {
pub fn get_map(&self) -> String {
let mut s = String::new();
for row in &self.grid {
for col in row {
write!(&mut s, "{} ", col.letter()).unwrap();
}
s.push('\n');
}
s
}
}

View File

@@ -1,7 +1,5 @@
use crate::data::boats_layout::{BoatsLayout, Coordinates};
use crate::data::{
BoatPosition, CurrentGameMapStatus, EndGameMap, GameRules, MapCellContent, PrintableMap,
};
use crate::data::*;
#[derive(Debug, Copy, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum FireResult {
@@ -110,19 +108,6 @@ impl GameMap {
sunk_boats: self.sunk_boats.clone(),
}
}
pub fn final_map(&self) -> EndGameMap {
EndGameMap {
boats: self.boats_config.clone(),
grid: (0..self.rules.map_height)
.map(|y| {
(0..self.rules.map_width)
.map(|x| self.get_cell_content(Coordinates::new(x as i32, y as i32)))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>(),
}
}
}
impl PrintableMap for GameMap {

View File

@@ -38,6 +38,11 @@ impl GameRules {
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

View File

@@ -1,6 +1,5 @@
pub use boats_layout::*;
pub use current_game_status::*;
pub use end_game_map::*;
pub use game_map::*;
pub use game_rules::*;
pub use play_config::*;
@@ -8,7 +7,6 @@ pub use printable_map::*;
mod boats_layout;
mod current_game_status;
mod end_game_map;
mod game_map;
mod game_rules;
mod play_config;

View File

@@ -1,3 +1,6 @@
use std::fmt::Write;
use std::string::String;
use crate::data::Coordinates;
#[derive(Debug, Copy, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
@@ -27,6 +30,12 @@ pub trait PrintableMap {
fn map_cell_content(&self, c: Coordinates) -> MapCellContent;
fn print_map(&self) {
print!("{}", self.get_map());
}
fn get_map(&self) -> String {
let mut out = String::with_capacity(100);
let mut y = 0;
let mut x;
loop {
@@ -38,11 +47,11 @@ pub trait PrintableMap {
break;
}
print!("{} ", content.letter());
write!(out, "{} ", content.letter()).unwrap();
x += 1;
}
println!();
out.push('\n');
// x == 0 <=> we reached the end of the map
if x == 0 {
@@ -51,5 +60,7 @@ pub trait PrintableMap {
y += 1;
}
out
}
}