card-game 0.2.0

Framework for building card games
Documentation
use std::collections::HashMap;

use crate::{cards::CardID, create_valid_identification, identifications::MutID};
use card_stack::NonEmptyInput;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PlayerID(usize);
impl NonEmptyInput for PlayerID {}
impl PlayerID {
    pub fn new(id: usize) -> Self {
        PlayerID(id)
    }
    pub fn value(&self) -> usize {
        self.0
    }
    fn next_player_id(&self, max_players: usize) -> Self {
        PlayerID((self.0 + 1) % max_players)
    }
}
impl std::fmt::Display for PlayerID {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

use crate as card_game;
create_valid_identification!(ValidPlayerID, PlayerID, with_copy);
impl From<ValidPlayerID<ActivePlayer>> for ValidPlayerID<()> {
    fn from(valid_id: ValidPlayerID<ActivePlayer>) -> Self {
        ValidPlayerID(valid_id.0, std::marker::PhantomData::default())
    }
}
impl<F> ValidPlayerID<F> {
    pub(crate) fn new(player_id: PlayerID) -> Self {
        ValidPlayerID(player_id, std::marker::PhantomData::default())
    }
}
impl ValidPlayerID<()> {
    pub fn try_new<P>(
        player_manager: &PlayerManager<P>,
        player_id: PlayerID,
    ) -> Result<Self, PlayerDoesNotExist> {
        if player_manager.players.contains_key(&player_id) {
            Ok(ValidPlayerID(
                player_id,
                std::marker::PhantomData::default(),
            ))
        } else {
            Err(PlayerDoesNotExist(player_id))
        }
    }
}
#[derive(thiserror::Error, Debug)]
#[error("player {0} does not exist")]
pub struct PlayerDoesNotExist(PlayerID);
#[derive(Debug)]
pub struct ActivePlayer;

#[derive(Debug, Clone)]
pub struct PlayerManager<P> {
    pub(crate) players: HashMap<PlayerID, P>,
}

impl<P> PlayerManager<P> {
    /// `players`: must have at least one player
    pub fn new(players: HashMap<PlayerID, P>) -> Self {
        PlayerManager { players }
    }
    pub fn player_count(&self) -> usize {
        self.players.len()
    }
    pub fn players(&self) -> impl Iterator<Item = ValidPlayerID<()>> {
        self.players
            .keys()
            .copied()
            .map(|player_id| ValidPlayerID::new(player_id))
    }
    pub fn get_player(&self, player_id: PlayerID) -> Option<&P> {
        self.players.get(&player_id)
    }
    pub fn get_player_mut(&mut self, player_id: MutID<PlayerID>) -> Option<&mut P> {
        self.players.get_mut(player_id.id())
    }
    pub fn valid_player<F>(&self, valid_player_id: &ValidPlayerID<F>) -> &P {
        self.get_player(valid_player_id.id()).unwrap()
    }
    pub fn valid_player_mut<F>(&mut self, valid_player_id: MutID<ValidPlayerID<F>>) -> &mut P {
        self.players.get_mut(&valid_player_id.id().id()).unwrap()
    }
}

pub struct PlayerIDBuilder {
    next_player_id: usize,
}

impl PlayerIDBuilder {
    pub(crate) fn new() -> Self {
        PlayerIDBuilder { next_player_id: 0 }
    }
    /// Generates a unique player ID,
    /// call repeatedly for subsequent player IDs.
    pub fn generate_player_id(&mut self) -> PlayerID {
        let player_id = PlayerID(self.next_player_id);
        self.next_player_id += 1;
        player_id
    }
}