openpql_prelude/game/
game.rs1use 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}