games-rs 0.5.0

Pre-implemented games written in rust.
Documentation
//! Coin Toss, make a prediction on which side the coin will land
//! ```rust
//! use games::coin_toss::*;
//! fn main() -> Result<(), CoinError> {
//!     // Method A
//!     if CoinToss::guess(Coin::Heads).is_correct() {
//!         println!("You guessed correctly for A");
//!     }
//!     // Method B
//!     if CoinToss::guess("Heads".parse()?).is_correct() {
//!         println!("You guessed correctly for B");
//!     }
//!     // Method C
//!     if CoinToss::guess(Coin::flip()).is_correct() {
//!         println!("Fate loves you");
//!     }
//!     Ok(())
//! }
//! ```
use crate::errors::{BASE_COIN_TOSS_ERROR_CODE, ErrorCode};

use core::fmt;

use rand::RngExt;

/// Error raised by Coin Toss
#[repr(C)]
#[derive(
    Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, PartialOrd, Ord, Hash,
)]
pub enum CoinError {
    /// Failed to parse coin side (5001)
    InvalidSideError,
}

impl fmt::Display for CoinError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CoinError::InvalidSideError => f.write_str("Not a valid side"),
        }
    }
}

impl ErrorCode for CoinError {
    fn error_code(&self) -> i32 {
        BASE_COIN_TOSS_ERROR_CODE
            + match *self {
                CoinError::InvalidSideError => 1,
            }
    }
}

/// Enum representing a coin
#[derive(
    Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
pub enum Coin {
    /// Head side of the coin
    Heads,
    /// Tails side of the coin
    Tails,
}

impl Coin {
    /// Flips a coin, returning a Coin with its current Side up
    pub fn flip() -> Coin {
        Coin::from(crate::get_rng().random_bool(0.5))
    }
}

impl fmt::Display for Coin {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Coin::Heads => f.write_str("Heads"),
            Coin::Tails => f.write_str("Tails"),
        }
    }
}

/// Coin toss struct
#[derive(
    Copy, Clone, Debug, serde::Serialize, serde::Deserialize, Ord, PartialOrd, PartialEq, Eq, Hash,
)]
pub struct CoinToss {
    /// The coin's state that the player guessed
    pub guess: Coin,
    /// The coin's state that happened after the toss
    pub real: Coin,
}

impl From<CoinToss> for bool {
    fn from(val: CoinToss) -> Self {
        val.guess == val.real
    }
}

impl core::str::FromStr for Coin {
    type Err = CoinError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let guess = s.to_ascii_lowercase();
        if ["heads", "h", "t", "tails"].contains(&guess.as_str()) {
            Ok(Coin::from(guess.starts_with('h')))
        } else {
            Err(CoinError::InvalidSideError)
        }
    }
}

impl From<bool> for Coin {
    fn from(b: bool) -> Coin {
        if b { Coin::Heads } else { Coin::Tails }
    }
}

impl fmt::Display for CoinToss {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Guess: {}\nResult: {}", self.guess, self.real)
    }
}

impl CoinToss {
    /// Make a guess on what side the coin will land on
    pub fn guess(guess: Coin) -> Self {
        CoinToss {
            guess,
            real: Coin::flip(),
        }
    }
    /// Returns if the guess was correct
    pub fn is_correct(self) -> bool {
        self.real == self.guess
    }
}