123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- use std::collections::BTreeMap;
- use std::sync::Arc;
- use rand::thread_rng;
- use rand::seq::SliceRandom;
- use actix::prelude::*;
- use log::info;
- use crate::server::server::{GameConnection, Server};
- use crate::datasource;
- use crate::game;
- use crate::server::protocol::*;
- use crate::server::messages::*;
- #[derive(PartialEq)]
- enum LobbyState {
- Starting,
- Creating,
- Guessing,
- Revealing
- }
- pub struct GameLobby {
- server: Addr<Server>,
- connected_players: BTreeMap<String, Addr<GameConnection>>,
- game_id: String,
- game: game::Game,
- player_points: BTreeMap<String, i64>,
- waiting_players: BTreeMap<String, Addr<GameConnection>>,
- ready_players: Vec<String>,
- revealed_players: Vec<String>,
- round_result: Option<RoundResultData>,
- lobby_state: LobbyState,
-
- shuffler: datasource::Shuffler<String>,
- letter_distribution: datasource::LetterDistribution
- }
- impl Actor for GameLobby {
- type Context = Context<Self>;
- fn started(&mut self, _ctx: &mut Self::Context) {
- self.lobby_state = LobbyState::Starting;
- }
- }
- impl Handler<JoinRequest> for GameLobby {
- type Result = ();
- fn handle(&mut self, jr: JoinRequest, ctx: &mut Self::Context) -> Self::Result {
- if self.lobby_state == LobbyState::Starting {
- if self.connected_players.contains_key(&jr.nick) {
- jr.p.do_send(NickAlreadyExistsMsg {
- game_id: self.game_id.clone(),
- nick: jr.nick
- });
- }
- else {
- self.connected_players.insert(jr.nick.clone(), jr.p.clone());
- self.game.player_join(jr.nick.clone());
- jr.p.do_send(
- LobbyJoined {
- lobby: ctx.address(),
- game_id: self.game_id.clone(),
- nick: jr.nick.clone()
- }
- );
- self.send_game_to_all();
- info!("Player {} joined lobby {}", jr.nick, self.game_id);
- }
- }
- else {
- //self.waiting_players.insert(jr.nick.clone(), jr.p);
- jr.p.do_send(GameAlreadyStartedMsg(jr.lobby_id));
- }
- }
- }
- impl Handler<LeaveMsg> for GameLobby {
- type Result = ();
- fn handle(&mut self, lm: LeaveMsg, _ctx: &mut Self::Context) -> Self::Result {
- self.waiting_players.remove(&lm.0);
- self.connected_players.remove(&lm.0);
- self.ready_players.retain(|p| p != &lm.0);
- self.game.remove_player(&lm.0);
- if self.connected_players.is_empty() {
- self.server.do_send(LobbyFinished(self.game_id.clone()));
- }
- }
- }
- impl Handler<ReadyMsg> for GameLobby {
- type Result = ();
- fn handle(&mut self, rm: ReadyMsg, _ctx: &mut Self::Context) -> Self::Result {
- if !self.ready_players.contains(&rm.0) {
- self.ready_players.push(rm.0);
- }
- self.send_playerlist_to_all();
- if self.ready_players.len() >= self.connected_players.len() {
- self.set_state(LobbyState::Creating);
- self.send_game_to_all();
- }
- }
- }
- impl Handler<UnreadyMsg> for GameLobby {
- type Result = ();
- fn handle(&mut self, urm: UnreadyMsg, _ctx: &mut Self::Context) -> Self::Result {
- self.ready_players.retain(|p| p != &urm.0);
- self.send_playerlist_to_all();
- }
- }
- impl Handler<RevealMsg> for GameLobby {
- type Result = ();
- fn handle(&mut self, rm: RevealMsg, _ctx: &mut Self::Context) -> Self::Result {
- self.revealed_players.retain(|p| p != &rm.0);
- self.revealed_players.push(rm.0);
- self.send_game_to_all();
- if self.all_revealed() {
- self.set_state(LobbyState::Starting);
- self.send_game_to_all();
- }
- }
- }
- impl Handler<SubmitWordMsg> for GameLobby {
- type Result = ();
- fn handle(&mut self, swm: SubmitWordMsg, _ctx: &mut Self::Context) -> Self::Result {
- let _correct = self.game.submit_creation(&swm.nick, swm.word);
- if self.game.all_words_submitted() {
- self.set_state(LobbyState::Guessing);
- self.game.next_state();
- self.send_game_to_all();
- }
- else {
- self.send_playerlist_to_all();
- }
- }
- }
- impl Handler<SubmitGuessMsg> for GameLobby {
- type Result = ();
- fn handle(&mut self, sgm: SubmitGuessMsg, _ctx: &mut Self::Context) -> Self::Result {
- self.game.submit_guess(&sgm.nick, sgm.guesses);
- if self.game.all_guesses_submitted() {
- self.set_state(LobbyState::Revealing);
- let results = self.create_result_data();
- for (nick, pts) in &results.point_list {
- self.add_player_points(nick, *pts);
- }
- //self.broadcast_results(results.clone());
- self.round_result = Some(results);
- self.game.next_state();
- self.send_game_to_all();
- }
- else {
- self.send_playerlist_to_all();
- }
- }
- }
- impl GameLobby {
- pub fn new(gi: String, data_source: Arc<dyn datasource::DataSource<String>>, server: Addr<Server>) -> Self {
- GameLobby {
- server: server,
- connected_players: BTreeMap::new(),
- game_id: gi,
- game: game::Game::new(),
- player_points: BTreeMap::new(),
- waiting_players: BTreeMap::new(),
- round_result: None,
- ready_players: Vec::new(),
- revealed_players: Vec::new(),
- lobby_state: LobbyState::Starting,
- shuffler: datasource::Shuffler::create(data_source),
- letter_distribution: datasource::LetterDistribution::create()
- }
- }
- fn set_state(&mut self, new_state: LobbyState) {
- match new_state {
- LobbyState::Starting => {
- for (nick, _addr) in &self.waiting_players {
- self.game.player_join(nick.clone());
- }
- self.connected_players.append(&mut self.waiting_players);
- },
- LobbyState::Creating => {
- let s = &mut self.shuffler;
- let ld = &self.letter_distribution;
- self.game.start_round(|| s.get(), || ld.get(4, 6));
- },
- _ => {}
- }
- self.ready_players.clear();
- self.revealed_players.clear();
- self.round_result = None;
- self.lobby_state = new_state;
- }
- pub fn get_player_points(&self, nick: &str) -> i64 {
- *self.player_points.get(nick).unwrap_or(&0)
- }
- pub fn add_player_points(&mut self, nick: &str, points: i64) {
- let entry = self.player_points.get_mut(nick);
- match entry {
- Some(x) => *x += points,
- None => { self.player_points.insert(nick.to_owned(), points); },
- }
- }
- pub fn send_game_to_all(&self) {
- for (nick, player) in &self.connected_players {
- let game_state = self.create_opaque_message(nick);
- player.do_send(GameUpdate{ game_data: game_state });
- }
- }
- pub fn send_playerlist_to_all(&self) {
- let player_list = self.create_playerlist();
- for (_nick, player) in &self.connected_players {
- player.do_send(PlayerListUpdate{ player_list: player_list.clone() });
- }
- }
- pub fn create_result_data(&self) -> RoundResultData {
- let (guesses, point_list) = self.game.create_results();
- let words = self.game.players.iter()
- .map(|p| (
- p.nick.clone(),
- p.submitted_word.clone().unwrap(),
- self.revealed_players.iter().any(|x| x == &p.nick)
- )
- )
- .collect::<Vec<_>>();
- let questions = self.game.players.iter()
- .map(|x| x.creating_exercise.as_ref().unwrap().question.clone())
- .chain(self.game.additional_questions.clone().into_iter())
- .collect::<Vec<_>>();
- let solutions = words.iter()
- .map(|(_n, w, _r)| w.clone())
- .zip(questions.iter().map(|x| x.clone()))
- .collect::<Vec<_>>();
- let mut permutation = (0..questions.len()).collect::<Vec<_>>();
- permutation.shuffle(&mut thread_rng());
- let mut shuffled_questions: Vec<String> = Vec::new();
- let mut shuffled_guesses: Vec<Vec<Vec<String>>> = Vec::new();
-
-
- for pi in &permutation {
- shuffled_questions.push(questions[*pi].clone());
- }
- for guessline in guesses {
- let mut shuffled_line: Vec<Vec<String>> = Vec::new();
- for pi in &permutation {
- if *pi < guessline.len() {
- shuffled_line.push(guessline[*pi].clone());
- }
- else {
- shuffled_line.push(Vec::new());
- }
- }
- shuffled_guesses.push(shuffled_line);
- }
- RoundResultData {
- words,
- questions: shuffled_questions,
- solutions,
- guesses: shuffled_guesses,
- point_list
- }
- }
- /*pub fn broadcast_results(&self, results: RoundResultData) {
- let has_revealed = self.revealed_players.iter()
- .map(|n| (n.clone(), self.revealed_players.iter().any(|x| x == n)))
- .collect::<Vec<_>>();
- for (_nick, player) in &self.connected_players {
- player.do_send(ResultMsg {
- results: results.clone(),
- //has_revealed: has_revealed.clone()
- });
- }
- }*/
- ///
- /// determines if a player is ready to progress into the next game state
- ///
- fn player_is_ready(&self, nick: &str) -> bool {
- match self.lobby_state {
- LobbyState::Starting => self.ready_players.iter().any(|p| p == nick),
- LobbyState::Creating => self.game.get_player(nick)
- .map(|p| p.has_submitted_word())
- .unwrap_or(false),
- LobbyState::Guessing => self.game.get_player(nick)
- .map(|p| p.has_submitted_guess())
- .unwrap_or(false),
- LobbyState::Revealing => self.ready_players.iter().any(|p| p == nick)
- }
- }
- fn create_playerlist(&self) -> Vec<PlayerData> {
- self.game.players.iter()
- .map(|p|
- PlayerData {
- nick: p.nick.clone(),
- points: self.get_player_points(&p.nick),
- ready: self.player_is_ready(&p.nick),
- })
- .collect::<Vec<_>>()
- }
- pub fn create_opaque_message(&self, nick: &str) -> GameData {
- let player = self.game.players.iter()
- .find(|p| p.nick == nick);
- GameData {
- players: self.create_playerlist(),
- state_data:
- if self.lobby_state == LobbyState::Revealing {
- let mut round_result = self.round_result.as_ref().unwrap().clone();
- for (nick, _word, revealed) in &mut round_result.words {
- *revealed = self.revealed_players.iter().any(|x| x == nick);
- }
- GameStateData::Revealing {
- round_result
- }
- }
- else {
- match self.game.state {
- game::GameState::Starting => {
- GameStateData::Starting
- },
- game::GameState::Creating => {
- GameStateData::Creating{
- question: player.unwrap().creating_exercise.as_ref().unwrap().question.clone(),
- available_chars: player.unwrap().creating_exercise.as_ref().unwrap().letters.clone()
- }
- },
- game::GameState::Guessing => {
- self.create_guessing(nick)
- },
- }
- }
- }
- }
- pub fn check_optionals(&self) {
- for p in &self.game.players {
- println!("{:?}", p);
- }
- }
-
- pub fn all_revealed(&self) -> bool {
- self.connected_players.iter().all(|(nick, _p)| self.revealed_players.iter().any(|x| x == nick))
- }
- pub fn create_guessing(&self, nick: &str) -> GameStateData {
- self.check_optionals();
- let words_with_chars = self.game.players.iter()
- .filter(|p| p.nick != nick)
- .map(|p|
- (p.submitted_word.clone().unwrap(),
- p.creating_exercise.clone().unwrap().letters))
- .collect::<Vec<_>>();
- let mut questions = self.game.players.iter()
- .filter(|p| p.nick != nick)
- .map(|p| p.creating_exercise.clone().unwrap().question)
- .collect::<Vec<_>>();
- questions.append(&mut self.game.additional_questions.iter()
- .map(|x| x.clone())
- .collect::<Vec<_>>()
- );
- questions.shuffle(&mut thread_rng());
- GameStateData::Guessing {
- submitted_words: words_with_chars,
- questions: questions
- }
- }
- }
|