mao/server/game/mod.rs

94 lines
2.5 KiB
Rust
Raw Normal View History

2024-07-26 13:39:38 -04:00
pub mod errors;
use rand::prelude::*;
use std::fmt::Display;
use crate::card::Card;
use crate::card::consts::{DECK, CARDS_PER_PLAYER};
use errors::{MakeGameError, PlayError};
#[derive(Debug, Clone)]
pub struct Game {
played: Vec<Card>,
deck: Vec<Card>,
players: Vec<Vec<Card>>,
}
impl Game {
pub fn new(decks: usize, players: usize) -> Result<Self, MakeGameError> {
const TOP_CARD: usize = 1;
if players * CARDS_PER_PLAYER + TOP_CARD >= DECK.len() * decks {
return Err(MakeGameError::InsufficientCards);
}
let mut deck = DECK.to_vec().repeat(decks);
let mut rng = thread_rng();
deck.shuffle(&mut rng);
let mut players = vec![ Vec::with_capacity(7); players ];
for p in &mut players {
let range = deck.len()-CARDS_PER_PLAYER .. deck.len();
let iter = deck.drain(range);
p.extend(iter);
}
// safety: this will always be safe because we checked ahead of time
// if there were enough cards
let top_card = unsafe { deck.pop().unwrap_unchecked() };
let played = vec![top_card];
Ok(Self {
played,
deck,
players,
})
}
pub fn play(&mut self, player: usize, cards: &[Card]) -> Result<(), PlayError> {
let player = self.players.get_mut(player).ok_or(PlayError::NoSuchPlayer)?;
let o_len = player.len();
player.retain(|card| !cards.contains(card));
if o_len - player.len() == cards.len() {
Ok(())
} else {
Err(PlayError::PlayerDoesNotHaveCard)
}
}
}
impl Display for Game {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let join_cards_by_spaces = |cards: &[Card]| join_formatted(cards, ToString::to_string, " ");
let played = join_cards_by_spaces(&self.played);
let deck = join_cards_by_spaces(&self.deck);
let players = join_formatted(
(1..).zip(&self.players),
|(i, v)| format!("{i}: {}", join_cards_by_spaces(v)),
"\n"
);
write!(f, "played: {played}\ndeck: {deck}\nplayers:\n{players}")
}
}
fn join_formatted<I, F>(iter: I, f: F, sep: &str) -> String
where
I: IntoIterator,
F: FnMut(I::Item) -> String,
{
iter.into_iter()
.map(f)
.reduce(|acc, s| acc + sep + &s)
.unwrap_or_default()
}
pub enum Message {
PlayCards(usize, Vec<Card>)
}