impl game over

master^2
bel 2020-05-06 08:43:56 -06:00
parent 2b8581952e
commit 0347d613df
5 changed files with 186 additions and 37 deletions

View File

@ -1,46 +1,67 @@
use super::gamemaster::GameMaster;
use super::super::gameevent::GameEvent;
use super::super::gameevent::GameEventType;
use super::super::policy::Policy;
use log::{LevelFilter};
use super::super::role::Role;
use super::super::player::Player;
impl GameMaster {
pub fn game_is_over(&mut self) -> Result<GameEvent, String> {
Err("not impl".to_string())
pub fn game_is_over(&mut self) -> Result<GameEvent, Role> {
if self.policies[&Policy::Facist] >= 3 {
let chancellor = self.chancellor.clone();
if chancellor.is_some() {
let player = self.player(chancellor.unwrap());
if player.is_some() && player.unwrap().get_role() == Role::Hitler {
return Err(Role::Facist);
}
}
}
if self.policies[&Policy::Facist] > 5 {
return Err(Role::Facist);
}
if self.policies[&Policy::Liberal] > 5 {
return Err(Role::Liberal);
}
Ok(GameEventType::Null.build())
}
pub fn game_election(&mut self) -> Result<GameEvent, String> {
Err("not impl".to_string())
pub fn game_election(&mut self) -> Result<GameEvent, Role> {
Err(Role::Null)
}
pub fn game_election_vote(&mut self) -> Result<GameEvent, String> {
Err("not impl".to_string())
pub fn game_election_vote(&mut self) -> Result<GameEvent, Role> {
Err(Role::Null)
}
pub fn game_policy_select_random(&mut self) -> Result<Policy, String> {
Err("not impl".to_string())
pub fn game_policy_select_random(&mut self) -> Result<GameEvent, Role> {
Err(Role::Null)
}
pub fn game_policy_select(&mut self) -> Result<Policy, String> {
Err("not impl".to_string())
pub fn game_policy_select(&mut self) -> Result<GameEvent, Role> {
Err(Role::Null)
}
pub fn game_policy_veto(&mut self, _p: Policy) -> Result<GameEvent, String> {
Err("not impl".to_string())
pub fn game_policy_veto(&mut self, _p: Policy) -> Result<GameEvent, Role> {
Err(Role::Null)
}
pub fn game_ends_with(&mut self, _p: Policy) -> Result<GameEvent, String> {
Err("not impl".to_string())
pub fn game_ends_with(&mut self, _p: Policy) -> Result<GameEvent, Role> {
Err(Role::Null)
}
pub fn game_policy_enact(&mut self, _p: Policy) -> Result<GameEvent, String> {
Err("not impl".to_string())
pub fn game_policy_enact(&mut self, _p: Policy) -> Result<GameEvent, Role> {
Err(Role::Null)
}
}
#[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;
use log::{debug, LevelFilter};
fn init() {
let _ = env_logger::builder()
@ -49,8 +70,83 @@ mod tests {
.try_init();
}
#[test]
fn game() {
fn dummy() -> GameMaster {
init();
let mut mrs = MockRooms::new();
let r = mrs.create();
let room_id = r.room_id().clone();
let mut gm = GameMaster::new(r);
for _ in 0..config::MIN_PLAYERS-2 {
assert!(mrs.join(room_id.clone()).is_ok());
}
mrs.join(room_id).unwrap().send(format!(r#"{{
"msgtype": "m.text",
"body": "{{\"GameEventType\": \"GameStart\"}}"
}}"#)).unwrap();
assert!(gm.run_lobby().is_ok());
assert!(gm.run_game_setup().is_ok());
gm
}
#[test]
fn test_dummy() {
let gm = dummy();
assert!(gm.players().len() == config::MIN_PLAYERS);
assert!(config::players_to_policies_facist(gm.players().len()) + config::players_to_policies_liberal(gm.players().len()) == gm.deck.len());
assert!(gm.players().len() < gm.candidate_presidents.len());
assert!(gm.policies[&Policy::Facist] == 0);
assert!(gm.policies[&Policy::Liberal] == 0);
let mut found = false;
for i in 1..gm.candidate_presidents.len() {
found = found || gm.candidate_presidents[i-1] > gm.candidate_presidents[i];
}
assert!(found);
debug!("gamemaster dummy: {:?}", gm);
}
#[test]
fn game_is_over() {
let mut gm = dummy();
assert!(gm.game_is_over().is_ok());
let mut gm = dummy();
gm.policies.insert(Policy::Facist, 10);
assert!(gm.game_is_over().is_err());
assert!(gm.game_is_over().err().unwrap() == Role::Facist);
let mut gm = dummy();
gm.policies.insert(Policy::Liberal, 10);
assert!(gm.game_is_over().err().unwrap() == Role::Liberal);
let mut gm = dummy();
gm.policies.insert(Policy::Facist, 3);
assert!(gm.game_is_over().is_ok());
gm.chancellor = Some("123".to_string());
assert!(gm.game_is_over().is_ok());
let mut p = Player::new("123".to_string());
p.set_role(Role::Liberal);
gm.lobby.players.insert("123".to_string(), p);
assert!(gm.game_is_over().is_ok());
let mut gm = dummy();
gm.policies.insert(Policy::Facist, 3);
assert!(gm.game_is_over().is_ok());
gm.chancellor = Some("123".to_string());
assert!(gm.game_is_over().is_ok());
let mut p = Player::new("123".to_string());
p.set_role(Role::Facist);
gm.lobby.players.insert("123".to_string(), p);
assert!(gm.game_is_over().is_ok());
let mut gm = dummy();
gm.policies.insert(Policy::Facist, 3);
assert!(gm.game_is_over().is_ok());
gm.chancellor = Some("123".to_string());
assert!(gm.game_is_over().is_ok());
let mut p = Player::new("123".to_string());
p.set_role(Role::Hitler);
gm.lobby.players.insert("123".to_string(), p);
assert!(gm.game_is_over().is_err());
assert!(gm.game_is_over().err().unwrap() == Role::Facist);
}
}

View File

@ -2,19 +2,25 @@ 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::role::Role;
use super::super::gameevent::GameEventType;
use super::super::gameevent::GameEvent;
use log::{info, error};
use std::collections::HashMap;
#[derive(Debug)]
pub struct GameMaster {
pub room: Box<dyn Room>,
pub lobby: Lobby,
pub candidate_presidents: Vec<String>,
pub deck: Vec<Policy>,
pub policies: HashMap<Policy, usize>,
pub president: Option<String>,
pub chancellor: Option<String>,
}
impl GameMaster {
pub fn new(room: Box<dyn Room>) -> GameMaster {
info!("created for room {}", room.room_id());
GameMaster{
@ -22,10 +28,13 @@ impl GameMaster {
lobby: Lobby::new(),
candidate_presidents: vec![],
deck: vec![],
policies: HashMap::new(),
president: None,
chancellor: None,
}
}
pub fn run(&mut self) -> Result<String, String> {
pub fn run(&mut self) -> Result<GameEvent, Role> {
loop {
let r = self.run_lobby();
if r.is_ok() {
@ -37,19 +46,31 @@ impl GameMaster {
self.run_game()
}
pub fn run_game(&mut self) -> Result<String, String> {
pub fn run_game(&mut self) -> Result<GameEvent, Role> {
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()),
GameEventType::GameStop => self.game_is_over(),
_ => 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
if p.mode() != GameEventType::PolicySet {
error!("unexpected game event type after election vote followup: {:?}", p);
return Err(Role::Null);
}
let params = p.params();
let param = params.first();
if param.is_none() {
error!("unexpected missing param on {:?}: {:?}", p, param);
return Err(Role::Null);
}
let param = param.unwrap();
let policy = Policy::from_string(param.to_string());
self.game_policy_veto(policy.clone())?;
self.game_ends_with(policy.clone())?;
self.game_policy_enact(policy.clone())?;
}
}

View File

@ -6,10 +6,10 @@ use super::super::policy::Policy;
use super::super::rand::rand_usize;
use super::super::rand::shuffle;
use log::{debug, LevelFilter};
use log::{debug, error, LevelFilter};
impl GameMaster {
pub fn run_game_setup(&mut self) -> Result<String, String> {
pub fn run_game_setup(&mut self) -> Result<String, Role> {
self.setup_gather_candidates()?;
debug!("players: {:?}", self.candidate_presidents);
self.setup_set_roles()?;
@ -20,11 +20,12 @@ impl GameMaster {
Ok("ok".to_string())
}
pub fn setup_gather_candidates(&mut self) -> Result<String, String> {
pub fn setup_gather_candidates(&mut self) -> Result<String, Role> {
for player in self.players() {
let p = self.player(player.clone());
if p.is_none() {
return Err(format!("missing player {}", player));
error!("missing player {}", player);
return Err(Role::Null);
}
self.candidate_presidents.push(player.clone());
debug!("player = {}", player);
@ -32,11 +33,15 @@ impl GameMaster {
Ok("ok".to_string())
}
pub fn setup_set_roles(&mut self) -> Result<String, String> {
pub fn setup_set_roles(&mut self) -> Result<String, Role> {
for player in self.players() {
self.player(player.clone()).unwrap().set_role(Role::Liberal);
}
let n = config::players_to_facists(self.players().len())?;
let n = config::players_to_facists(self.players().len());
if n.is_err() {
return Err(Role::Null);
}
let n = n.unwrap();
for i in 0..n {
debug!("picking facist {}/{} for {} players", i, n, self.players().len());
loop {
@ -54,10 +59,12 @@ impl GameMaster {
break;
}
}
self.president = None;
self.chancellor = None;
Ok("ok".to_string())
}
pub fn setup_order_candidates(&mut self) -> Result<String, String> {
pub fn setup_order_candidates(&mut self) -> Result<String, Role> {
shuffle(&mut self.candidate_presidents);
let n = self.candidate_presidents.len();
for _ in 0..5 {
@ -68,7 +75,7 @@ impl GameMaster {
Ok("ok".to_string())
}
pub fn setup_deck(&mut self) -> Result<String, String> {
pub fn setup_deck(&mut self) -> Result<String, Role> {
for _ in 0..config::players_to_policies_facist(self.players().len()) {
self.deck.push(Policy::Facist);
}
@ -79,6 +86,9 @@ impl GameMaster {
shuffle(&mut self.deck);
self.policies.insert(Policy::Facist, 0); // todo start iwth 1 if 5 players?
self.policies.insert(Policy::Liberal, 0); // todo start iwth 1 if 5 players?
Ok("deck is loaded".to_string())
}
}

View File

@ -1,4 +1,4 @@
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Policy {
Null,
Facist,
@ -6,6 +6,20 @@ pub enum Policy {
}
impl Policy {
pub fn from_string(s: String) -> Policy {
let cases = [
Policy::Null,
Policy::Facist,
Policy::Liberal,
];
for c in &cases {
if format!("{:?}", c) == s {
return c.clone();
}
}
Policy::Null
}
pub fn new() -> Policy {
Policy::Null
}
@ -34,4 +48,10 @@ mod tests {
r.set(Policy::Liberal);
assert!(r == Policy::Liberal);
}
fn from_string() {
assert!(Policy::from_string("".to_string()) == Policy::Null);
assert!(Policy::from_string("Liberal".to_string()) == Policy::Liberal);
assert!(Policy::from_string("Facist".to_string()) == Policy::Facist);
}
}

View File

@ -1,6 +1,8 @@
use super::event;
pub trait Room {
use std::fmt;
pub trait Room: fmt::Debug {
fn rollback(&mut self, since: String);
fn sync(&mut self) -> Vec<event::Event>;
fn send(&mut self, message: String) -> Result<String, &str>;