2022-09-10 15:02:45 +02:00
|
|
|
use crate::consts::*;
|
|
|
|
|
2022-09-11 16:48:20 +02:00
|
|
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)]
|
|
|
|
pub enum BotType {
|
|
|
|
Random,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(serde::Serialize)]
|
|
|
|
struct BotDescription {
|
|
|
|
r#type: BotType,
|
|
|
|
description: String,
|
|
|
|
}
|
|
|
|
|
2022-09-10 15:02:45 +02:00
|
|
|
#[derive(serde::Serialize)]
|
|
|
|
pub struct PlayConfiguration {
|
|
|
|
min_boat_len: usize,
|
|
|
|
max_boat_len: usize,
|
|
|
|
min_map_width: usize,
|
|
|
|
max_map_width: usize,
|
|
|
|
min_map_height: usize,
|
|
|
|
max_map_height: usize,
|
|
|
|
min_boats_number: usize,
|
|
|
|
max_boats_number: usize,
|
2022-09-11 16:48:20 +02:00
|
|
|
bot_types: Vec<BotDescription>,
|
2022-09-10 15:02:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for PlayConfiguration {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
min_boat_len: MIN_BOATS_LENGTH,
|
|
|
|
max_boat_len: MAX_BOATS_LENGTH,
|
|
|
|
min_map_width: MIN_MAP_WIDTH,
|
|
|
|
max_map_width: MAX_MAP_WIDTH,
|
|
|
|
min_map_height: MIN_MAP_HEIGHT,
|
|
|
|
max_map_height: MAX_MAP_HEIGHT,
|
|
|
|
min_boats_number: MIN_BOATS_NUMBER,
|
|
|
|
max_boats_number: MAX_BOATS_NUMBER,
|
2022-09-11 16:48:20 +02:00
|
|
|
bot_types: vec![BotDescription {
|
|
|
|
r#type: BotType::Random,
|
|
|
|
description: "Random strike. All the time.".to_string(),
|
|
|
|
}],
|
2022-09-10 15:02:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-11 16:48:20 +02:00
|
|
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
2022-09-10 15:02:45 +02:00
|
|
|
pub struct GameRules {
|
|
|
|
pub map_width: usize,
|
|
|
|
pub map_height: usize,
|
2022-09-11 16:48:20 +02:00
|
|
|
pub boats_str: String,
|
2022-09-10 15:02:45 +02:00
|
|
|
pub boats_can_touch: bool,
|
|
|
|
pub player_continue_on_hit: bool,
|
2022-09-11 16:48:20 +02:00
|
|
|
pub bot_type: BotType,
|
2022-09-10 15:02:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl GameRules {
|
|
|
|
pub fn multi_players_rules() -> Self {
|
|
|
|
Self {
|
|
|
|
map_width: MULTI_PLAYER_MAP_WIDTH,
|
|
|
|
map_height: MULTI_PLAYER_MAP_HEIGHT,
|
2022-09-11 16:48:20 +02:00
|
|
|
boats_str: MULTI_PLAYER_PLAYER_BOATS
|
|
|
|
.iter()
|
|
|
|
.map(usize::to_string)
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(","),
|
2022-09-10 15:02:45 +02:00
|
|
|
boats_can_touch: MULTI_PLAYER_BOATS_CAN_TOUCH,
|
|
|
|
player_continue_on_hit: MULTI_PLAYER_PLAYER_CAN_CONTINUE_AFTER_HIT,
|
2022-09-11 16:48:20 +02:00
|
|
|
bot_type: BotType::Random,
|
2022-09-10 15:02:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-11 16:48:20 +02:00
|
|
|
pub fn boats(&self) -> Vec<usize> {
|
|
|
|
self.boats_str
|
|
|
|
.split(',')
|
|
|
|
.map(|s| s.parse::<usize>().unwrap_or_default())
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
2022-09-10 15:02:45 +02:00
|
|
|
pub fn get_errors(&self) -> Vec<&str> {
|
|
|
|
let config = PlayConfiguration::default();
|
|
|
|
|
|
|
|
let mut errors = vec![];
|
|
|
|
|
|
|
|
if self.map_width < config.min_map_width || self.map_width > config.max_map_width {
|
|
|
|
errors.push("Map width is outside bounds!");
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.map_height < config.min_map_height || self.map_height > config.max_map_height {
|
|
|
|
errors.push("Map height is outside bounds!");
|
|
|
|
}
|
|
|
|
|
2022-09-11 16:48:20 +02:00
|
|
|
if self.boats().len() < config.min_boats_number
|
|
|
|
|| self.boats().len() > config.max_boats_number
|
|
|
|
{
|
2022-09-10 15:02:45 +02:00
|
|
|
errors.push("Number of boats is invalid!");
|
|
|
|
}
|
|
|
|
|
2022-09-11 16:48:20 +02:00
|
|
|
for boat in self.boats() {
|
|
|
|
if boat < config.min_boat_len || boat > config.max_boat_len {
|
|
|
|
errors.push("A boat has an invalid length");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-10 15:02:45 +02:00
|
|
|
errors
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use crate::data::GameRules;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn multi_players_config() {
|
|
|
|
assert!(GameRules::multi_players_rules().get_errors().is_empty());
|
|
|
|
}
|
2022-09-11 16:48:20 +02:00
|
|
|
}
|