openpql_prelude/game/
game.rs

1use super::{
2    Board, Card64, CardCount, FlopHandCategory, FromStr, HandRating,
3    ParseError, eval_flop_holdem, eval_flop_omaha, eval_holdem, eval_omaha,
4    eval_shortdeck,
5};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8pub enum Game {
9    #[default]
10    Holdem,
11    Omaha,
12    ShortDeck,
13}
14
15impl Game {
16    pub const fn player_cards_len(self) -> CardCount {
17        match self {
18            Self::Holdem | Self::ShortDeck => 2,
19            Self::Omaha => 4,
20        }
21    }
22
23    pub const fn is_shortdeck(self) -> bool {
24        matches!(self, Self::ShortDeck)
25    }
26
27    pub fn eval_rating(self, player: Card64, board: Card64) -> HandRating {
28        match self {
29            Self::Holdem => eval_holdem(player | board),
30            Self::ShortDeck => eval_shortdeck(player | board),
31            Self::Omaha => eval_omaha(player, board),
32        }
33    }
34
35    pub fn eval_flop_category(
36        self,
37        player: Card64,
38        board: Board,
39    ) -> FlopHandCategory {
40        match self {
41            Self::Holdem | Self::ShortDeck => eval_flop_holdem(player, board),
42            Self::Omaha => eval_flop_omaha(player, board),
43        }
44    }
45}
46
47impl FromStr for Game {
48    type Err = ParseError;
49
50    fn from_str(s: &str) -> Result<Self, Self::Err> {
51        match s.to_ascii_lowercase().trim() {
52            "holdem" => Ok(Self::Holdem),
53            "omaha" => Ok(Self::Omaha),
54            "shortdeck" => Ok(Self::ShortDeck),
55            _ => Err(ParseError::InvalidGame(s.into())),
56        }
57    }
58}
59
60#[cfg(any(test, feature = "quickcheck"))]
61impl quickcheck::Arbitrary for Game {
62    #[cfg_attr(coverage_nightly, coverage(off))]
63    fn arbitrary(g: &mut quickcheck::Gen) -> Self {
64        #[allow(unused)]
65        const fn completeness_check(e: Game) {
66            match e {
67                Game::Holdem | Game::Omaha | Game::ShortDeck => (),
68            }
69        }
70
71        *g.choose(&[Self::Holdem, Self::Omaha, Self::ShortDeck])
72            .unwrap()
73    }
74}
75
76#[cfg(test)]
77#[cfg_attr(coverage_nightly, coverage(off))]
78mod tests {
79    use super::*;
80    use crate::*;
81
82    #[test]
83    fn test_player_cards_len() {
84        assert_eq!(2, Game::Holdem.player_cards_len());
85        assert_eq!(4, Game::Omaha.player_cards_len());
86        assert_eq!(2, Game::ShortDeck.player_cards_len());
87    }
88
89    #[test]
90    fn test_is_shortdeck() {
91        assert!(!Game::Holdem.is_shortdeck());
92        assert!(!Game::Omaha.is_shortdeck());
93        assert!(Game::ShortDeck.is_shortdeck());
94    }
95
96    #[test]
97    fn test_from_str() {
98        assert_eq!(Ok(Game::Holdem), " HoldEM ".parse());
99
100        assert_eq!(Ok(Game::Omaha), "omaha".parse());
101        assert_eq!(Ok(Game::ShortDeck), "shortdeck".parse());
102
103        assert_eq!(
104            Err(ParseError::InvalidGame("unknown".into())),
105            "unknown".parse::<Game>()
106        );
107    }
108
109    #[quickcheck]
110    fn test_eval_rating_args(cs: CardN<5>) {
111        let c5 = Card64::from(cs.as_slice());
112        let (c3, c2): (CardN<3>, CardN<2>) = cs.into();
113        let c3 = Card64::from(c3);
114        let c2 = Card64::from(c2);
115
116        let r1 = Game::Holdem.eval_rating(c3, c2);
117        let r2 = Game::Holdem.eval_rating(c5, Card64::default());
118        let r3 = Game::Holdem.eval_rating(Card64::default(), c5);
119
120        assert_eq!(r1, r2);
121        assert_eq!(r1, r3);
122    }
123
124    #[test]
125    fn test_eval_rating() {
126        assert_eq!(
127            Game::Omaha
128                .eval_rating(c64!("Ks Qh 8s 9h"), c64!("7h 7c 7d As Ah")),
129            mk_rating(HandType::Trips, "7", "KQ")
130        );
131        assert_eq!(
132            Game::ShortDeck
133                .eval_rating(c64!("Kh As Ah Ac Ad 6d 6c"), Card64::default()),
134            mk_rating(HandType::Quads, "A", "K")
135        );
136    }
137
138    #[test]
139    fn test_eval_flop_cat() {
140        assert_eq!(
141            Game::Holdem.eval_flop_category(c64!("7c 8c"), board!("7s 8h Tc")),
142            FlopHandCategory::BottomTwo,
143        );
144
145        assert_eq!(
146            Game::Omaha
147                .eval_flop_category(c64!("7c 8c 2s 3s"), board!("7s 8h Tc")),
148            FlopHandCategory::BottomTwo,
149        );
150    }
151}