1#![allow(clippy::wildcard_imports)]
2
3use std::{
4 iter::Filter,
5 str::{Chars, FromStr},
6 sync::LazyLock,
7};
8
9use itertools::Itertools;
10use open_pql_macro::{pqlfn, pqlfn_fromstr};
11use rustc_hash::FxHashMap;
12use speedy::Readable;
13use vm::{VmBuffer, VmStack, VmStackValue, VmStore, VmStoreVarIdx, VmValue, *};
14
15use crate::{
16 Board, Card, Card64, DeadCards, Flop, Hand, HandType, PQLBoardRange,
17 PQLBoolean, PQLCard, PQLCardCount, PQLGame, PQLHiRating, PQLInteger,
18 PQLRange, PQLRank, PQLRankSet, PQLStreet, Rank, Rank16, RuntimeError, Suit,
19 Suit4, eval_holdem7, eval_omaha9, eval_shortdeck7,
20 prim::eval::{ARR_STRAIGHT, ARR_STRAIGHT_SHORT, get_card_count},
21 *,
22};
23
24mod outs_info;
25
26mod cast;
27pub use cast::*;
28
29mod best_hi_rating;
30mod board_in_range;
31mod board_ranks;
32mod board_suit_count;
33mod duplicated_board_ranks;
34mod duplicated_hand_ranks;
35mod equity;
36mod exact_flop_hand_category;
37mod exact_hand_type;
38mod five_card_hi_hand_number;
39mod flop_hand_category;
40mod flushing_board;
41mod four_flush;
42mod hand_board_intersections;
43mod hand_ranks;
44mod hand_type;
45mod has_second_board_rank;
46mod has_top_board_rank;
47mod hi_rating;
48mod in_range;
49mod intersecting_hand_ranks;
50mod max_rank;
51mod min_flop_hand_category;
52mod min_hand_type;
53mod min_hi_rating;
54mod min_outs_to_hand_type;
55mod min_rank;
56mod monotone_board;
57mod nonintersecting_hand_ranks;
58mod nth_rank;
59mod nut_hi;
60mod nut_hi_for_hand_type;
61mod nut_hi_outs;
62mod outs_to_hand_type;
63mod overpair;
64mod paired_board;
65mod pocket_pair;
66mod rainbow_board;
67mod rank_count;
68mod rate_hi_hand;
69mod river_card;
70mod scoops;
71mod straight_board;
72mod three_flush;
73mod ties_hi;
74mod turn_card;
75mod twotone_board;
76mod winning_hand_type;
77mod wins_hi;
78
79pub use best_hi_rating::best_hi_rating;
80pub use board_in_range::board_in_range;
81pub use board_ranks::board_ranks;
82pub use board_suit_count::board_suit_count;
83pub use duplicated_board_ranks::duplicated_board_ranks;
84pub use duplicated_hand_ranks::duplicated_hand_ranks;
85pub use equity::equity;
86pub use exact_flop_hand_category::exact_flop_hand_category;
87pub use exact_hand_type::exact_hand_type;
88pub use five_card_hi_hand_number::five_card_hi_hand_number;
89pub use flop_hand_category::flop_hand_category;
90pub use flushing_board::flushing_board;
91pub use four_flush::four_flush;
92pub use hand_board_intersections::hand_board_intersections;
93pub use hand_ranks::hand_ranks;
94pub use hand_type::hand_type;
95pub use has_second_board_rank::has_second_board_rank;
96pub use has_top_board_rank::has_top_board_rank;
97pub use hi_rating::hi_rating;
98pub use in_range::in_range;
99pub use intersecting_hand_ranks::intersecting_hand_ranks;
100pub use max_rank::max_rank;
101pub use min_flop_hand_category::min_flop_hand_category;
102pub use min_hand_type::min_hand_type;
103pub use min_hi_rating::min_hi_rating;
104pub use min_outs_to_hand_type::min_outs_to_hand_type;
105pub use min_rank::min_rank;
106pub use monotone_board::monotone_board;
107pub use nonintersecting_hand_ranks::nonintersecting_hand_ranks;
108pub use nth_rank::nth_rank;
109pub use nut_hi::nut_hi;
110pub use nut_hi_for_hand_type::nut_hi_for_hand_type;
111pub use nut_hi_outs::nut_hi_outs;
112pub use outs_to_hand_type::outs_to_hand_type;
113pub use overpair::overpair;
114pub use paired_board::paired_board;
115pub use pocket_pair::pocket_pair;
116pub use rainbow_board::rainbow_board;
117pub use rank_count::rank_count;
118pub use rate_hi_hand::rate_hi_hand;
119pub use river_card::river_card;
120pub use scoops::scoops;
121pub use straight_board::straight_board;
122pub use three_flush::three_flush;
123pub use ties_hi::ties_hi;
124pub use turn_card::turn_card;
125pub use twotone_board::twotone_board;
126pub use winning_hand_type::winning_hand_type;
127pub use wins_hi::wins_hi;
128
129#[inline]
132fn max_rank_of_board(street: PQLStreet, board: Board) -> PQLRank {
133 max_rank(board_ranks(street, board)).unwrap()
134}
135
136#[inline]
139fn fill_ratings(
140 street: PQLStreet,
141 (game, board, player_hands, ratings): (
142 PQLGame,
143 Board,
144 &PlayerHands,
145 &mut BufferRatings,
146 ),
147) {
148 for (hand, rating) in player_hands.iter().zip(ratings.iter_mut()) {
149 *rating = hi_rating(hand, street, (game, board));
150 }
151}
152
153pub trait PQLFn:
190 fmt::Debug + Send + Sync + PQLFnRtn + PQLFnArgs + PQLFnEval
191{
192}
193
194impl<T> PQLFn for T where
195 T: fmt::Debug + Send + Sync + PQLFnRtn + PQLFnArgs + PQLFnEval
196{
197}
198
199pub trait PQLFnArgs {
200 fn arg_types(&self) -> &[PQLType];
201}
202
203pub trait PQLFnRtn {
204 fn rtn_type(&self) -> PQLType;
205}
206
207pub trait PQLFnEval {
208 fn evaluate(
209 &self,
210 buffer: &mut VmBuffer,
211 store: &mut VmStore,
212 stack: &mut VmStack,
213 ) -> Result<VmStackValue, PQLError>;
214}
215
216impl FromStr for &dyn PQLFn {
217 type Err = ParseError;
218
219 pqlfn_fromstr!();
220}
221
222fn arg_player<'b>(
223 buffer: &'b VmBuffer,
224 _store: &mut VmStore,
225 stack: &mut VmStack,
226) -> &'b Hand {
227 let player: PQLPlayer = stack.downcast_pop().unwrap();
228
229 let hand: &Hand = buffer.player_hand(player);
230
231 hand
232}
233
234fn arg_str<'b>(
235 _buffer: &VmBuffer,
236 store: &'b VmStore,
237 stack: &mut VmStack,
238) -> &'b PQLString {
239 let idx: VmStoreVarIdx = stack.downcast_pop().unwrap();
240 let s: &PQLString = store.downcast_get(idx).unwrap();
241
242 s
243}
244
245fn arg_range<'b, R>(
246 _buffer: &VmBuffer,
247 store: &'b mut VmStore,
248 stack: &mut VmStack,
249) -> &'b mut R
250where
251 &'b mut R: TryFrom<&'b mut VmValue>,
252{
253 let range_idx: VmStoreVarIdx = stack.downcast_pop().unwrap();
254
255 store.downcast_get_mut(range_idx).unwrap()
256}
257
258const fn decompose_omaha(
259 cards: Card64,
260) -> (Card64, Card64, Card64, Card64, Card64, Card64) {
261 let (v0, v1, v2, v3, v4, v5) = eval::decompose_omaha(cards.to_u64());
262
263 (
264 Card64::from_u64(v0),
265 Card64::from_u64(v1),
266 Card64::from_u64(v2),
267 Card64::from_u64(v3),
268 Card64::from_u64(v4),
269 Card64::from_u64(v5),
270 )
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276 use crate::*;
277
278 #[quickcheck]
279 fn test_decompose_omaha(cards: CardN<4>) {
280 let vec: Vec<_> = cards.clone().into();
281 let hands: [_; 6] = decompose_omaha(cards.into()).into();
282
283 for cs in vec.into_iter().combinations(2) {
284 assert!(hands.contains(&Card64::from(cs.as_ref())));
285 }
286 }
287}