games-rs 0.5.0

Pre-implemented games written in rust.
Documentation
//! Standard Cards for traditional card games (Solitaire, BlackJack, etc)
//!
//! CardError: Parsing Error
//!
//! StandardCardFace: Your Traditional Card Faces (Meant to be used with StandardCard)
//!
//! StandardCard: Your Traditional Card Face + Suite
//!
//! ```
//! use games::cards::{StandardCard, StandardCardFace};
//! use games::color::Color;
//! let card: StandardCard = match "HEARTS:ACE".parse() {
//!     Ok(card) => card,
//!     Err(_) => {
//!         println!("Invalid Card!");
//!         return
//!     }
//! };
//! match card.color() {
//!     Color::Red => println!("{} is Red", card),
//!     Color::Black => println!("{} is Black", card),
//!     _ => unreachable!()
//! }
//! ```
use crate::color::Color;
use core::fmt::{self, Display};
use core::str::FromStr;

use crate::errors::{BASE_CARD_ERROR_CODE, ErrorCode};

#[repr(C)]
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
/// Card error
pub enum CardError {
    /// Attempted to parse an invalid card (1001)
    // #[fail(display = "Invalid Card")]
    InvalidCardError,
}

impl fmt::Display for CardError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CardError::InvalidCardError => f.write_str("Invalid Card"),
        }
    }
}

impl ErrorCode for CardError {
    fn error_code(&self) -> i32 {
        BASE_CARD_ERROR_CODE
            + match *self {
                CardError::InvalidCardError => 1,
            }
    }
}

/// Card Faces
#[repr(C)]
#[derive(
    Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Ord, PartialOrd, Hash,
)]
pub enum StandardCardFace {
    /// ACE
    Ace,
    /// Twos
    Two,
    /// Threes
    Three,
    /// Fours
    Four,
    /// Fives
    Five,
    /// Sixes
    Six,
    /// Sevens
    Seven,
    /// Eights
    Eight,
    /// Nines
    Nine,
    /// Tens
    Ten,
    /// Jacks
    Jack,
    /// Kings
    King,
    /// Queens
    Queen,
    /// Joker
    Joker,
}

impl Display for StandardCardFace {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}",
            match self {
                StandardCardFace::Ace => "ACE",
                StandardCardFace::Two => "TWO",
                StandardCardFace::Three => "THREE",
                StandardCardFace::Four => "FOUR",
                StandardCardFace::Five => "FIVE",
                StandardCardFace::Six => "SIX",
                StandardCardFace::Seven => "SEVEN",
                StandardCardFace::Eight => "EIGHT",
                StandardCardFace::Nine => "NINE",
                StandardCardFace::Ten => "TEN",
                StandardCardFace::Jack => "JACK",
                StandardCardFace::King => "KING",
                StandardCardFace::Queen => "Queen",
                StandardCardFace::Joker => "JOKER",
            }
        )
    }
}
impl FromStr for StandardCardFace {
    type Err = CardError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "ACE" => Ok(StandardCardFace::Ace),
            "TWO" => Ok(StandardCardFace::Two),
            "THREE" => Ok(StandardCardFace::Three),
            "FOUR" => Ok(StandardCardFace::Four),
            "FIVE" => Ok(StandardCardFace::Five),
            "SIX" => Ok(StandardCardFace::Six),
            "SEVEN" => Ok(StandardCardFace::Seven),
            "EIGHT" => Ok(StandardCardFace::Eight),
            "NINE" => Ok(StandardCardFace::Nine),
            "TEN" => Ok(StandardCardFace::Ten),
            "JACK" => Ok(StandardCardFace::Jack),
            "KING" => Ok(StandardCardFace::King),
            "QUEEN" => Ok(StandardCardFace::Queen),
            "JOKER" => Ok(StandardCardFace::Joker),
            _ => Err(CardError::InvalidCardError),
        }
    }
}

