use crate::funky::types::draws::Draws;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
#[derive(
Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize,
)]
pub enum BossBlind {
#[default]
TheNeedle,
TheWater,
TheManacle,
}
impl BossBlind {
#[must_use]
pub fn apply(self, mut draws: Draws) -> Draws {
match self {
Self::TheNeedle => draws.hands_to_play = 1,
Self::TheWater => draws.discards = 0,
Self::TheManacle => draws.hand_size = draws.hand_size.saturating_sub(1),
}
draws
}
}
impl Display for BossBlind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::TheNeedle => write!(f, "The Needle"),
Self::TheWater => write!(f, "The Water"),
Self::TheManacle => write!(f, "The Manacle"),
}
}
}
#[derive(
Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize,
)]
pub enum Blind {
#[default]
Small,
Big,
Boss(BossBlind),
}
impl Blind {
#[must_use]
pub fn is_boss(self) -> bool {
matches!(self, Self::Boss(_))
}
#[must_use]
pub fn boss(self) -> Option<BossBlind> {
match self {
Self::Boss(boss) => Some(boss),
_ => None,
}
}
}
impl Display for Blind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Small => write!(f, "Small Blind"),
Self::Big => write!(f, "Big Blind"),
Self::Boss(boss) => write!(f, "{boss}"),
}
}
}
#[cfg(test)]
#[allow(non_snake_case)]
mod funky__types__blind_tests {
use super::*;
#[test]
fn default__is_the_small_blind() {
assert_eq!(Blind::default(), Blind::Small);
assert!(!Blind::default().is_boss());
}
#[test]
fn is_boss__separates_identity_from_the_ability() {
assert!(Blind::Boss(BossBlind::TheNeedle).is_boss());
assert!(!Blind::Small.is_boss());
assert!(!Blind::Big.is_boss());
assert_eq!(
Blind::Boss(BossBlind::TheWater).boss(),
Some(BossBlind::TheWater)
);
assert_eq!(Blind::Small.boss(), None);
}
#[test]
fn apply__the_needle_leaves_exactly_one_hand() {
let draws = BossBlind::TheNeedle.apply(Draws::new(4, 3));
assert_eq!(draws.hands_to_play, 1);
assert_eq!(draws.discards, 3, "it does not touch discards");
}
#[test]
fn apply__the_water_leaves_no_discards() {
let draws = BossBlind::TheWater.apply(Draws::new(4, 3));
assert_eq!(draws.discards, 0);
assert_eq!(draws.hands_to_play, 4, "it does not touch hands");
}
#[test]
fn apply__the_manacle_shrinks_the_hand_by_one() {
let draws = BossBlind::TheManacle.apply(Draws::new(4, 3));
assert_eq!(draws.hand_size, Draws::DEFAULT_HAND_SIZE - 1);
let mut tiny = Draws::new(4, 3);
tiny.hand_size = 0;
assert_eq!(BossBlind::TheManacle.apply(tiny).hand_size, 0);
}
#[test]
fn display() {
assert_eq!(Blind::Small.to_string(), "Small Blind");
assert_eq!(Blind::Big.to_string(), "Big Blind");
assert_eq!(Blind::Boss(BossBlind::TheNeedle).to_string(), "The Needle");
assert_eq!(
Blind::Boss(BossBlind::TheManacle).to_string(),
"The Manacle"
);
}
}