Skip to main content

games/
cards.rs

1//! Standard Cards for traditional card games (Solitaire, BlackJack, etc)
2//!
3//! CardError: Parsing Error
4//!
5//! StandardCardFace: Your Traditional Card Faces (Meant to be used with StandardCard)
6//!
7//! StandardCard: Your Traditional Card Face + Suite
8//!
9//! ```
10//! use games::cards::{StandardCard, StandardCardFace};
11//! use games::color::Color;
12//! let card: StandardCard = match "HEARTS:ACE".parse() {
13//!     Ok(card) => card,
14//!     Err(_) => {
15//!         println!("Invalid Card!");
16//!         return
17//!     }
18//! };
19//! match card.color() {
20//!     Color::Red => println!("{} is Red", card),
21//!     Color::Black => println!("{} is Black", card),
22//!     _ => unreachable!()
23//! }
24//! ```
25use crate::color::Color;
26use core::fmt::{self, Display};
27use core::str::FromStr;
28
29use crate::errors::{BASE_CARD_ERROR_CODE, ErrorCode};
30
31#[repr(C)]
32#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
33/// Card error
34pub enum CardError {
35    /// Attempted to parse an invalid card (1001)
36    // #[fail(display = "Invalid Card")]
37    InvalidCardError,
38}
39
40impl fmt::Display for CardError {
41    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42        match *self {
43            CardError::InvalidCardError => f.write_str("Invalid Card"),
44        }
45    }
46}
47
48impl ErrorCode for CardError {
49    fn error_code(&self) -> i32 {
50        BASE_CARD_ERROR_CODE
51            + match *self {
52                CardError::InvalidCardError => 1,
53            }
54    }
55}
56
57/// Card Faces
58#[repr(C)]
59#[derive(
60    Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Ord, PartialOrd, Hash,
61)]
62pub enum StandardCardFace {
63    /// ACE
64    Ace,
65    /// Twos
66    Two,
67    /// Threes
68    Three,
69    /// Fours
70    Four,
71    /// Fives
72    Five,
73    /// Sixes
74    Six,
75    /// Sevens
76    Seven,
77    /// Eights
78    Eight,
79    /// Nines
80    Nine,
81    /// Tens
82    Ten,
83    /// Jacks
84    Jack,
85    /// Kings
86    King,
87    /// Queens
88    Queen,
89    /// Joker
90    Joker,
91}
92
93impl Display for StandardCardFace {
94    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95        write!(
96            f,
97            "{}",
98            match self {
99                StandardCardFace::Ace => "ACE",
100                StandardCardFace::Two => "TWO",
101                StandardCardFace::Three => "THREE",
102                StandardCardFace::Four => "FOUR",
103                StandardCardFace::Five => "FIVE",
104                StandardCardFace::Six => "SIX",
105                StandardCardFace::Seven => "SEVEN",
106                StandardCardFace::Eight => "EIGHT",
107                StandardCardFace::Nine => "NINE",
108                StandardCardFace::Ten => "TEN",
109                StandardCardFace::Jack => "JACK",
110                StandardCardFace::King => "KING",
111                StandardCardFace::Queen => "Queen",
112                StandardCardFace::Joker => "JOKER",
113            }
114        )
115    }
116}
117impl FromStr for StandardCardFace {
118    type Err = CardError;
119
120    fn from_str(s: &str) -> Result<Self, Self::Err> {
121        match s {
122            "ACE" => Ok(StandardCardFace::Ace),
123            "TWO" => Ok(StandardCardFace::Two),
124            "THREE" => Ok(StandardCardFace::Three),
125            "FOUR" => Ok(StandardCardFace::Four),
126            "FIVE" => Ok(StandardCardFace::Five),
127            "SIX" => Ok(StandardCardFace::Six),
128            "SEVEN" => Ok(StandardCardFace::Seven),
129            "EIGHT" => Ok(StandardCardFace::Eight),
130            "NINE" => Ok(StandardCardFace::Nine),
131            "TEN" => Ok(StandardCardFace::Ten),
132            "JACK" => Ok(StandardCardFace::Jack),
133            "KING" => Ok(StandardCardFace::King),
134            "QUEEN" => Ok(StandardCardFace::Queen),
135            "JOKER" => Ok(StandardCardFace::Joker),
136            _ => Err(CardError::InvalidCardError),
137        }
138    }
139}
140
141/// Standard Card
142#[repr(C)]
143#[derive(
144    Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Ord, PartialOrd, Hash,
145)]
146pub enum StandardCard {
147    /// Clubs
148    Clubs(StandardCardFace),
149    /// Diamonds
150    Diamonds(StandardCardFace),
151    /// Hearts
152    Hearts(StandardCardFace),
153    /// Spades
154    Spades(StandardCardFace),
155}
156
157impl Display for StandardCard {
158    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159        write!(
160            f,
161            "{}",
162            match self {
163                StandardCard::Hearts(inner) => format!("HEARTS:{}", inner),
164                StandardCard::Spades(inner) => format!("SPADES:{}", inner),
165                StandardCard::Clubs(inner) => format!("CLUBS:{}", inner),
166                StandardCard::Diamonds(inner) => format!("DIAMONDS:{}", inner),
167            }
168        )
169    }
170}
171
172impl FromStr for StandardCard {
173    type Err = CardError;
174    fn from_str(s: &str) -> Result<Self, Self::Err> {
175        let txt = s.to_uppercase();
176        let mut txt = txt.split(':');
177        let card = txt.next().ok_or(CardError::InvalidCardError)?;
178        let face: StandardCardFace = txt.next().ok_or(CardError::InvalidCardError)?.parse()?;
179        match card {
180            "HEARTS" => Ok(StandardCard::Hearts(face)),
181            "SPADES" => Ok(StandardCard::Spades(face)),
182            "CLUBS" => Ok(StandardCard::Clubs(face)),
183            "DIAMONDS" => Ok(StandardCard::Diamonds(face)),
184            _ => Err(CardError::InvalidCardError),
185        }
186    }
187}
188
189impl StandardCard {
190    /// Get the Card's face
191    pub fn face(self) -> StandardCardFace {
192        StandardCardFace::from(self)
193    }
194    /// The cards suite as a string
195    pub fn suite_string(self) -> &'static str {
196        match self {
197            StandardCard::Hearts(_) => "Hearts",
198            StandardCard::Clubs(_) => "Clubs",
199            StandardCard::Spades(_) => "Spades",
200            StandardCard::Diamonds(_) => "Diamonds",
201        }
202    }
203    /// Cards face as a string
204    pub fn face_to_string(self) -> String {
205        self.face().to_string()
206    }
207    /// Return the color of the card's suite
208    pub fn color(self) -> Color {
209        match self {
210            StandardCard::Hearts(_) | StandardCard::Diamonds(_) => Color::Red,
211            StandardCard::Clubs(_) | StandardCard::Spades(_) => Color::Black,
212        }
213    }
214    /// Check if the suites of the cards are equal
215    pub fn eq_suite(self, card: StandardCard) -> bool {
216        match self {
217            StandardCard::Hearts(_) => matches!(card, StandardCard::Hearts(_)),
218            StandardCard::Spades(_) => matches!(card, StandardCard::Spades(_)),
219            StandardCard::Clubs(_) => matches!(card, StandardCard::Clubs(_)),
220            StandardCard::Diamonds(_) => matches!(card, StandardCard::Diamonds(_)),
221        }
222    }
223}
224
225impl StandardCardFace {
226    /// Returns the numerical value of a Face by blackjack standards
227    /// Please note, Ace can be both 11 and 1 but is 11 in this instance
228    pub fn value(self) -> u8 {
229        u8::from(self)
230    }
231}
232
233impl From<StandardCard> for StandardCardFace {
234    fn from(card: StandardCard) -> StandardCardFace {
235        match card {
236            StandardCard::Hearts(inner) => inner,
237            StandardCard::Spades(inner) => inner,
238            StandardCard::Clubs(inner) => inner,
239            StandardCard::Diamonds(inner) => inner,
240        }
241    }
242}
243
244impl From<StandardCardFace> for u8 {
245    fn from(face: StandardCardFace) -> u8 {
246        match face {
247            StandardCardFace::Ace => 11,
248            StandardCardFace::Two => 2,
249            StandardCardFace::Three => 3,
250            StandardCardFace::Four => 4,
251            StandardCardFace::Five => 5,
252            StandardCardFace::Six => 6,
253            StandardCardFace::Seven => 7,
254            StandardCardFace::Eight => 8,
255            StandardCardFace::Nine => 9,
256            _ => 10,
257        }
258    }
259}
260
261impl From<StandardCard> for u8 {
262    fn from(card: StandardCard) -> u8 {
263        u8::from(StandardCardFace::from(card))
264    }
265}