/// Standard Card
#[repr(C)]
#[derive(
    Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Ord, PartialOrd, Hash,
)]
pub enum StandardCard {
    /// Clubs
    Clubs(StandardCardFace),
    /// Diamonds
    Diamonds(StandardCardFace),
    /// Hearts
    Hearts(StandardCardFace),
    /// Spades
    Spades(StandardCardFace),
}

impl Display for StandardCard {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}",
            match self {
                StandardCard::Hearts(inner) => format!("HEARTS:{}", inner),
                StandardCard::Spades(inner) => format!("SPADES:{}", inner),
                StandardCard::Clubs(inner) => format!("CLUBS:{}", inner),
                StandardCard::Diamonds(inner) => format!("DIAMONDS:{}", inner),
            }
        )
    }
}

impl FromStr for StandardCard {
    type Err = CardError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let txt = s.to_uppercase();
        let mut txt = txt.split(':');
        let card = txt.next().ok_or(CardError::InvalidCardError)?;
        let face: StandardCardFace = txt.next().ok_or(CardError::InvalidCardError)?.parse()?;
        match card {
            "HEARTS" => Ok(StandardCard::Hearts(face)),
            "SPADES" => Ok(StandardCard::Spades(face)),
            "CLUBS" => Ok(StandardCard::Clubs(face)),
            "DIAMONDS" => Ok(StandardCard::Diamonds(face)),
            _ => Err(CardError::InvalidCardError),
        }
    }
}

impl StandardCard {
    /// Get the Card's face
    pub fn face(self) -> StandardCardFace {
        StandardCardFace::from(self)
    }
    /// The cards suite as a string
    pub fn suite_string(self) -> &'static str {
        match self {
            StandardCard::Hearts(_) => "Hearts",
            StandardCard::Clubs(_) => "Clubs",
            StandardCard::Spades(_) => "Spades",
            StandardCard::Diamonds(_) => "Diamonds",
        }
    }
    /// Cards face as a string
    pub fn face_to_string(self) -> String {
        self.face().to_string()
    }
    /// Return the color of the card's suite
    pub fn color(self) -> Color {
        match self {
            StandardCard::Hearts(_) | StandardCard::Diamonds(_) => Color::Red,
            StandardCard::Clubs(_) | StandardCard::Spades(_) => Color::Black,
        }
    }
    /// Check if the suites of the cards are equal
    pub fn eq_suite(self, card: StandardCard) -> bool {
        match self {
            StandardCard::Hearts(_) => matches!(card, StandardCard::Hearts(_)),
            StandardCard::Spades(_) => matches!(card, StandardCard::Spades(_)),
            StandardCard::Clubs(_) => matches!(card, StandardCard::Clubs(_)),
            StandardCard::Diamonds(_) => matches!(card, StandardCard::Diamonds(_)),
        }
    }
}

impl StandardCardFace {
    /// Returns the numerical value of a Face by blackjack standards
    /// Please note, Ace can be both 11 and 1 but is 11 in this instance
    pub fn value(self) -> u8 {
        u8::from(self)
    }
}

impl From<StandardCard> for StandardCardFace {
    fn from(card: StandardCard) -> StandardCardFace {
        match card {
            StandardCard::Hearts(inner) => inner,
            StandardCard::Spades(inner) => inner,
            StandardCard::Clubs(inner) => inner,
            StandardCard::Diamonds(inner) => inner,
        }
    }
}

impl From<StandardCardFace> for u8 {
    fn from(face: StandardCardFace) -> u8 {
        match face {
            StandardCardFace::Ace => 11,
            StandardCardFace::Two => 2,
            StandardCardFace::Three => 3,
            StandardCardFace::Four => 4,
            StandardCardFace::Five => 5,
            StandardCardFace::Six => 6,
            StandardCardFace::Seven => 7,
            StandardCardFace::Eight => 8,
            StandardCardFace::Nine => 9,
            _ => 10,
        }
    }
}

impl From<StandardCard> for u8 {
    fn from(card: StandardCard) -> u8 {
        u8::from(StandardCardFace::from(card))
    }
}