From 8d005065f6e6f772b0d33b93c3227898e6fd74e0 Mon Sep 17 00:00:00 2001 From: bel Date: Wed, 6 May 2020 07:28:54 -0600 Subject: [PATCH] Refacotr to small files dedicated to gamemaster sub ops --- secert-hitler/src/config.rs | 8 + .../src/controller/gamemaster/gameevent.rs | 7 +- .../src/controller/gamemaster/gamemaster.rs | 339 ------------------ .../controller/gamemaster/gamemaster/game.rs | 56 +++ .../gamemaster/gamemaster/gamemaster.rs | 98 +++++ .../controller/gamemaster/gamemaster/lobby.rs | 81 +++++ .../controller/gamemaster/gamemaster/mod.rs | 4 + .../controller/gamemaster/gamemaster/setup.rs | 181 ++++++++++ .../src/controller/gamemaster/mod.rs | 2 + .../src/controller/gamemaster/policy.rs | 37 ++ .../src/controller/gamemaster/rand.rs | 47 +++ 11 files changed, 518 insertions(+), 342 deletions(-) delete mode 100644 secert-hitler/src/controller/gamemaster/gamemaster.rs create mode 100644 secert-hitler/src/controller/gamemaster/gamemaster/game.rs create mode 100644 secert-hitler/src/controller/gamemaster/gamemaster/gamemaster.rs create mode 100644 secert-hitler/src/controller/gamemaster/gamemaster/lobby.rs create mode 100644 secert-hitler/src/controller/gamemaster/gamemaster/mod.rs create mode 100644 secert-hitler/src/controller/gamemaster/gamemaster/setup.rs create mode 100644 secert-hitler/src/controller/gamemaster/policy.rs create mode 100644 secert-hitler/src/controller/gamemaster/rand.rs diff --git a/secert-hitler/src/config.rs b/secert-hitler/src/config.rs index a0330dd..a08dabc 100644 --- a/secert-hitler/src/config.rs +++ b/secert-hitler/src/config.rs @@ -13,3 +13,11 @@ pub fn players_to_facists(n: usize) -> Result { _ => Err("unsupported number of players".to_string()), } } + +pub fn players_to_policies_facist(n: usize) -> usize { + 11 - (n-5)/2 +} + +pub fn players_to_policies_liberal(_: usize) -> usize { + 6 +} diff --git a/secert-hitler/src/controller/gamemaster/gameevent.rs b/secert-hitler/src/controller/gamemaster/gameevent.rs index 27625dc..a703ee4 100644 --- a/secert-hitler/src/controller/gamemaster/gameevent.rs +++ b/secert-hitler/src/controller/gamemaster/gameevent.rs @@ -15,6 +15,7 @@ pub enum GameEventType { ElectionPend, ElectionSet, VoteSet, + VoteFailed, CardPend, CardPick, PolicySet, @@ -26,7 +27,7 @@ pub enum GameEventType { } impl GameEventType { - fn from_string(s: String) -> GameEventType { + pub fn from_string(s: String) -> GameEventType { let cases = vec![ GameEventType::Null, GameEventType::GameStart, @@ -51,7 +52,7 @@ impl GameEventType { GameEventType::Null } - fn build(&self) -> GameEvent { + pub fn build(&self) -> GameEvent { let d = json::object!{ "body": json::object!{ GameEventType: format!("{:?}", self), @@ -103,7 +104,7 @@ impl GameEvent { self.str_vec("params") } - fn str_vec(&self, key: &str) -> Vec { + pub fn str_vec(&self, key: &str) -> Vec { let mut out = vec![]; if self.d[key].is_string() { out.push(self.d[key].as_str().unwrap().to_string()); diff --git a/secert-hitler/src/controller/gamemaster/gamemaster.rs b/secert-hitler/src/controller/gamemaster/gamemaster.rs deleted file mode 100644 index b24642f..0000000 --- a/secert-hitler/src/controller/gamemaster/gamemaster.rs +++ /dev/null @@ -1,339 +0,0 @@ -use super::super::super::model::state::room::Room; -use super::super::super::config; -use super::lobby::Lobby; -use super::player::Player; -use super::gameevent::GameEvent; -use super::gameevent::GameEventType; -use super::role::Role; - -use std::thread; -use std::time; -use log::{info, debug, error, LevelFilter}; -use rand::{self, Rng}; - -pub struct GameMaster { - room: Box, - lobby: Lobby, - candidate_presidents: Vec, -} - -impl GameMaster { - pub fn new(room: Box) -> GameMaster { - info!("created for room {}", room.room_id()); - GameMaster{ - room: room, - lobby: Lobby::new(), - candidate_presidents: vec![], - } - } - - pub fn run(&mut self) -> Result { - loop { - let r = self.run_lobby(); - if r.is_ok() { - break - } - error!("error running lobby: {:?}", r); - } - self.run_game_setup()?; - self.run_game() - } - - fn run_lobby(&mut self) -> Result { - loop { - let r = self.run_lobby_scrape().clone(); - if r.clone().is_err() { - return r; - } - if r.clone().unwrap_or(0) != 0 { - return r; - } - thread::sleep(time::Duration::new(1, 0)); - } - } - - fn run_lobby_scrape(&mut self) -> Result { - debug!("run_lobby_scrape:"); - let events = self.room.sync(); - for e in &events { - let ge = GameEvent::new(e.clone()); - debug!("run_lobby_scrape: ge: {:?}", ge); - if ge.mode() == GameEventType::GameStart { - self.room.rollback(e.since.clone()); - self.lobby.lock(); - return self.lobby.ready(); - } - self.lobby.eat(e.clone()); - } - return self.lobby.ready(); - } - - fn run_game_setup(&mut self) -> Result { - self.setup_gather_candidates()?; - debug!("players: {:?}", self.candidate_presidents); - self.setup_set_roles()?; - debug!("/players: {:?}", self.candidate_presidents); - self.setup_order_candidates()?; - debug!("/players: {:?}", self.candidate_presidents); - Ok("ok".to_string()) - } - - fn run_game(&mut self) -> Result { - Err("not impl".to_string()) - } - - fn players(&self) -> Vec { - let mut players = vec![]; - for k in self.lobby.players.keys() { - players.push(k.clone()); - } - players - } - - fn player(&mut self, id: String) -> Option<&mut Player> { - self.lobby.players.get_mut(&id) - } - - fn setup_gather_candidates(&mut self) -> Result { - for player in self.players() { - let p = self.player(player.clone()); - if p.is_none() { - return Err(format!("missing player {}", player)); - } - self.candidate_presidents.push(player.clone()); - debug!("player = {}", player); - } - Ok("ok".to_string()) - } - - fn setup_set_roles(&mut self) -> Result { - for player in self.players() { - self.player(player.clone()).unwrap().set_role(Role::Liberal); - } - let n = config::players_to_facists(self.players().len())?; - for i in 0..n { - debug!("picking facist {}/{} for {} players", i, n, self.players().len()); - loop { - let j = rand_usize(self.players().len()); - let id = self.candidate_presidents[j].clone(); - let player = self.player(id.clone()).unwrap(); - if player.get_role() != Role::Liberal { - continue; - } - let role = match i { - 0 => Role::Hitler, - _ => Role::Facist, - }; - player.set_role(role); - break; - } - } - Ok("ok".to_string()) - } - - fn setup_order_candidates(&mut self) -> Result { - shuffle(&mut self.candidate_presidents); - let n = self.candidate_presidents.len(); - for _ in 0..5 { - for i in 0..n { - self.candidate_presidents.push(self.candidate_presidents[i].clone()); - } - } - Ok("ok".to_string()) - } -} - -fn shuffle(v: &mut Vec) { - for _ in 0..v.len()*2 { - let a = rand_usize(v.len()); - let b = rand_usize(v.len()); - let t: T = v[a].clone(); - v[a] = v[b].clone(); - v[b] = t.clone(); - } -} - -fn rand_usize(n: usize) -> usize { - rand::thread_rng().gen_range(0, n) -} - -#[cfg(test)] -mod tests { - use super::*; - use super::super::super::super::model::state::mockroom::MockRoom; - use super::super::super::super::model::state::mockrooms::MockRooms; - use super::super::super::super::model::state::rooms::Rooms; - use std::collections::HashMap; - - fn init() { - let _ = env_logger::builder() - .is_test(true) - .filter_level(LevelFilter::Trace) - .try_init(); - } - - #[test] - fn _rand_usize() { - init(); - let mut unique: HashMap = HashMap::new(); - for _ in 0..100 { - unique.insert(rand_usize(100), true); - } - assert!(unique.len() > 1); - } - - #[test] - fn _shuffle() { - init(); - let mut items: Vec = vec![]; - let n: usize = 50; - for i in 0..n { - items.push(i); - } - assert!(items.len() == n); - shuffle(&mut items); - assert!(items.len() == n); - let mut found = false; - for i in 1..items.len() { - found = found || items[i] < items[i-1]; - } - assert!(found); - } - - #[test] - fn new_mockroom() { - let _ = GameMaster::new(Box::new(MockRoom::create())); - } - - #[test] - fn new_rooms_mockrooms() { - fn get() -> impl Rooms { - let mrs = MockRooms::new(); - mrs - } - let mut mrs = get(); - let r = mrs.create(); - let _ = GameMaster::new(r); - } - - #[test] - fn new_mockrooms() { - let mut mrs = MockRooms::new(); - let r = mrs.create(); - let _ = GameMaster::new(r); - } - - #[test] - fn run_lobby() { - init(); - let mut mrs = MockRooms::new(); - let r1 = mrs.create(); - let room_id = r1.room_id(); - let mut gm = GameMaster::new(r1); - for i in 0..config::MIN_PLAYERS-1 { - let mut r2 = mrs.join(room_id.clone()).unwrap(); - r2.send(format!(r#"{{ - "msgtype": "m.text", - "body": "{{\"GameEventType\": \"GameStart\"}}" - }}"#)).unwrap(); - let ready = gm.run_lobby(); - assert!(ready.is_err() == (i != 3), "want {:?} for ready.is_err #{:?}, which is {:?}", i != 3, i, ready.is_err()); - } - assert!(gm.lobby.players.len() == 5, "first run_lobby players: {:?}, sync: {:?}", gm.lobby.players, gm.room.sync()); - let mut players1 = vec![]; - for k in gm.lobby.players.keys() { - players1.push(k.clone()); - } - assert!(gm.run_lobby().is_ok()); - assert!(gm.lobby.players.len() == 5, "secnd run_lobby players: {:?}, sync: {:?}", gm.lobby.players, gm.room.sync()); - let players2 = gm.lobby.players.keys(); - assert!(format!("{:?}", players1) == format!("{:?}", players2)); - } - - #[test] - fn run_game_setup() { - init(); - let mut mrs = MockRooms::new(); - let r1 = mrs.create(); - let mut gm = GameMaster::new(r1); - let r = gm.run_game_setup(); - assert!(!r.is_ok()); - for i in 0..config::MIN_PLAYERS { - let id = format!("{}", i); - gm.lobby.players.insert(id.clone(), Player::new(id.clone())); - } - let r = gm.run_game_setup(); - assert!(r.is_ok(), "failed to start game after sufficient players joined: {:?}", r); - assert!(gm.candidate_presidents.len() > gm.lobby.players.len()); - } - - #[test] - fn run_game_fail() { - assert!(false, "not impl"); - } - - #[test] - fn setup_gather_candidates() { - init(); - let mut mrs = MockRooms::new(); - let r1 = mrs.create(); - let mut gm = GameMaster::new(r1); - assert!(gm.setup_gather_candidates().is_ok()); - for i in 0..config::MIN_PLAYERS { - let id = format!("{}", i); - gm.lobby.players.insert(id.clone(), Player::new(id.clone())); - } - assert!(gm.setup_gather_candidates().is_ok()); - for i in config::MIN_PLAYERS..config::MAX_PLAYERS+1 { - let id = format!("{}", i); - gm.lobby.players.insert(id.clone(), Player::new(id.clone())); - } - assert!(gm.setup_gather_candidates().is_ok()); - } - - #[test] - fn setup_set_roles() { - init(); - let mut mrs = MockRooms::new(); - let r1 = mrs.create(); - let mut gm = GameMaster::new(r1); - assert!(gm.setup_set_roles().is_err()); - for i in 0..config::MIN_PLAYERS { - let id = format!("{}", i); - gm.lobby.players.insert(id.clone(), Player::new(id.clone())); - gm.candidate_presidents.push(id.clone()); - } - assert!(gm.setup_set_roles().is_ok()); - for i in config::MIN_PLAYERS..config::MAX_PLAYERS+1 { - let id = format!("{}", i); - gm.lobby.players.insert(id.clone(), Player::new(id.clone())); - gm.candidate_presidents.push(id.clone()); - } - assert!(gm.setup_set_roles().is_err()); - } - - #[test] - fn setup_order_candidates() { - init(); - let mut mrs = MockRooms::new(); - let r1 = mrs.create(); - let mut gm = GameMaster::new(r1); - assert!(gm.setup_order_candidates().is_ok()); - gm.candidate_presidents = ["1".to_string()].to_vec(); - assert!(gm.setup_order_candidates().is_ok()); - assert!(gm.candidate_presidents.len() > 1); - gm.candidate_presidents = [].to_vec(); - for i in 0..50 { - gm.candidate_presidents.push(format!("{}", i)); - } - let was = format!("{:?}", gm.candidate_presidents); - assert!(gm.setup_order_candidates().is_ok()); - assert!(gm.candidate_presidents.len() > 50); - assert!(was != format!("{:?}", gm.candidate_presidents)); - let mut found = false; - for i in 1..gm.candidate_presidents.len() { - found = found || gm.candidate_presidents[i] < gm.candidate_presidents[i-1]; - } - assert!(found); - } -} diff --git a/secert-hitler/src/controller/gamemaster/gamemaster/game.rs b/secert-hitler/src/controller/gamemaster/gamemaster/game.rs new file mode 100644 index 0000000..319ecba --- /dev/null +++ b/secert-hitler/src/controller/gamemaster/gamemaster/game.rs @@ -0,0 +1,56 @@ +use super::gamemaster::GameMaster; +use super::super::gameevent::GameEvent; +use super::super::policy::Policy; + +use log::{LevelFilter}; + +impl GameMaster { + pub fn game_is_over(&mut self) -> Result { + Err("not impl".to_string()) + } + + pub fn game_election(&mut self) -> Result { + Err("not impl".to_string()) + } + + pub fn game_election_vote(&mut self) -> Result { + Err("not impl".to_string()) + } + + pub fn game_policy_select_random(&mut self) -> Result { + Err("not impl".to_string()) + } + + pub fn game_policy_select(&mut self) -> Result { + Err("not impl".to_string()) + } + + pub fn game_policy_veto(&mut self, _p: Policy) -> Result { + Err("not impl".to_string()) + } + + pub fn game_ends_with(&mut self, _p: Policy) -> Result { + Err("not impl".to_string()) + } + + pub fn game_policy_enact(&mut self, _p: Policy) -> Result { + Err("not impl".to_string()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn init() { + let _ = env_logger::builder() + .is_test(true) + .filter_level(LevelFilter::Trace) + .try_init(); + } + + #[test] + fn game() { + init(); + } +} diff --git a/secert-hitler/src/controller/gamemaster/gamemaster/gamemaster.rs b/secert-hitler/src/controller/gamemaster/gamemaster/gamemaster.rs new file mode 100644 index 0000000..c201dfb --- /dev/null +++ b/secert-hitler/src/controller/gamemaster/gamemaster/gamemaster.rs @@ -0,0 +1,98 @@ +use super::super::super::super::model::state::room::Room; +use super::super::lobby::Lobby; +use super::super::player::Player; +use super::super::policy::Policy; +use super::super::gameevent::GameEventType; + +use log::{info, error}; + +pub struct GameMaster { + pub room: Box, + pub lobby: Lobby, + pub candidate_presidents: Vec, + pub deck: Vec, +} + +impl GameMaster { + + pub fn new(room: Box) -> GameMaster { + info!("created for room {}", room.room_id()); + GameMaster{ + room: room, + lobby: Lobby::new(), + candidate_presidents: vec![], + deck: vec![], + } + } + + pub fn run(&mut self) -> Result { + loop { + let r = self.run_lobby(); + if r.is_ok() { + break + } + error!("error running lobby: {:?}", r); + } + self.run_game_setup()?; + self.run_game() + } + + pub fn run_game(&mut self) -> Result { + loop { + self.game_is_over()?; + self.game_election()?; + self.game_is_over()?; + let p = match self.game_election_vote().unwrap_or(GameEventType::GameStop.build()).mode() { + GameEventType::VoteFailed => self.game_policy_select_random(), + GameEventType::GameStop => Err("game ended".to_string()), + _ => self.game_policy_select(), + }?; + self.game_policy_veto(p.clone())?; + self.game_ends_with(p.clone())?; + self.game_policy_enact(p.clone())?; // todo facist policies special + } + } + + pub fn players(&self) -> Vec { + let mut players = vec![]; + for k in self.lobby.players.keys() { + players.push(k.clone()); + } + players + } + + pub fn player(&mut self, id: String) -> Option<&mut Player> { + self.lobby.players.get_mut(&id) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use super::super::super::super::super::model::state::mockroom::MockRoom; + use super::super::super::super::super::model::state::mockrooms::MockRooms; + use super::super::super::super::super::model::state::rooms::Rooms; + + #[test] + fn new_mockroom() { + let _ = GameMaster::new(Box::new(MockRoom::create())); + } + + #[test] + fn new_rooms_mockrooms() { + fn get() -> impl Rooms { + let mrs = MockRooms::new(); + mrs + } + let mut mrs = get(); + let r = mrs.create(); + let _ = GameMaster::new(r); + } + + #[test] + fn new_mockrooms() { + let mut mrs = MockRooms::new(); + let r = mrs.create(); + let _ = GameMaster::new(r); + } +} diff --git a/secert-hitler/src/controller/gamemaster/gamemaster/lobby.rs b/secert-hitler/src/controller/gamemaster/gamemaster/lobby.rs new file mode 100644 index 0000000..1cc3ede --- /dev/null +++ b/secert-hitler/src/controller/gamemaster/gamemaster/lobby.rs @@ -0,0 +1,81 @@ +use super::gamemaster::GameMaster; + +use super::super::gameevent::GameEvent; +use super::super::gameevent::GameEventType; + +use std::thread; +use std::time; +use log::{debug, LevelFilter}; + +impl GameMaster { + pub fn run_lobby(&mut self) -> Result { + loop { + let r = self.run_lobby_scrape().clone(); + if r.clone().is_err() { + return r; + } + if r.clone().unwrap_or(0) != 0 { + return r; + } + thread::sleep(time::Duration::new(1, 0)); + } + } + + pub fn run_lobby_scrape(&mut self) -> Result { + debug!("run_lobby_scrape:"); + let events = self.room.sync(); + for e in &events { + let ge = GameEvent::new(e.clone()); + debug!("run_lobby_scrape: ge: {:?}", ge); + if ge.mode() == GameEventType::GameStart { + self.room.rollback(e.since.clone()); + self.lobby.lock(); + return self.lobby.ready(); + } + self.lobby.eat(e.clone()); + } + return self.lobby.ready(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use super::super::super::super::super::model::state::mockrooms::MockRooms; + use super::super::super::super::super::model::state::rooms::Rooms; + use super::super::super::super::super::config; + + fn init() { + let _ = env_logger::builder() + .is_test(true) + .filter_level(LevelFilter::Trace) + .try_init(); + } + + #[test] + fn run_lobby() { + init(); + let mut mrs = MockRooms::new(); + let r1 = mrs.create(); + let room_id = r1.room_id(); + let mut gm = GameMaster::new(r1); + for i in 0..config::MIN_PLAYERS-1 { + let mut r2 = mrs.join(room_id.clone()).unwrap(); + r2.send(format!(r#"{{ + "msgtype": "m.text", + "body": "{{\"GameEventType\": \"GameStart\"}}" + }}"#)).unwrap(); + let ready = gm.run_lobby(); + assert!(ready.is_err() == (i != 3), "want {:?} for ready.is_err #{:?}, which is {:?}", i != 3, i, ready.is_err()); + } + assert!(gm.lobby.players.len() == 5, "first run_lobby players: {:?}, sync: {:?}", gm.lobby.players, gm.room.sync()); + let mut players1 = vec![]; + for k in gm.lobby.players.keys() { + players1.push(k.clone()); + } + assert!(gm.run_lobby().is_ok()); + assert!(gm.lobby.players.len() == 5, "secnd run_lobby players: {:?}, sync: {:?}", gm.lobby.players, gm.room.sync()); + let players2 = gm.lobby.players.keys(); + assert!(format!("{:?}", players1) == format!("{:?}", players2)); + } +} diff --git a/secert-hitler/src/controller/gamemaster/gamemaster/mod.rs b/secert-hitler/src/controller/gamemaster/gamemaster/mod.rs new file mode 100644 index 0000000..fa9bfd8 --- /dev/null +++ b/secert-hitler/src/controller/gamemaster/gamemaster/mod.rs @@ -0,0 +1,4 @@ +pub mod gamemaster; +mod lobby; +mod setup; +mod game; diff --git a/secert-hitler/src/controller/gamemaster/gamemaster/setup.rs b/secert-hitler/src/controller/gamemaster/gamemaster/setup.rs new file mode 100644 index 0000000..45aecbd --- /dev/null +++ b/secert-hitler/src/controller/gamemaster/gamemaster/setup.rs @@ -0,0 +1,181 @@ +use super::gamemaster::GameMaster; + +use super::super::super::super::config; +use super::super::role::Role; +use super::super::policy::Policy; +use super::super::rand::rand_usize; +use super::super::rand::shuffle; + +use log::{debug, LevelFilter}; + +impl GameMaster { + pub fn run_game_setup(&mut self) -> Result { + self.setup_gather_candidates()?; + debug!("players: {:?}", self.candidate_presidents); + self.setup_set_roles()?; + debug!("/players: {:?}", self.candidate_presidents); + self.setup_order_candidates()?; + debug!("/players: {:?}", self.candidate_presidents); + self.setup_deck()?; + Ok("ok".to_string()) + } + + pub fn setup_gather_candidates(&mut self) -> Result { + for player in self.players() { + let p = self.player(player.clone()); + if p.is_none() { + return Err(format!("missing player {}", player)); + } + self.candidate_presidents.push(player.clone()); + debug!("player = {}", player); + } + Ok("ok".to_string()) + } + + pub fn setup_set_roles(&mut self) -> Result { + for player in self.players() { + self.player(player.clone()).unwrap().set_role(Role::Liberal); + } + let n = config::players_to_facists(self.players().len())?; + for i in 0..n { + debug!("picking facist {}/{} for {} players", i, n, self.players().len()); + loop { + let j = rand_usize(self.players().len()); + let id = self.candidate_presidents[j].clone(); + let player = self.player(id.clone()).unwrap(); + if player.get_role() != Role::Liberal { + continue; + } + let role = match i { + 0 => Role::Hitler, + _ => Role::Facist, + }; + player.set_role(role); + break; + } + } + Ok("ok".to_string()) + } + + pub fn setup_order_candidates(&mut self) -> Result { + shuffle(&mut self.candidate_presidents); + let n = self.candidate_presidents.len(); + for _ in 0..5 { + for i in 0..n { + self.candidate_presidents.push(self.candidate_presidents[i].clone()); + } + } + Ok("ok".to_string()) + } + + pub fn setup_deck(&mut self) -> Result { + for _ in 0..config::players_to_policies_facist(self.players().len()) { + self.deck.push(Policy::Facist); + } + + for _ in 0..config::players_to_policies_liberal(self.players().len()) { + self.deck.push(Policy::Liberal); + } + + shuffle(&mut self.deck); + + Ok("deck is loaded".to_string()) + } +} + +mod tests { + use super::*; + use super::super::super::super::super::model::state::mockrooms::MockRooms; + use super::super::super::super::super::model::state::rooms::Rooms; + use super::super::super::player::Player; + + fn init() { + let _ = env_logger::builder() + .is_test(true) + .filter_level(LevelFilter::Trace) + .try_init(); + } + + #[test] + fn run_game_setup() { + init(); + let mut mrs = MockRooms::new(); + let r1 = mrs.create(); + let mut gm = GameMaster::new(r1); + let r = gm.run_game_setup(); + assert!(!r.is_ok()); + for i in 0..config::MIN_PLAYERS { + let id = format!("{}", i); + gm.lobby.players.insert(id.clone(), Player::new(id.clone())); + } + let r = gm.run_game_setup(); + assert!(r.is_ok(), "failed to start game after sufficient players joined: {:?}", r); + assert!(gm.candidate_presidents.len() > gm.lobby.players.len()); + assert!(gm.deck.len() > 1); + } + + #[test] + fn setup_gather_candidates() { + init(); + let mut mrs = MockRooms::new(); + let r1 = mrs.create(); + let mut gm = GameMaster::new(r1); + assert!(gm.setup_gather_candidates().is_ok()); + for i in 0..config::MIN_PLAYERS { + let id = format!("{}", i); + gm.lobby.players.insert(id.clone(), Player::new(id.clone())); + } + assert!(gm.setup_gather_candidates().is_ok()); + for i in config::MIN_PLAYERS..config::MAX_PLAYERS+1 { + let id = format!("{}", i); + gm.lobby.players.insert(id.clone(), Player::new(id.clone())); + } + assert!(gm.setup_gather_candidates().is_ok()); + } + + #[test] + fn setup_set_roles() { + init(); + let mut mrs = MockRooms::new(); + let r1 = mrs.create(); + let mut gm = GameMaster::new(r1); + assert!(gm.setup_set_roles().is_err()); + for i in 0..config::MIN_PLAYERS { + let id = format!("{}", i); + gm.lobby.players.insert(id.clone(), Player::new(id.clone())); + gm.candidate_presidents.push(id.clone()); + } + assert!(gm.setup_set_roles().is_ok()); + for i in config::MIN_PLAYERS..config::MAX_PLAYERS+1 { + let id = format!("{}", i); + gm.lobby.players.insert(id.clone(), Player::new(id.clone())); + gm.candidate_presidents.push(id.clone()); + } + assert!(gm.setup_set_roles().is_err()); + } + + #[test] + fn setup_order_candidates() { + init(); + let mut mrs = MockRooms::new(); + let r1 = mrs.create(); + let mut gm = GameMaster::new(r1); + assert!(gm.setup_order_candidates().is_ok()); + gm.candidate_presidents = ["1".to_string()].to_vec(); + assert!(gm.setup_order_candidates().is_ok()); + assert!(gm.candidate_presidents.len() > 1); + gm.candidate_presidents = [].to_vec(); + for i in 0..50 { + gm.candidate_presidents.push(format!("{}", i)); + } + let was = format!("{:?}", gm.candidate_presidents); + assert!(gm.setup_order_candidates().is_ok()); + assert!(gm.candidate_presidents.len() > 50); + assert!(was != format!("{:?}", gm.candidate_presidents)); + let mut found = false; + for i in 1..gm.candidate_presidents.len() { + found = found || gm.candidate_presidents[i] < gm.candidate_presidents[i-1]; + } + assert!(found); + } +} diff --git a/secert-hitler/src/controller/gamemaster/mod.rs b/secert-hitler/src/controller/gamemaster/mod.rs index bfefc32..758a60d 100644 --- a/secert-hitler/src/controller/gamemaster/mod.rs +++ b/secert-hitler/src/controller/gamemaster/mod.rs @@ -3,3 +3,5 @@ pub mod player; pub mod role; pub mod lobby; pub mod gameevent; +pub mod policy; +pub mod rand; diff --git a/secert-hitler/src/controller/gamemaster/policy.rs b/secert-hitler/src/controller/gamemaster/policy.rs new file mode 100644 index 0000000..816c4e5 --- /dev/null +++ b/secert-hitler/src/controller/gamemaster/policy.rs @@ -0,0 +1,37 @@ +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Policy { + Null, + Facist, + Liberal, +} + +impl Policy { + pub fn new() -> Policy { + Policy::Null + } + + pub fn set(&mut self, policy: Policy) { + *self = policy.clone() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn new_role() { + let _ = Policy::new(); + } + + #[test] + fn set() { + let mut r = Policy::new(); + r.set(Policy::Facist); + assert!(r == Policy::Facist); + + let mut r = Policy::new(); + r.set(Policy::Liberal); + assert!(r == Policy::Liberal); + } +} diff --git a/secert-hitler/src/controller/gamemaster/rand.rs b/secert-hitler/src/controller/gamemaster/rand.rs new file mode 100644 index 0000000..5821690 --- /dev/null +++ b/secert-hitler/src/controller/gamemaster/rand.rs @@ -0,0 +1,47 @@ +use rand::{self, Rng}; + +pub fn shuffle(v: &mut Vec) { + for _ in 0..v.len()*2 { + let a = rand_usize(v.len()); + let b = rand_usize(v.len()); + let t: T = v[a].clone(); + v[a] = v[b].clone(); + v[b] = t.clone(); + } +} + +pub fn rand_usize(n: usize) -> usize { + rand::thread_rng().gen_range(0, n) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashMap; + + #[test] + fn _rand_usize() { + let mut unique: HashMap = HashMap::new(); + for _ in 0..100 { + unique.insert(rand_usize(100), true); + } + assert!(unique.len() > 1); + } + + #[test] + fn _shuffle() { + let mut items: Vec = vec![]; + let n: usize = 50; + for i in 0..n { + items.push(i); + } + assert!(items.len() == n); + shuffle(&mut items); + assert!(items.len() == n); + let mut found = false; + for i in 1..items.len() { + found = found || items[i] < items[i-1]; + } + assert!(found); + } +}