use crate::errors::{BASE_COIN_TOSS_ERROR_CODE, ErrorCode};
use core::fmt;
use rand::RngExt;
#[repr(C)]
#[derive(
Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, PartialOrd, Ord, Hash,
)]
pub enum CoinError {
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,
}
}
}
#[derive(
Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
pub enum Coin {
Heads,
Tails,
}
impl Coin {
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"),
}
}
}
#[derive(
Copy, Clone, Debug, serde::Serialize, serde::Deserialize, Ord, PartialOrd, PartialEq, Eq, Hash,
)]
pub struct CoinToss {
pub guess: Coin,
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 {
pub fn guess(guess: Coin) -> Self {
CoinToss {
guess,
real: Coin::flip(),
}
}
pub fn is_correct(self) -> bool {
self.real == self.guess
}
}