1use std::cmp;
2use std::fmt;
3use std::mem;
4
5use super::error::RSPokerError;
6
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[derive(PartialEq, PartialOrd, Eq, Ord, Debug, Clone, Copy, Hash)]
11pub enum Value {
12    Two = 0,
14    Three = 1,
16    Four = 2,
18    Five = 3,
20    Six = 4,
22    Seven = 5,
24    Eight = 6,
26    Nine = 7,
28    Ten = 8,
30    Jack = 9,
32    Queen = 10,
34    King = 11,
36    Ace = 12,
38}
39
40const VALUES: [Value; 13] = [
43    Value::Two,
44    Value::Three,
45    Value::Four,
46    Value::Five,
47    Value::Six,
48    Value::Seven,
49    Value::Eight,
50    Value::Nine,
51    Value::Ten,
52    Value::Jack,
53    Value::Queen,
54    Value::King,
55    Value::Ace,
56];
57
58impl Value {
59    pub fn from_u8(v: u8) -> Self {
68        Self::from(v)
69    }
70    pub const fn values() -> [Self; 13] {
75        VALUES
76    }
77
78    pub fn from_char(c: char) -> Option<Self> {
92        Self::try_from(c).ok()
93    }
94
95    pub fn to_char(self) -> char {
97        char::from(self)
98    }
99
100    pub fn gap(self, other: Self) -> u8 {
109        let min = cmp::min(self as u8, other as u8);
110        let max = cmp::max(self as u8, other as u8);
111        max - min
112    }
113}
114
115impl From<u8> for Value {
116    fn from(value: u8) -> Self {
117        unsafe { mem::transmute(cmp::min(value, Self::Ace as u8)) }
118    }
119}
120
121impl TryFrom<char> for Value {
122    type Error = RSPokerError;
123
124    fn try_from(value: char) -> Result<Self, Self::Error> {
132        match value.to_ascii_uppercase() {
133            'A' => Ok(Self::Ace),
134            'K' => Ok(Self::King),
135            'Q' => Ok(Self::Queen),
136            'J' => Ok(Self::Jack),
137            'T' => Ok(Self::Ten),
138            '9' => Ok(Self::Nine),
139            '8' => Ok(Self::Eight),
140            '7' => Ok(Self::Seven),
141            '6' => Ok(Self::Six),
142            '5' => Ok(Self::Five),
143            '4' => Ok(Self::Four),
144            '3' => Ok(Self::Three),
145            '2' => Ok(Self::Two),
146            _ => Err(RSPokerError::UnexpectedValueChar),
147        }
148    }
149}
150
151impl From<Value> for char {
152    fn from(value: Value) -> Self {
153        match value {
154            Value::Ace => 'A',
155            Value::King => 'K',
156            Value::Queen => 'Q',
157            Value::Jack => 'J',
158            Value::Ten => 'T',
159            Value::Nine => '9',
160            Value::Eight => '8',
161            Value::Seven => '7',
162            Value::Six => '6',
163            Value::Five => '5',
164            Value::Four => '4',
165            Value::Three => '3',
166            Value::Two => '2',
167        }
168    }
169}
170
171impl From<Value> for u8 {
191    fn from(value: Value) -> Self {
192        value as u8
193    }
194}
195
196#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
200#[derive(PartialEq, PartialOrd, Eq, Ord, Debug, Clone, Copy, Hash)]
201pub enum Suit {
202    Spade = 0,
204    Club = 1,
206    Heart = 2,
208    Diamond = 3,
210}
211
212const SUITS: [Suit; 4] = [Suit::Spade, Suit::Club, Suit::Heart, Suit::Diamond];
214
215impl Suit {
219    pub const fn suits() -> [Self; 4] {
229        SUITS
230    }
231
232    pub fn from_u8(s: u8) -> Self {
242        Self::from(s)
243    }
244
245    pub fn from_char(s: char) -> Option<Self> {
264        TryFrom::try_from(s).ok()
265    }
266
267    pub fn to_char(self) -> char {
269        char::from(self)
270    }
271}
272
273impl From<u8> for Suit {
274    fn from(value: u8) -> Self {
275        unsafe { mem::transmute(cmp::min(value, Self::Diamond as u8)) }
276    }
277}
278
279impl From<Suit> for u8 {
280    fn from(value: Suit) -> Self {
281        value as u8
282    }
283}
284
285impl TryFrom<char> for Suit {
286    type Error = RSPokerError;
287
288    fn try_from(value: char) -> Result<Self, Self::Error> {
289        match value.to_ascii_lowercase() {
290            'd' => Ok(Self::Diamond),
291            's' => Ok(Self::Spade),
292            'h' => Ok(Self::Heart),
293            'c' => Ok(Self::Club),
294            _ => Err(RSPokerError::UnexpectedSuitChar),
295        }
296    }
297}
298
299impl From<Suit> for char {
300    fn from(value: Suit) -> Self {
301        match value {
302            Suit::Diamond => 'd',
303            Suit::Spade => 's',
304            Suit::Heart => 'h',
305            Suit::Club => 'c',
306        }
307    }
308}
309
310#[derive(PartialEq, PartialOrd, Eq, Ord, Clone, Copy, Hash)]
313pub struct Card {
314    pub value: Value,
316    pub suit: Suit,
318}
319
320impl Card {
321    pub fn new(value: Value, suit: Suit) -> Self {
332        Self { value, suit }
333    }
334}
335
336impl From<Card> for u8 {
337    fn from(card: Card) -> Self {
338        u8::from(card.suit) * 13 + u8::from(card.value)
339    }
340}
341
342impl From<u8> for Card {
343    fn from(value: u8) -> Self {
344        Self {
345            value: Value::from(value % 13),
346            suit: Suit::from(value / 13),
347        }
348    }
349}
350
351impl fmt::Debug for Card {
352    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
353        write!(
354            f,
355            "Card({}{})",
356            char::from(self.value),
357            char::from(self.suit)
358        )
359    }
360}
361
362impl fmt::Display for Card {
363    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
364        write!(f, "{}{}", char::from(self.value), char::from(self.suit))
365    }
366}
367
368impl TryFrom<&str> for Card {
369    type Error = RSPokerError;
370
371    fn try_from(value: &str) -> Result<Self, Self::Error> {
372        let mut chars = value.chars();
373        let value_char = chars.next().ok_or(RSPokerError::TooFewChars)?;
374        let suit_char = chars.next().ok_or(RSPokerError::TooFewChars)?;
375        Ok(Self {
376            value: Value::try_from(value_char)?,
377            suit: Suit::try_from(suit_char)?,
378        })
379    }
380}
381
382#[cfg(feature = "serde")]
383impl serde::Serialize for Card {
384    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
385    where
386        S: serde::Serializer,
387    {
388        serializer.serialize_str(&self.to_string())
390    }
391}
392
393#[cfg(feature = "serde")]
394impl<'de> serde::Deserialize<'de> for Card {
395    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
396    where
397        D: serde::Deserializer<'de>,
398    {
399        let s = String::deserialize(deserializer)?;
400        Card::try_from(s.as_str()).map_err(serde::de::Error::custom)
401    }
402}
403
404#[cfg(test)]
405mod tests {
406    use super::*;
407
408    #[test]
409    fn test_constructor() {
410        let c = Card {
411            value: Value::Three,
412            suit: Suit::Spade,
413        };
414        assert_eq!(Suit::Spade, c.suit);
415        assert_eq!(Value::Three, c.value);
416    }
417
418    #[test]
419    fn test_suit_from_u8() {
420        assert_eq!(Suit::Spade, Suit::from_u8(0));
421        assert_eq!(Suit::Club, Suit::from_u8(1));
422        assert_eq!(Suit::Heart, Suit::from_u8(2));
423        assert_eq!(Suit::Diamond, Suit::from_u8(3));
424    }
425
426    #[test]
427    fn test_value_from_u8() {
428        assert_eq!(Value::Two, Value::from_u8(0));
429        assert_eq!(Value::Ace, Value::from_u8(12));
430    }
431
432    #[test]
433    fn test_roundtrip_from_u8_all_cards() {
434        for suit in SUITS {
435            for value in VALUES {
436                let c = Card { suit, value };
437                let u = u8::from(c);
438                assert_eq!(c, Card::from(u));
439            }
440        }
441    }
442
443    #[test]
444    fn test_try_parse_card() {
445        let expected = Card {
446            value: Value::King,
447            suit: Suit::Spade,
448        };
449
450        assert_eq!(expected, Card::try_from("Ks").unwrap())
451    }
452
453    #[test]
454    fn test_parse_all_cards() {
455        for suit in SUITS {
456            for value in VALUES {
457                let e = Card { suit, value };
458                let card_string = format!("{}{}", char::from(value), char::from(suit));
459                assert_eq!(e, Card::try_from(card_string.as_str()).unwrap());
460            }
461        }
462    }
463
464    #[test]
465    fn test_compare() {
466        let c1 = Card {
467            value: Value::Three,
468            suit: Suit::Spade,
469        };
470        let c2 = Card {
471            value: Value::Four,
472            suit: Suit::Spade,
473        };
474        let c3 = Card {
475            value: Value::Four,
476            suit: Suit::Club,
477        };
478
479        assert!(c1 < c2);
481        assert!(c2 > c1);
482        assert!(c3 > c2);
484    }
485
486    #[test]
487    fn test_value_cmp() {
488        assert!(Value::Two < Value::Ace);
489        assert!(Value::King < Value::Ace);
490        assert_eq!(Value::Two, Value::Two);
491    }
492
493    #[test]
494    fn test_from_u8() {
495        assert_eq!(Value::Two, Value::from_u8(0));
496        assert_eq!(Value::Ace, Value::from_u8(12));
497    }
498
499    #[test]
500    fn test_size_card() {
501        assert!(mem::size_of::<Card>() <= 2);
503    }
504
505    #[test]
506    fn test_size_suit() {
507        assert!(mem::size_of::<Suit>() <= 1);
509    }
510
511    #[test]
512    fn test_size_value() {
513        assert!(mem::size_of::<Value>() <= 1);
515    }
516
517    #[test]
518    fn test_gap() {
519        assert!(1 == Value::Ace.gap(Value::King));
521        assert!(0 == Value::Ace.gap(Value::Ace));
523        assert!(0 == Value::Two.gap(Value::Two));
525        assert!(1 == Value::Two.gap(Value::Three));
527        assert!(1 == Value::Three.gap(Value::Two));
529        assert!(12 == Value::Ace.gap(Value::Two));
531        assert!(12 == Value::Two.gap(Value::Ace));
532    }
533
534    #[test]
535    fn test_suit_to_char() {
536        let s = Suit::Spade;
537        assert_eq!('s', s.to_char());
538
539        let s = Suit::Club;
540        assert_eq!('c', s.to_char());
541
542        let s = Suit::Heart;
543        assert_eq!('h', s.to_char());
544
545        let s = Suit::Diamond;
546        assert_eq!('d', s.to_char());
547    }
548
549    #[test]
550    fn test_value_to_char() {
551        let v = Value::Ace;
552        assert_eq!('A', v.to_char());
553
554        let v = Value::King;
555        assert_eq!('K', v.to_char());
556
557        let v = Value::Queen;
558        assert_eq!('Q', v.to_char());
559
560        let v = Value::Jack;
561        assert_eq!('J', v.to_char());
562
563        let v = Value::Ten;
564        assert_eq!('T', v.to_char());
565
566        for i in 2..=9 {
567            let v = Value::from(i - 2);
570            assert_eq!(char::from_digit(u32::from(i), 10).unwrap(), v.to_char());
571        }
572    }
573}