From f9b45845be9ac62645b6afb08fc5dd3e46420965 Mon Sep 17 00:00:00 2001 From: Mollemoll Date: Sun, 26 May 2024 20:23:13 +0200 Subject: [PATCH] refactor: initial structure --- src/errors.rs | 5 + src/game.rs | 331 ++-------------------------------------------- src/game/lobby.rs | 322 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 4 files changed, 341 insertions(+), 318 deletions(-) create mode 100644 src/errors.rs create mode 100644 src/game/lobby.rs diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..ff39894 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,5 @@ +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum GameError { + RequiresFourReadyPlayers, + UnbalancedTeams, +} diff --git a/src/game.rs b/src/game.rs index c92a640..278212e 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,4 +1,7 @@ use crate::user::User; +use crate::game::lobby::Lobby; + +mod lobby; #[derive(Debug, PartialEq, Eq, Clone, Copy)] struct Settings { @@ -42,113 +45,8 @@ struct Game { } impl Game { - fn new(settings: Settings) -> GameLobby<'static> { - GameLobby { settings, players: Vec::new() } - } -} - - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum GameError { - RequiresFourReadyPlayers, - UnbalancedTeams, -} - -#[derive(Debug, PartialEq)] -struct GameLobby<'a> { - settings: Settings, - players: Vec>, -} - -impl<'a> GameLobby<'a> { - fn add_user(&mut self, user: &'a User) { - // Create player - let player = Player::build( - &user, - self.team_to_assign_to() - ); - - // Deny player if already in the game - if self.players.iter() - .any(|p| &p.user() == &user) { - return; - } - - // Deny player if there are already 4 players - if self.players.len() == 4 { - return; - } - - self.players.push(player); - } - - fn del_user(&mut self, user: &'a User) { - self.players.retain(|p| &p.user() != &user); - } - - fn change_team(&mut self, user: &'a User, team: Team) { - if let Some(player) = self.players - .iter_mut() - .find(|p| p.user() == user) { - player.team = team; - } - } - - fn ready_up(&mut self, user: &'a User) { - if let Some(player) = self.players - .iter_mut() - .find(|p| p.user() == user) { - player.ready = true; - } - } - - fn unready(&mut self, user: &'a User) { - if let Some(player) = self.players - .iter_mut() - .find(|p| p.user() == user) { - player.ready = false; - } - } - - fn ready_count(&self) -> usize { - self.players.iter() - .filter(|p| p.ready == true) - .count() - } - - fn balanced_teams(&self) -> bool { - let team_count = self.players.iter() - .fold((0, 0), |(lajvarna, gottarna), p| { - match p.team { - Team::Lajvarna => (lajvarna + 1, gottarna), - Team::Gottarna => (lajvarna, gottarna + 1), - } - }); - - team_count.0 == 2 && team_count.1 == 2 - } - - fn team_to_assign_to(&mut self) -> Team { - let count_lajvarna = self.players.iter().filter(|p| p.team == Team::Lajvarna).count(); - let count_gottarna = self.players.iter().filter(|p| p.team == Team::Gottarna).count(); - - if count_lajvarna <= count_gottarna { - Team::Lajvarna - } else { - Team::Gottarna - } - } - - fn start_game(&self) -> Result { - if self.ready_count() != 4 { - return Err(GameError::RequiresFourReadyPlayers); - } - - if !self.balanced_teams() { - return Err(GameError::UnbalancedTeams); - } - - Ok(BidRound::new(self.settings)) + fn new(settings: Settings) -> Lobby<'static> { + Lobby { settings, players: Vec::new() } } } @@ -165,227 +63,24 @@ impl BidRound { } } - #[cfg(test)] mod tests { use super::*; - fn setup_game() -> GameLobby<'static> { - let settings = Settings { to_win: 13 }; - Game::new(settings) - } - #[test] - fn new_game_return_game_lobby() { + fn new_game_returns_a_lobby() { let settings = Settings { to_win: 13 }; - let game_lobby = Game::new(settings); - - assert_eq!( - game_lobby, - GameLobby { settings, players: Vec::new() } - ); - } + let game = Game::new(settings); - #[test] - fn add_user_to_lobby() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - - game_lobby.add_user(&user); - - assert_eq!(game_lobby.players.len(), 1); + assert_eq!(game, Lobby { settings, players: Vec::new() }); } #[test] - fn game_lobby_denies_player_joining_twice() { - let mut game_lobby = setup_game(); + fn build_player() { let user = User::new("John Doe"); + let player = Player::build(&user, Team::Lajvarna); - game_lobby.add_user(&user); - game_lobby.add_user(&user); - - assert_eq!(game_lobby.players.len(), 1); + assert_eq!(player.user().name(), "John Doe"); + assert_eq!(player.team(), Team::Lajvarna); } - - #[test] - fn game_accepts_user_leaving() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - let user2 = User::new("Jane Doe"); - - game_lobby.add_user(&user); - game_lobby.add_user(&user2); - game_lobby.del_user(&user); - - assert_eq!(game_lobby.players.len(), 1); - } - - - #[test] - fn game_lobby_denies_user_leaving_twice() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - let user2 = User::new("Jane Doe"); - - game_lobby.add_user(&user); - game_lobby.add_user(&user2); - game_lobby.del_user(&user); - game_lobby.del_user(&user); - - assert_eq!(game_lobby.players.len(), 1); - } - - #[test] - fn users_gets_assigned_to_teams() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - let user2 = User::new("Jane Doe"); - let user3 = User::new("Dolly"); - let user4 = User::new("Phil"); - - game_lobby.add_user(&user); - game_lobby.add_user(&user2); - game_lobby.add_user(&user3); - game_lobby.add_user(&user4); - - assert_eq!(game_lobby.balanced_teams(), true); - } - - #[test] - fn game_lobby_denies_5th_player() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - let user2 = User::new("Jane Doe"); - let user3 = User::new("Dolly"); - let user4 = User::new("Phil"); - let user5 = User::new("John Johnson"); - - game_lobby.add_user(&user); - game_lobby.add_user(&user2); - game_lobby.add_user(&user3); - game_lobby.add_user(&user4); - game_lobby.add_user(&user5); - - assert_eq!(game_lobby.players.len(), 4); - assert_eq!(game_lobby.players.iter().any(|p| p.user == &user5), false); - } - - - #[test] - fn player_can_change_team() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - - game_lobby.add_user(&user); - game_lobby.change_team(&user, Team::Gottarna); - - assert_eq!( - game_lobby.players.iter() - .any(|p| p.user == &user && p.team == Team::Gottarna), - true - ); - } - - #[test] - fn player_can_ready_up() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - - game_lobby.add_user(&user); - game_lobby.ready_up(&user); - - assert_eq!(game_lobby.ready_count(), 1); - } - - #[test] - fn readying_up_twice_doesnt_change_anything() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - - game_lobby.add_user(&user); - game_lobby.ready_up(&user); - game_lobby.ready_up(&user); - - assert_eq!(game_lobby.ready_count(), 1); - } - - #[test] - fn player_can_unready() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - let user2 = User::new("Jane Doe"); - - game_lobby.add_user(&user); - game_lobby.add_user(&user2); - game_lobby.ready_up(&user); - game_lobby.ready_up(&user2); - game_lobby.unready(&user); - - assert_eq!(game_lobby.ready_count(), 1); - } - - #[test] - fn starting_requires_four_ready_players() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - let user2 = User::new("Jane Doe"); - let user3 = User::new("Dolly"); - - game_lobby.add_user(&user); - game_lobby.add_user(&user2); - game_lobby.add_user(&user3); - game_lobby.ready_up(&user); - game_lobby.ready_up(&user2); - game_lobby.ready_up(&user3); - - assert_eq!(game_lobby.start_game(), Err(GameError::RequiresFourReadyPlayers)); - } - - #[test] - fn game_cant_start_with_unbalanced_teams() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - let user2 = User::new("Jane Doe"); - let user3 = User::new("Dolly"); - let user4 = User::new("Homer"); - - game_lobby.add_user(&user); - game_lobby.add_user(&user2); - game_lobby.add_user(&user3); - game_lobby.add_user(&user4); - game_lobby.change_team(&user4, Team::Lajvarna); - game_lobby.ready_up(&user); - game_lobby.ready_up(&user2); - game_lobby.ready_up(&user3); - game_lobby.ready_up(&user4); - - assert_eq!(game_lobby.start_game(), Err(GameError::UnbalancedTeams)); - } - - #[test] - fn game_can_start_with_four_ready_players() { - let mut game_lobby = setup_game(); - let user = User::new("John Doe"); - let user2 = User::new("Jane Doe"); - let user3 = User::new("Dolly"); - let user4 = User::new("Homer"); - - game_lobby.add_user(&user); - game_lobby.add_user(&user2); - game_lobby.add_user(&user3); - game_lobby.add_user(&user4); - game_lobby.ready_up(&user); - game_lobby.ready_up(&user2); - game_lobby.ready_up(&user3); - game_lobby.ready_up(&user4); - - assert_eq!( - game_lobby.start_game().unwrap(), - BidRound { - settings: Settings { to_win: 13 }, - // TODO(2024-05-25 mollemoll): fix move players - players: vec![] - } - ); - } -} \ No newline at end of file +} diff --git a/src/game/lobby.rs b/src/game/lobby.rs new file mode 100644 index 0000000..cc4d422 --- /dev/null +++ b/src/game/lobby.rs @@ -0,0 +1,322 @@ +use crate::errors::GameError; +use crate::game::{BidRound, Player, Settings, Team}; +use crate::user::User; + +#[derive(Debug, PartialEq)] +pub(crate) struct Lobby<'a> { + pub(crate) settings: Settings, + pub(crate) players: Vec>, +} + +impl<'a> Lobby<'a> { + fn add_user(&mut self, user: &'a User) { + // Create player + let player = Player::build( + &user, + self.team_to_assign_to() + ); + + // Deny player if already in the game + if self.players.iter() + .any(|p| &p.user() == &user) { + return; + } + + // Deny player if there are already 4 players + if self.players.len() == 4 { + return; + } + + self.players.push(player); + } + + fn del_user(&mut self, user: &'a User) { + self.players.retain(|p| &p.user() != &user); + } + + fn change_team(&mut self, user: &'a User, team: Team) { + if let Some(player) = self.players + .iter_mut() + .find(|p| p.user() == user) { + player.team = team; + } + } + + fn ready_up(&mut self, user: &'a User) { + if let Some(player) = self.players + .iter_mut() + .find(|p| p.user() == user) { + player.ready = true; + } + } + + fn unready(&mut self, user: &'a User) { + if let Some(player) = self.players + .iter_mut() + .find(|p| p.user() == user) { + player.ready = false; + } + } + + fn ready_count(&self) -> usize { + self.players.iter() + .filter(|p| p.ready == true) + .count() + } + + fn balanced_teams(&self) -> bool { + let team_count = self.players.iter() + .fold((0, 0), |(lajvarna, gottarna), p| { + match p.team { + Team::Lajvarna => (lajvarna + 1, gottarna), + Team::Gottarna => (lajvarna, gottarna + 1), + } + }); + + team_count.0 == 2 && team_count.1 == 2 + } + + fn team_to_assign_to(&mut self) -> Team { + let count_lajvarna = self.players.iter() + .filter(|p| p.team == Team::Lajvarna).count(); + let count_gottarna = self.players.iter() + .filter(|p| p.team == Team::Gottarna).count(); + + if count_lajvarna <= count_gottarna { + Team::Lajvarna + } else { + Team::Gottarna + } + } + + fn start_game(&self) -> Result { + if self.ready_count() != 4 { + return Err(GameError::RequiresFourReadyPlayers); + } + + if !self.balanced_teams() { + return Err(GameError::UnbalancedTeams); + } + + Ok(BidRound::new(self.settings)) + } +} + + + +#[cfg(test)] +mod tests { + use crate::game::{Game, Settings, Team}; + use super::*; + + fn setup_game() -> Lobby<'static> { + let settings = Settings { to_win: 13 }; + Game::new(settings) + } + + #[test] + fn accepts_user_joining() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + + game_lobby.add_user(&user); + + assert_eq!(game_lobby.players.len(), 1); + } + + #[test] + fn denies_player_joining_twice() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + + game_lobby.add_user(&user); + game_lobby.add_user(&user); + + assert_eq!(game_lobby.players.len(), 1); + } + + #[test] + fn accepts_user_leaving() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + let user2 = User::new("Jane Doe"); + + game_lobby.add_user(&user); + game_lobby.add_user(&user2); + game_lobby.del_user(&user); + + assert_eq!(game_lobby.players.len(), 1); + } + + + #[test] + fn denies_user_leaving_twice() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + let user2 = User::new("Jane Doe"); + + game_lobby.add_user(&user); + game_lobby.add_user(&user2); + game_lobby.del_user(&user); + game_lobby.del_user(&user); + + assert_eq!(game_lobby.players.len(), 1); + } + + #[test] + fn assigning_users_evenly_between_teams() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + let user2 = User::new("Jane Doe"); + let user3 = User::new("Dolly"); + let user4 = User::new("Phil"); + + game_lobby.add_user(&user); + game_lobby.add_user(&user2); + game_lobby.add_user(&user3); + game_lobby.add_user(&user4); + + assert_eq!(game_lobby.balanced_teams(), true); + } + + #[test] + fn denies_5th_player() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + let user2 = User::new("Jane Doe"); + let user3 = User::new("Dolly"); + let user4 = User::new("Phil"); + let user5 = User::new("John Johnson"); + + game_lobby.add_user(&user); + game_lobby.add_user(&user2); + game_lobby.add_user(&user3); + game_lobby.add_user(&user4); + game_lobby.add_user(&user5); + + assert_eq!(game_lobby.players.len(), 4); + assert_eq!(game_lobby.players.iter().any(|p| p.user == &user5), false); + } + + + #[test] + fn allowing_players_to_change_team() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + + game_lobby.add_user(&user); + game_lobby.change_team(&user, Team::Gottarna); + + assert_eq!( + game_lobby.players.iter() + .any(|p| p.user == &user && p.team == Team::Gottarna), + true + ); + } + + #[test] + fn player_can_ready_up() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + + game_lobby.add_user(&user); + game_lobby.ready_up(&user); + + assert_eq!(game_lobby.ready_count(), 1); + } + + #[test] + fn readying_up_twice_doesnt_change_anything() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + + game_lobby.add_user(&user); + game_lobby.ready_up(&user); + game_lobby.ready_up(&user); + + assert_eq!(game_lobby.ready_count(), 1); + } + + #[test] + fn player_can_unready() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + let user2 = User::new("Jane Doe"); + + game_lobby.add_user(&user); + game_lobby.add_user(&user2); + game_lobby.ready_up(&user); + game_lobby.ready_up(&user2); + game_lobby.unready(&user); + + assert_eq!(game_lobby.ready_count(), 1); + } + + #[test] + fn starting_requires_four_ready_players() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + let user2 = User::new("Jane Doe"); + let user3 = User::new("Dolly"); + + game_lobby.add_user(&user); + game_lobby.add_user(&user2); + game_lobby.add_user(&user3); + game_lobby.ready_up(&user); + game_lobby.ready_up(&user2); + game_lobby.ready_up(&user3); + + assert_eq!(game_lobby.start_game(), Err(GameError::RequiresFourReadyPlayers)); + } + + #[test] + fn cant_start_with_unbalanced_teams() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + let user2 = User::new("Jane Doe"); + let user3 = User::new("Dolly"); + let user4 = User::new("Homer"); + + game_lobby.add_user(&user); + game_lobby.add_user(&user2); + game_lobby.add_user(&user3); + game_lobby.add_user(&user4); + game_lobby.change_team(&user, Team::Lajvarna); + game_lobby.change_team(&user2, Team::Gottarna); + game_lobby.change_team(&user3, Team::Lajvarna); + game_lobby.change_team(&user4, Team::Lajvarna); + game_lobby.ready_up(&user); + game_lobby.ready_up(&user2); + game_lobby.ready_up(&user3); + game_lobby.ready_up(&user4); + + assert_eq!(game_lobby.start_game(), Err(GameError::UnbalancedTeams)); + } + + #[test] + fn can_start_with_four_ready_players() { + let mut game_lobby = setup_game(); + let user = User::new("John Doe"); + let user2 = User::new("Jane Doe"); + let user3 = User::new("Dolly"); + let user4 = User::new("Homer"); + + game_lobby.add_user(&user); + game_lobby.add_user(&user2); + game_lobby.add_user(&user3); + game_lobby.add_user(&user4); + game_lobby.ready_up(&user); + game_lobby.ready_up(&user2); + game_lobby.ready_up(&user3); + game_lobby.ready_up(&user4); + + assert_eq!( + game_lobby.start_game().unwrap(), + BidRound { + settings: Settings { to_win: 13 }, + // TODO(2024-05-25 mollemoll): fix move players + players: vec![] + } + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index d81e420..709e245 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod user; mod game; +mod errors;