use std::str::FromStr; use mental_poker::{game::AttestedCard, game::AttestedDeckCard, Card, DeckType}; #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, PartialOrd, Ord)] pub(crate) enum GoFishDeck {} impl DeckType for GoFishDeck { const SIZE: usize = 52; } #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] pub(crate) enum Suit { A, B, C, D, } #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)] pub(crate) struct Rank(u8); impl Rank { const MAX: u8 = 12; pub fn all() -> impl Iterator { (0..=Self::MAX).map(Rank) } } pub(crate) enum RankParseError { Parse(::Err), OutOfBounds(u8), } #[derive(PartialEq, Eq, Hash, Debug, Default, Copy, Clone)] pub(crate) struct UnknownCard; #[derive(PartialEq, Eq, Hash)] pub(crate) struct SomeRank; #[derive(PartialEq, Eq, Hash)] pub(crate) struct SomeValue; #[derive(Copy, Clone, PartialEq, Eq, std::hash::Hash)] pub(crate) struct GoFishCard(Card); #[derive(Copy, Clone, PartialEq, Eq, std::hash::Hash)] pub(crate) struct AttestedGoFishCard(AttestedCard); impl FromStr for Rank { type Err = RankParseError; fn from_str(s: &str) -> Result { u8::from_str(s) .map_err(RankParseError::Parse) .and_then(|u| u.try_into().map_err(RankParseError::OutOfBounds)) } } impl std::fmt::Display for Rank { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!("rank {}", self.0)) } } impl std::error::Error for Rank {} impl TryFrom for Rank { type Error = u8; fn try_from(v: u8) -> Result { if v <= Self::MAX { Ok(Self(v.try_into().unwrap())) } else { Err(v) } } } impl TryFrom for Suit { type Error = u8; fn try_from(value: u8) -> Result { match value { 0 => Ok(Suit::A), 1 => Ok(Suit::B), 2 => Ok(Suit::C), 3 => Ok(Suit::D), x => Err(x), } } } impl From for u8 { fn from(r: Rank) -> u8 { r.0 } } impl std::fmt::Debug for GoFishCard { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("GoFishCard") .field(&self.rank()) .field(&self.suit()) .finish() } } impl std::fmt::Debug for AttestedGoFishCard { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!("Attested({:?})", GoFishCard(*self.0.card()))) } } pub(crate) trait GoFishDeckCard { fn rank(&self) -> Rank; fn suit(&self) -> Suit; } impl GoFishDeckCard for GoFishCard { fn rank(&self) -> Rank { self.0.rank() } fn suit(&self) -> Suit { self.0.suit() } } impl GoFishDeckCard for Card { fn rank(&self) -> Rank { (self.index() as u8 % (Rank::MAX + 1)).try_into().unwrap() } fn suit(&self) -> Suit { (self.index() as u8 / (Rank::MAX + 1)).try_into().unwrap() } } impl GoFishDeckCard for AttestedGoFishCard { fn rank(&self) -> Rank { self.0.card().rank() } fn suit(&self) -> Suit { self.0.card().suit() } } impl From for Card { fn from(c: GoFishCard) -> Self { c.0 } } impl<'a> From<&'a AttestedGoFishCard> for &'a AttestedCard { fn from(c: &'a AttestedGoFishCard) -> &'a AttestedCard { &c.0 } } impl Into> for AttestedGoFishCard { fn into(self) -> AttestedCard { self.0 } } impl From> for GoFishCard { fn from(card: Card) -> Self { Self(card) } } impl From> for AttestedGoFishCard { fn from(card: AttestedCard) -> Self { Self(card) } } impl From> for AttestedGoFishCard { fn from(card: AttestedDeckCard) -> Self { Self(card.into()) } } impl AsRef> for GoFishCard { fn as_ref(&self) -> &Card { &self.0 } } impl AsRef> for AttestedGoFishCard { fn as_ref(&self) -> &AttestedCard { &self.0 } } impl From for SomeRank { fn from(_: Rank) -> Self { Self {} } } impl From> for SomeValue { fn from(_: Card) -> Self { Self {} } }