cards/server/src/game.rs

184 lines
5 KiB
Rust
Raw Normal View History

2024-08-24 16:15:19 -04:00
use crate::AppState;
use crate::User;
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<RwLock<User>>,
/// Selected game packs
pub packs: Vec<u8>,
}
/// 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<RwLock<User>>,
/// The player's hand
pub white: Vec<Arc<CardWhiteWithID>>,
/// The player's wins
pub black: Vec<Arc<CardBlackWithID>>,
}
/// 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<RwLock<User>>,
/// Current card czar
pub czar: Arc<RwLock<User>>,
/// Packs selected for this game
pub packs: Vec<u8>,
/// White draw pile
pub white: Vec<Arc<CardWhiteWithID>>,
/// Black draw pile
pub black: Vec<Arc<CardBlackWithID>>,
pub players: HashMap<String, Player>,
/// Black card for the current round
pub current_black: Arc<CardBlackWithID>,
/// Judge pool
pub judge_pool: HashMap<Vec<String>, String>,
}
impl Game {
/// Returns a new game object
pub fn new(state: Arc<AppState>, 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(),
}
}
/// 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();
}
/// Draw one black card at random from play deck.
fn draw_one_black(&mut self) -> Option<Arc<CardBlackWithID>> {
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<Arc<CardWhiteWithID>> {
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<RwLock<User>>) {
// 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);
}
}