| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- use serde::{Serialize, Deserialize};
- use std::collections::BTreeMap;
- #[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
- pub enum GameState {
- Starting,
- Creating,
- Guessing
- }
- #[derive(Serialize, Deserialize, Clone, Debug)]
- pub struct CreatingEx {
- pub question: String,
- pub letters: Vec<char>
- }
- #[derive(Serialize, Clone, Debug)]
- pub struct Player {
- pub nick: String,
- pub creating_exercise: Option<CreatingEx>,
- pub submitted_word: Option<String>,
- pub submitted_guess: Option<Vec<(String, String)>>
- }
- #[derive(Serialize, Clone, Debug)]
- pub struct Game {
- pub players: Vec<Player>,
- pub round_number: i32,
- pub additional_questions: Vec<String>,
- pub state: GameState,
- }
- impl Player {
- pub fn has_submitted_word(&self) -> bool {
- self.submitted_word.is_some()
- }
-
- pub fn has_submitted_guess(&self) -> bool {
- self.submitted_guess.is_some()
- }
- }
- impl Game {
- pub fn new() -> Self {
- Self {
- players: Vec::new(),
- round_number: 0,
- additional_questions: Vec::new(),
- state: GameState::Starting
- }
- }
- pub fn get_player_mut(&mut self, nick: &str) -> Option<&mut Player> {
- self.players.iter_mut().find(|x| x.nick == nick)
- }
- pub fn get_player(&self, nick: &str) -> Option<&Player> {
- self.players.iter().find(|x| x.nick == nick)
- }
- pub fn check_letters(word: &str, letters: &Vec<char>) -> bool {
- let allowed_chars = [" ", "-", "'"];
- if word.len() == 0 {
- return false;
- }
- let mut countmap: BTreeMap<String, isize> = BTreeMap::new();
- for c in letters {
- let upper: String = c.to_uppercase().collect();
- let val = countmap.get(&upper).unwrap_or(&0) + 1;
- countmap.insert(upper, val);
- }
- for c in word.to_uppercase().chars() {
- let upper = String::from(c);
- let count = countmap.get(&upper);
- if allowed_chars.iter().any(|x| &upper == *x) {
- continue;
- }
- if let Some(&v) = count {
- if v <= 0 {
- return false;
- }
- countmap.insert(upper, v - 1);
- }
- else {
- return false;
- }
- }
- true
- }
- pub fn submit_creation(&mut self, player_nick: &str, word: String) -> bool {
- match self.state {
- GameState::Creating => {
- if let Some(player) = self.get_player_mut(player_nick) {
- if let Some(ex) = &player.creating_exercise {
- if Self::check_letters(&word, &ex.letters) {
- player.submitted_word = Some(word);
- return true;
- }
- }
- }
- },
- _ => {}
- }
- false
- }
- pub fn submit_guess(&mut self, player_nick: &str, guess: Vec<(String, String)>) -> bool {
- match self.state {
- GameState::Guessing => {
- if let Some(player) = self.get_player_mut(player_nick) {
- player.submitted_guess = Some(guess);
- true
- }
- else {
- false
- }
- },
- _ => false
- }
- }
- pub fn all_words_submitted(&self) -> bool {
- self.state == GameState::Creating &&
- self.players.iter().map(|p| p.submitted_word.is_some()).fold(true, |a, b| a && b)
- }
- pub fn all_guesses_submitted(&self) -> bool {
- self.state == GameState::Guessing &&
- self.players.iter().map(|p| p.submitted_guess.is_some()).fold(true, |a, b| a && b)
- }
- pub fn next_state(&mut self) {
- if self.state == GameState::Guessing {
- self.clear_submissions();
- }
- self.state = match self.state {
- GameState::Starting => GameState::Creating,
- GameState::Creating => GameState::Guessing,
- GameState::Guessing => GameState::Starting
- }
- }
- pub fn start_round<F, G>(&mut self, mut word_generator: F, mut char_generator: G)
- where F: FnMut() -> String,
- G: FnMut() -> Vec<char> {
- self.clear_submissions();
- /*let mut exes = vec![
- CreatingEx{ question: "Delikatessfutter für Hunde".to_owned(), letters: vec!['a', 'b', 'c'] },
- CreatingEx{ question: "Ein Hotel für die ganze Familie".to_owned(), letters: vec!['b', 'c', 'd'] },
- CreatingEx{ question: "Brasilianischer Superstar".to_owned(), letters: vec!['c', 'd', 'e'] },
- CreatingEx{ question: "Buchstabe des griechischen Alphabets".to_owned(), letters: vec!['d', 'e', 'f'] },
- ];*/
- for p in &mut self.players {
- p.creating_exercise = Some(
- CreatingEx{
- question: word_generator(),
- letters: char_generator()
- }
- );
- }
- self.additional_questions.clear();
- self.additional_questions.push(word_generator());
- self.additional_questions.push(word_generator());
- self.state = GameState::Creating;
- }
- pub fn clear_submissions(&mut self) {
- for p in &mut self.players {
- p.submitted_word = None;
- p.submitted_guess = None;
- p.creating_exercise = None;
- }
- }
- pub fn player_join(&mut self, nick: String) {
- self.players.push(Player{
- nick: nick,
- creating_exercise: None,
- submitted_word: None,
- submitted_guess: None
- });
- }
- pub fn remove_player(&mut self, nick: &str) {
- self.players.retain(|p| p.nick != nick);
- }
- pub fn create_results(&self) -> (Vec<Vec<Vec<String>>>, Vec<(String, i64)>) {
- let mut result: Vec<Vec<Vec<String>>> = Vec::new();
- let mut questions = self.players.iter()
- .map(|p| p.creating_exercise.clone().unwrap().question)
- .collect::<Vec<_>>();
- questions.append(&mut self.additional_questions.iter()
- .map(|x| x.clone())
- .collect::<Vec<_>>()
- );
- let mut player_points: Vec<i64> = vec![0; self.players.len()];
- for (player, p_id) in self.players.iter().zip(0..) {
- let mut line: Vec<Vec<String>> = Vec::new();
- let word = player.submitted_word.as_ref().unwrap();
- for (question, q_id) in questions.iter().zip(0..) {
- let mut cell: Vec<String> = Vec::new();
- for (p, inner_p) in self.players.iter().zip(0..) {
- if let Some(guess) = &p.submitted_guess {
- if let Some(_corr) = guess.iter().find(|(w, q)| w == word && q == question) {
- cell.push(p.nick.clone());
- // if solution is correct and not its own
- if p_id == q_id && p_id != inner_p {
- player_points[p_id] += 1;
- player_points[inner_p] += 1;
- }
- }
- }
- }
- line.push(cell);
- }
- result.push(line);
- }
- let point_list = self.players.iter()
- .map(|p| p.nick.clone())
- .zip(player_points)
- .collect::<Vec<_>>();
- return (result, point_list);
- }
- }
|