Boat automatically send its boats configuration
This commit is contained in:
parent
b36f2d4f20
commit
001d4341de
@ -159,7 +159,7 @@ impl BoatsLayout {
|
|||||||
direction: directions[rng.gen::<usize>() % directions.len()],
|
direction: directions[rng.gen::<usize>() % directions.len()],
|
||||||
};
|
};
|
||||||
|
|
||||||
if boats.is_acceptable_boat_position(&position, &rules) {
|
if boats.is_acceptable_boat_position(&position, rules) {
|
||||||
boats.0.push(position);
|
boats.0.push(position);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -194,7 +194,7 @@ impl BoatsLayout {
|
|||||||
// Check if the boat touch another boat in a configuration where is it forbidden
|
// Check if the boat touch another boat in a configuration where is it forbidden
|
||||||
if !rules.boats_can_touch
|
if !rules.boats_can_touch
|
||||||
&& pos
|
&& pos
|
||||||
.neighbor_coordinates(&rules)
|
.neighbor_coordinates(rules)
|
||||||
.iter()
|
.iter()
|
||||||
.any(|c| self.find_boat_at_position(*c).is_some())
|
.any(|c| self.find_boat_at_position(*c).is_some())
|
||||||
{
|
{
|
||||||
@ -225,7 +225,7 @@ impl BoatsLayout {
|
|||||||
for boat_i in 0..self.0.len() {
|
for boat_i in 0..self.0.len() {
|
||||||
// Check boat coordinates
|
// Check boat coordinates
|
||||||
let boat_i_coordinates = self.0[boat_i].all_coordinates();
|
let boat_i_coordinates = self.0[boat_i].all_coordinates();
|
||||||
if boat_i_coordinates.iter().any(|c| !c.is_valid(&rules)) {
|
if boat_i_coordinates.iter().any(|c| !c.is_valid(rules)) {
|
||||||
errors.push("A boat goes outside the game map!");
|
errors.push("A boat goes outside the game map!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +241,7 @@ impl BoatsLayout {
|
|||||||
|
|
||||||
if !rules.boats_can_touch
|
if !rules.boats_can_touch
|
||||||
&& self.0[boat_i]
|
&& self.0[boat_i]
|
||||||
.neighbor_coordinates(&rules)
|
.neighbor_coordinates(rules)
|
||||||
.iter()
|
.iter()
|
||||||
.any(|c| boat_j_coords.contains(c))
|
.any(|c| boat_j_coords.contains(c))
|
||||||
{
|
{
|
||||||
@ -263,7 +263,6 @@ mod test {
|
|||||||
use crate::data::boats_layout::{BoatDirection, BoatPosition, BoatsLayout, Coordinates};
|
use crate::data::boats_layout::{BoatDirection, BoatPosition, BoatsLayout, Coordinates};
|
||||||
use crate::data::game_map::GameMap;
|
use crate::data::game_map::GameMap;
|
||||||
use crate::data::{BotType, GameRules, PlayConfiguration};
|
use crate::data::{BotType, GameRules, PlayConfiguration};
|
||||||
use crate::game::Game;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_boat_coordinates() {
|
fn get_boat_coordinates() {
|
||||||
@ -317,13 +316,23 @@ mod test {
|
|||||||
game.print_map();
|
game.print_map();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generate_random_boats_layout_without_touching_boats() {
|
||||||
|
let mut rules = GameRules::random_players_rules();
|
||||||
|
rules.boats_can_touch = false;
|
||||||
|
let boats = BoatsLayout::gen_random_for_rules(&rules).unwrap();
|
||||||
|
assert!(boats.errors(&rules).is_empty());
|
||||||
|
let game = GameMap::new(rules, boats);
|
||||||
|
game.print_map();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn impossible_map() {
|
fn impossible_map() {
|
||||||
let mut rules = GameRules::random_players_rules();
|
let mut rules = GameRules::random_players_rules();
|
||||||
rules.map_height = PlayConfiguration::default().min_map_height;
|
rules.map_height = PlayConfiguration::default().min_map_height;
|
||||||
rules.map_width = PlayConfiguration::default().min_map_width;
|
rules.map_width = PlayConfiguration::default().min_map_width;
|
||||||
let mut boats = Vec::new();
|
let mut boats = Vec::new();
|
||||||
for i in 0..PlayConfiguration::default().max_boats_number {
|
for _i in 0..PlayConfiguration::default().max_boats_number {
|
||||||
boats.push(PlayConfiguration::default().max_boat_len);
|
boats.push(PlayConfiguration::default().max_boat_len);
|
||||||
}
|
}
|
||||||
rules.set_boats_list(&boats);
|
rules.set_boats_list(&boats);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::data::boats_layout::{BoatsLayout, Coordinates};
|
use crate::data::boats_layout::{BoatsLayout, Coordinates};
|
||||||
use crate::data::GameRules;
|
use crate::data::GameRules;
|
||||||
|
|
||||||
enum MapCellContent {
|
pub enum MapCellContent {
|
||||||
Invalid,
|
Invalid,
|
||||||
Nothing,
|
Nothing,
|
||||||
TouchedBoat,
|
TouchedBoat,
|
||||||
@ -41,7 +41,7 @@ impl GameMap {
|
|||||||
return MapCellContent::Boat;
|
return MapCellContent::Boat;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MapCellContent::Nothing;
|
MapCellContent::Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_map(&self) {
|
pub fn print_map(&self) {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
pub use boats_layout::*;
|
||||||
|
pub use game_map::*;
|
||||||
pub use game_rules::*;
|
pub use game_rules::*;
|
||||||
pub use play_config::*;
|
pub use play_config::*;
|
||||||
|
|
||||||
|
61
src/game.rs
61
src/game.rs
@ -1,16 +1,29 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::data::GameRules;
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use actix::{Actor, Context, Handler};
|
use actix::{Actor, Context, Handler};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::data::{BoatsLayout, GameMap, GameRules};
|
||||||
|
|
||||||
pub trait Player {
|
pub trait Player {
|
||||||
fn get_name(&self) -> &str;
|
fn get_name(&self) -> &str;
|
||||||
|
|
||||||
fn get_uid(&self) -> Uuid;
|
fn get_uid(&self) -> Uuid;
|
||||||
|
|
||||||
fn query_boats_layout(&self, rules: &GameRules);
|
fn query_boats_layout(&self, rules: &GameRules);
|
||||||
|
|
||||||
|
fn notify_other_player_ready(&self);
|
||||||
|
|
||||||
|
fn notify_game_starting(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opponent(index: usize) -> usize {
|
||||||
|
match index {
|
||||||
|
0 => 1,
|
||||||
|
1 => 0,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Eq, PartialEq, Debug, Copy, Clone)]
|
#[derive(Default, Eq, PartialEq, Debug, Copy, Clone)]
|
||||||
@ -18,12 +31,15 @@ enum GameStatus {
|
|||||||
#[default]
|
#[default]
|
||||||
Created,
|
Created,
|
||||||
WaitingForBoatsDisposition,
|
WaitingForBoatsDisposition,
|
||||||
|
Started,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
rules: GameRules,
|
rules: GameRules,
|
||||||
players: Vec<Arc<dyn Player>>,
|
players: Vec<Arc<dyn Player>>,
|
||||||
status: GameStatus,
|
status: GameStatus,
|
||||||
|
map_0: Option<GameMap>,
|
||||||
|
map_1: Option<GameMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
@ -32,9 +48,21 @@ impl Game {
|
|||||||
rules,
|
rules,
|
||||||
players: vec![],
|
players: vec![],
|
||||||
status: GameStatus::Created,
|
status: GameStatus::Created,
|
||||||
|
map_0: None,
|
||||||
|
map_1: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find the ID of a player from its UUID
|
||||||
|
fn player_id_by_uuid(&self, uuid: Uuid) -> usize {
|
||||||
|
self.players
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|p| p.1.get_uid() == uuid)
|
||||||
|
.expect("Player is not member of this game!")
|
||||||
|
.0
|
||||||
|
}
|
||||||
|
|
||||||
/// Once the two player has been registered, the game may start
|
/// Once the two player has been registered, the game may start
|
||||||
fn query_boats_disposition(&mut self) {
|
fn query_boats_disposition(&mut self) {
|
||||||
assert_eq!(self.status, GameStatus::Created);
|
assert_eq!(self.status, GameStatus::Created);
|
||||||
@ -42,6 +70,11 @@ impl Game {
|
|||||||
self.players[0].query_boats_layout(&self.rules);
|
self.players[0].query_boats_layout(&self.rules);
|
||||||
self.players[1].query_boats_layout(&self.rules);
|
self.players[1].query_boats_layout(&self.rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start fires exchange
|
||||||
|
fn start_fire_exchanges(&mut self) {
|
||||||
|
self.status = GameStatus::Started;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Actor for Game {
|
impl Actor for Game {
|
||||||
@ -68,3 +101,29 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct SetBoatsLayout(pub Uuid, pub BoatsLayout);
|
||||||
|
|
||||||
|
impl Handler<SetBoatsLayout> for Game {
|
||||||
|
type Result = ();
|
||||||
|
|
||||||
|
/// Receive game configuration of a player
|
||||||
|
fn handle(&mut self, msg: SetBoatsLayout, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
assert_eq!(self.status, GameStatus::WaitingForBoatsDisposition);
|
||||||
|
let player_index = self.player_id_by_uuid(msg.0);
|
||||||
|
match player_index {
|
||||||
|
0 => self.map_0 = Some(GameMap::new(self.rules.clone(), msg.1)),
|
||||||
|
1 => self.map_1 = Some(GameMap::new(self.rules.clone(), msg.1)),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.players[opponent(player_index)].notify_other_player_ready();
|
||||||
|
|
||||||
|
if self.map_0.is_some() && self.map_1.is_some() {
|
||||||
|
self.players.iter().for_each(|p| p.notify_game_starting());
|
||||||
|
self.start_fire_exchanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -26,6 +26,14 @@ impl Player for HumanPlayer {
|
|||||||
rules: rules.clone(),
|
rules: rules.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn notify_other_player_ready(&self) {
|
||||||
|
self.player.do_send(ServerMessage::OtherPlayerReady);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn notify_game_starting(&self) {
|
||||||
|
self.player.do_send(ServerMessage::GameStarting);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HumanPlayer {
|
impl HumanPlayer {
|
||||||
|
@ -34,6 +34,7 @@ pub enum ServerMessage {
|
|||||||
QueryBoatsLayout { rules: GameRules },
|
QueryBoatsLayout { rules: GameRules },
|
||||||
WaitingForOtherPlayerConfiguration,
|
WaitingForOtherPlayerConfiguration,
|
||||||
OtherPlayerReady,
|
OtherPlayerReady,
|
||||||
|
GameStarting,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::data::GameRules;
|
|
||||||
use actix::Addr;
|
use actix::Addr;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::game::{Game, Player};
|
use crate::data::{BoatsLayout, GameRules};
|
||||||
|
use crate::game::{Game, Player, SetBoatsLayout};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RandomBot {
|
pub struct RandomBot {
|
||||||
@ -29,6 +29,17 @@ impl Player for RandomBot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn query_boats_layout(&self, rules: &GameRules) {
|
fn query_boats_layout(&self, rules: &GameRules) {
|
||||||
log::info!("Player requested boats configuration!");
|
match BoatsLayout::gen_random_for_rules(rules) {
|
||||||
|
Ok(layout) => self.game.do_send(SetBoatsLayout(self.uuid, layout)),
|
||||||
|
|
||||||
|
Err(e) => log::error!(
|
||||||
|
"Failed to use game rules to construct boats layout: {:?}",
|
||||||
|
e
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn notify_other_player_ready(&self) {}
|
||||||
|
|
||||||
|
fn notify_game_starting(&self) {}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user