impl run lobby without checks

master^2
bel 2020-05-03 11:19:42 -06:00
parent cbb8bbec40
commit 6fb3feeeac
6 changed files with 201 additions and 23 deletions

View File

@ -0,0 +1,162 @@
use super::super::super::model::state::event::Event;
use json;
#[derive(Clone, Debug)]
pub struct GameEvent {
d: json::JsonValue,
}
#[derive(PartialEq, Eq, Debug)]
pub enum GameEventType {
Null,
GameStart,
RoleSet,
ElectionPend,
ElectionSet,
VoteSet,
CardPend,
CardPick,
PolicySet,
SpecialInspect,
SpecialSelect,
SpecialKill,
SpecialPeek,
GameStop,
}
impl GameEventType {
fn from_string(s: String) -> GameEventType {
match s.as_ref() {
"Null" => return GameEventType::Null,
"GameStart" => return GameEventType::GameStart,
"RoleSet" => return GameEventType::RoleSet,
"ElectionPend" => return GameEventType::ElectionPend,
"ElectionSet" => return GameEventType::ElectionSet,
"VoteSet" => return GameEventType::VoteSet,
"CardPend" => return GameEventType::CardPend,
"CardPick" => return GameEventType::CardPick,
"PolicySet" => return GameEventType::PolicySet,
"SpecialInspect" => return GameEventType::SpecialInspect,
"SpecialSelect" => return GameEventType::SpecialSelect,
"SpecialKill" => return GameEventType::SpecialKill,
"SpecialPeek" => return GameEventType::SpecialPeek,
"GameStop" => return GameEventType::GameStop,
_ => return GameEventType::Null,
}
}
}
impl GameEvent {
pub fn new(body: String) -> GameEvent {
let top_level = json::parse(&body);
if top_level.is_err() {
return GameEvent{d: json::Null};
}
let top_level = top_level.unwrap();
if !top_level["body"].is_string() {
return GameEvent{d: json::Null};
}
GameEvent{
d: json::parse(&top_level["body"].as_str().unwrap()).unwrap_or(json::Null),
}
}
pub fn mode(&self) -> GameEventType {
if self.d.is_null() {
return GameEventType::Null;
}
if !self.d["GameEventType"].is_string() {
return GameEventType::Null;
}
let s = self.d["GameEventType"].as_str().unwrap().to_string();
GameEventType::from_string(s.to_string())
}
pub fn sources(&self) -> Vec<String> {
self.str_vec("sources")
}
pub fn targets(&self) -> Vec<String> {
self.str_vec("targets")
}
pub fn params(&self) -> Vec<String> {
self.str_vec("params")
}
fn str_vec(&self, key: &str) -> Vec<String> {
let mut out = vec![];
if self.d[key].is_string() {
out.push(self.d[key].as_str().unwrap().to_string());
return out;
}
if self.d[key].is_array() {
let iter = self.d[key].members();
for i in iter {
if !i.is_string() {
return vec![];
}
out.push(i.as_str().unwrap().to_string());
}
return out;
}
out
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new() {
let ge = GameEvent::new("\"a\"".to_string());
assert!(ge.d.is_null());
let ge = GameEvent::new("a".to_string());
assert!(ge.d.is_null());
assert!(ge.mode() == GameEventType::Null);
}
#[test]
fn type_from_string() {
assert!(GameEventType::from_string("Null".to_string()) == GameEventType::Null);
assert!(GameEventType::from_string("GameStart".to_string()) == GameEventType::GameStart);
assert!(GameEventType::from_string("RoleSet".to_string()) == GameEventType::RoleSet);
assert!(GameEventType::from_string("ElectionPend".to_string()) == GameEventType::ElectionPend);
assert!(GameEventType::from_string("ElectionSet".to_string()) == GameEventType::ElectionSet);
assert!(GameEventType::from_string("VoteSet".to_string()) == GameEventType::VoteSet);
assert!(GameEventType::from_string("CardPend".to_string()) == GameEventType::CardPend);
assert!(GameEventType::from_string("CardPick".to_string()) == GameEventType::CardPick);
assert!(GameEventType::from_string("PolicySet".to_string()) == GameEventType::PolicySet);
assert!(GameEventType::from_string("SpecialInspect".to_string()) == GameEventType::SpecialInspect);
assert!(GameEventType::from_string("SpecialSelect".to_string()) == GameEventType::SpecialSelect);
assert!(GameEventType::from_string("SpecialKill".to_string()) == GameEventType::SpecialKill);
assert!(GameEventType::from_string("SpecialPeek".to_string()) == GameEventType::SpecialPeek);
assert!(GameEventType::from_string("GameStop".to_string()) == GameEventType::GameStop);
}
#[test]
fn sources() {
let ge = GameEvent::new(r#"{"body": "{\"sources\": [\"a\", \"b\"]}"}"#.to_string());
assert!(ge.sources() == vec!["a", "b"]);
}
#[test]
fn targets() {
let ge = GameEvent::new(r#"{"body": "{\"targets\": [\"a\", \"b\"]}"}"#.to_string());
assert!(ge.targets() == vec!["a", "b"]);
}
#[test]
fn params() {
let ge = GameEvent::new(r#"{"body": "{\"params\": [\"a\", \"b\"]}"}"#.to_string());
assert!(ge.params() == vec!["a", "b"]);
let ge = GameEvent::new(r#"{"body": "{\"params\": []}"}"#.to_string());
assert!(ge.params().len() == 0);
let ge = GameEvent::new(r#"{"body": "{}"}"#.to_string());
assert!(ge.params().len() == 0);
}
}

View File

@ -1,5 +1,9 @@
use super::super::super::model::state::room::Room;
use super::lobby::Lobby;
use super::gameevent::GameEvent;
use super::gameevent::GameEventType;
use std::thread;
use std::time;
pub struct GameMaster {
room: Box<dyn Room>,
@ -21,18 +25,24 @@ impl GameMaster {
}
fn run_lobby(&mut self) -> Result<String, String> {
println!(". run lobby");
loop {
while !self.lobby.locked {
let rollback = self.room.since();
let events = self.room.sync();
println!(". rollback: {:?}", rollback);
println!("top of loop: since={:?}, events={:?}", self.room.since(), events);
for e in &events {
println!("e: {:?}", e);
let ge = GameEvent::new(e.body.clone());
println!(" ge.mode = {:?}", ge.mode());
if ge.mode() == GameEventType::GameStart {
println!(" should return");
self.room.rollback(e.since.clone());
self.lobby.lock();
return Ok("ok".to_string());
}
self.lobby.eat(e.clone());
}
self.room.rollback(rollback);
break
thread::sleep(time::Duration::new(1, 0));
}
Err("not impl".to_string())
Ok("ok".to_string()) // todo: on lobby too small, return err and do not lock
}
fn run_game_setup(&mut self) -> Result<String, String> {
@ -54,7 +64,6 @@ mod tests {
#[test]
fn new_mockroom() {
let _ = GameMaster::new(Box::new(MockRoom::create()));
println!("made");
}
#[test]
@ -78,27 +87,33 @@ mod tests {
#[test]
fn run_lobby() {
let mut mrs = MockRooms::new();
let mut r1 = mrs.create();
let r1 = mrs.create();
let room_id = r1.room_id();
let mut gm = GameMaster::new(r1);
let mut r2 = mrs.join(room_id).unwrap();
r2.send(r#"{
r2.send(format!(r#"{{
"msgtype": "m.text",
"body": ""
}"#);
gm.run_lobby();
assert!(gm.lobby.players.len() == 1, "players: {:?}, sync: {:?}", gm.lobby.players, gm.room.sync());
"body": "{{\"GameEventType\": \"GameStart\"}}"
}}"#)).unwrap(); // TODO mark end of new players
gm.run_lobby(); // todo assert is_ok
assert!(gm.lobby.players.len() == 2, "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());
}
gm.run_lobby(); // todo assert is_ok
assert!(gm.lobby.players.len() == 2, "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_fail() {
let gm = GameMaster::new(Box::new(MockRoom::create()));
panic!("not impl");
assert!(false, "not impl");
}
#[test]
fn run_game_fail() {
let gm = GameMaster::new(Box::new(MockRoom::create()));
panic!("not impl");
assert!(false, "not impl");
}
}

View File

@ -5,7 +5,7 @@ use std::collections::HashMap;
pub struct Lobby {
pub players: HashMap<String, Player>,
locked: bool,
pub locked: bool,
}
impl Lobby {

View File

@ -1,4 +1,5 @@
// pub mod gamemaster;
pub mod gamemaster;
pub mod player;
pub mod role;
pub mod lobby;
pub mod gameevent;

View File

@ -159,7 +159,7 @@ mod tests {
let mut r = _dummy();
r.sync();
let mut sinces = vec![];
for i in 0..10 {
for _ in 0..10 {
sinces.push(r.send("0".to_string()).ok().unwrap());
sinces.push(r.send("0".to_string()).ok().unwrap());
r.sync();
@ -172,7 +172,7 @@ mod tests {
let mut r = _dummy();
r.sync();
let mut sinces = vec![];
for i in 0..10 {
for _ in 0..10 {
sinces.push(r.send("0".to_string()).ok().unwrap());
r.sync();
assert!(r.since == sinces[sinces.len()-1]);

View File

@ -31,7 +31,7 @@ impl Rooms for MockRooms {
r.send(format!(r#"{{
"displayname": "{}",
"membership": "join"
}}"#, rands()));
}}"#, rands())).unwrap();
return Ok(Box::new(r));
}
}