Add tests for no replay after hit rule
This commit is contained in:
@@ -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)) {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user