use crate::AppState; use crate::User; use lib::*; use rand::prelude::IteratorRandom; use rand::thread_rng; use std::{ collections::HashMap, sync::{Arc, RwLock}, }; use uuid::Uuid; /// Internal manifest for making a new game #[derive(Debug)] pub struct NewGameManifest { /// Game name pub name: String, /// Game host pub host: Arc>, /// Selected game packs pub packs: Vec, } /// A processed white card for use server-side #[derive(Debug)] pub struct CardWhiteWithID { /// Unique identifier pub uuid: Uuid, /// Card text pub text: String, } /// A processed black card for use server-side #[derive(Debug)] pub struct CardBlackWithID { /// Unique identifier pub uuid: Uuid, /// Card text pub text: String, /// Amount of cards to submit for judging pub pick: u8, } /// A player #[derive(Debug)] pub struct Player { /// Pointer to user pub user: Arc>, /// The player's hand pub white: Vec>, /// The player's wins pub black: Vec>, } /// The game object #[derive(Debug)] pub struct Game { /// Game's UUID pub uuid: Uuid, /// The name of the game pub name: String, /// The host user of the game pub host: Arc>, /// Current card czar pub czar: Arc>, /// Packs selected for this game pub packs: Vec, /// White draw pile pub white: Vec>, /// Black draw pile pub black: Vec>, pub players: HashMap, /// Black card for the current round pub current_black: Arc, /// Judge pool pub judge_pool: HashMap, String>, } impl Game { /// Returns a new game object pub fn new(state: Arc, request: NewGameManifest) -> Self { // Build the decks let mut white = vec![]; let mut black = vec![]; for pack_num in &request.packs { if let Some(pack) = state.packs.official.get(&pack_num) { if let Some(card) = &pack.white { white.extend(card.clone()) } if let Some(card) = &pack.black { black.extend(card.clone()) } } else if let Some(pack) = state.packs.unofficial.get(&pack_num) { if let Some(card) = &pack.white { white.extend(card.clone()) } if let Some(card) = &pack.black { black.extend(card.clone()) } } } // Draw first black card let current_black = black.swap_remove( (0..black.len()) .choose(&mut thread_rng()) .expect("No black cards to draw from!"), ); // These are at the largest size they should ever be white.shrink_to_fit(); black.shrink_to_fit(); // Return game object Game { uuid: Uuid::now_v7(), name: request.name, host: request.host.clone(), czar: request.host.clone(), white, black, players: HashMap::new(), current_black, packs: request.packs.clone(), judge_pool: HashMap::new(), } } /// Process player move pub fn player_move( &mut self, request: PlayerMoveRequest, player_user_id: String, ) -> Result, String> { if self.czar.read().unwrap().uuid == player_user_id { tracing::debug!("Player is czar"); Err("You can't submit cards to judge, you ARE the judge!".to_string()) } else { // Ignore extra cards let trimmed = request.card_ids[..self.current_black.pick.into()].to_vec(); // TODO: handle not enough cards tracing::debug!("Trimmed: {:#?}", trimmed); // Put cards into judge pool self.judge_pool.insert(trimmed, player_user_id.clone()); // Start judging if this is last player to submit if self.judge_pool.len() == self.players.len() - 1 { Ok(Some(( JudgeRound { cards_to_judge: self .judge_pool .keys() .into_iter() .map(|group| { group .iter() .map(|id| WhiteCardMeta { uuid: id.to_string(), text: "test".to_string(), }) .collect() }) .collect(), }, self.czar.read().unwrap().uuid.clone(), ))) } else { // User submitted cards Ok(None) } } } /// Tick forward pub fn finish_round(&mut self, winner_id: String) { self.players .get_mut(&winner_id) .unwrap() .black .push(self.current_black.clone()); self.current_black = self.draw_one_black().unwrap(); self.judge_pool.clear(); } /// Draw one black card at random from play deck. fn draw_one_black(&mut self) -> Option> { let deck = &mut self.black; if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) { Some(deck.swap_remove(index)) } else { tracing::error!("Tried to draw white card that doesn't exist!"); None } } /// Draw one white card at random from play deck. fn draw_one_white(&mut self) -> Option> { let deck = &mut self.white; if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) { Some(deck.swap_remove(index)) } else { tracing::error!("Tried to draw white card that doesn't exist!"); None } } /// Create a new player and add them to the game. pub fn create_player(&mut self, user: Arc>) { // Build hand of 10 white cards let mut white = vec![]; for _ in 0..10 { if let Some(card) = self.draw_one_white() { white.push(card); } } // New player object let new_player = Player { user: user.clone(), white, black: vec![], }; // Add player to game self.players .insert(user.read().unwrap().uuid.clone(), new_player); } }