Start to work on game structures

This commit is contained in:
Pierre HUBERT 2022-09-12 16:38:14 +02:00
parent c0b6067d34
commit 5a19763d73
6 changed files with 199 additions and 46 deletions

92
src/data/boats_layout.rs Normal file
View File

@ -0,0 +1,92 @@
use crate::data::GameRules;
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy)]
pub enum BoatDirection {
Left,
Right,
Top,
Bottom,
}
impl BoatDirection {
pub fn shift_coordinates(&self, coordinates: Coordinates, nth: usize) -> Coordinates {
let shift = match self {
BoatDirection::Left => (1, 0),
BoatDirection::Right => (-1, 0),
BoatDirection::Top => (0, -1),
BoatDirection::Bottom => (0, 1),
};
Coordinates::new(
coordinates.x + shift.0 * nth as i32,
coordinates.y + shift.1 * nth as i32,
)
}
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
pub struct Coordinates {
x: i32,
y: i32,
}
impl Coordinates {
pub fn new<E>(x: E, y: E) -> Self
where
E: Into<i32>,
{
Self {
x: x.into(),
y: y.into(),
}
}
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy)]
pub struct BoatPosition {
start: Coordinates,
len: usize,
direction: BoatDirection,
}
impl BoatPosition {
pub fn all_coordinates(&self) -> Vec<Coordinates> {
let mut positions = Vec::with_capacity(self.len);
for i in 0..self.len {
positions.push(self.direction.shift_coordinates(self.start, i));
}
positions
}
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct BoatsLayout(Vec<BoatPosition>);
impl BoatsLayout {
pub fn gen_random_for_rules(rules: &GameRules) -> Self {
todo!()
}
}
#[cfg(test)]
mod test {
use crate::data::boats_layout::{BoatDirection, BoatPosition, Coordinates};
#[test]
fn get_boat_coordinates() {
let position = BoatPosition {
start: Coordinates { x: 1, y: 1 },
len: 3,
direction: BoatDirection::Bottom,
};
let coordinates = position.all_coordinates();
assert_eq!(
coordinates,
vec![
Coordinates::new(1, 1),
Coordinates::new(1, 2),
Coordinates::new(1, 3),
]
)
}
}

50
src/data/game_map.rs Normal file
View File

@ -0,0 +1,50 @@
use crate::data::boats_layout::BoatsLayout;
use crate::data::GameRules;
enum MapCellContent {
Invalid,
Nothing,
TouchedBoat,
Boat,
FailedStrike,
}
impl MapCellContent {
fn letter(&self) -> &'static str {
match self {
MapCellContent::Invalid => "!",
MapCellContent::Nothing => " ",
MapCellContent::TouchedBoat => "T",
MapCellContent::Boat => "B",
MapCellContent::FailedStrike => "X",
}
}
}
pub struct GameMap {
rules: GameRules,
boats_config: BoatsLayout,
}
impl GameMap {
pub fn new(rules: GameRules, boats_config: BoatsLayout) -> Self {
Self {
rules,
boats_config,
}
}
pub fn get_cell_content(&self, x: usize, y: usize) -> MapCellContent {
// TODO : improve this
return MapCellContent::Nothing;
}
pub fn print_map(&self) {
for y in 0..self.rules.map_height {
for x in 0..self.rules.map_width {
print!("{} ", self.get_cell_content(x, y).letter());
}
println!();
}
}
}

View File

@ -1,48 +1,5 @@
use crate::consts::*;
/// Specifies the kind of boat to use
#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)]
pub enum BotType {
Random,
}
#[derive(serde::Serialize)]
struct BotDescription {
r#type: BotType,
description: String,
}
#[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,
bot_types: Vec<BotDescription>,
}
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,
bot_types: vec![BotDescription {
r#type: BotType::Random,
description: "Random strike. All the time.".to_string(),
}],
}
}
}
use crate::data::{BotType, PlayConfiguration};
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct GameRules {

7
src/data/mod.rs Normal file
View File

@ -0,0 +1,7 @@
pub use game_rules::*;
pub use play_config::*;
mod boats_layout;
mod game_map;
mod game_rules;
mod play_config;

45
src/data/play_config.rs Normal file
View File

@ -0,0 +1,45 @@
use crate::consts::*;
/// Specifies the kind of boat to use
#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)]
pub enum BotType {
Random,
}
#[derive(serde::Serialize)]
pub struct BotDescription {
r#type: BotType,
description: String,
}
#[derive(serde::Serialize)]
pub struct PlayConfiguration {
pub min_boat_len: usize,
pub max_boat_len: usize,
pub min_map_width: usize,
pub max_map_width: usize,
pub min_map_height: usize,
pub max_map_height: usize,
pub min_boats_number: usize,
pub max_boats_number: usize,
pub bot_types: Vec<BotDescription>,
}
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,
bot_types: vec![BotDescription {
r#type: BotType::Random,
description: "Random strike. All the time.".to_string(),
}],
}
}
}

View File

@ -30,8 +30,10 @@ pub enum ClientMessage {
#[derive(serde::Serialize, Debug)]
#[serde(tag = "type")]
pub enum ServerMessage {
WaitingForOtherPlayer,
WaitingForAnotherPlayer,
QueryBoatsLayout { rules: GameRules },
WaitingForOtherPlayerConfiguration,
OtherPlayerReady,
}
#[derive(Default)]
@ -51,7 +53,7 @@ impl Actor for HumanPlayerWS {
type Context = WebsocketContext<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
self.send_message(ServerMessage::WaitingForOtherPlayer, ctx);
self.send_message(ServerMessage::WaitingForAnotherPlayer, ctx);
// Start game, according to appropriate start mode
match &self.start_mode {