open_pql/base/
isomorphic.rs1use super::{
2 Board, Card, Flop, HandN, IDX_RIVER, IDX_TURN, N_FLOP, Suit, SuitMapping,
3 Vec,
4};
5
6impl<const N: usize> HandN<N> {
7 pub fn new_iso_with_mapping(
8 cards: &[Card],
9 mapping: &mut SuitMapping,
10 ) -> Self {
11 Self::new(create_iso_array(cards, mapping))
12 }
13
14 pub fn new_iso(cards: &[Card]) -> (Self, SuitMapping) {
15 let mut mapping = SuitMapping::default();
16 let iso = Self::new_iso_with_mapping(cards, &mut mapping);
17 (iso, mapping)
18 }
19}
20
21impl Board {
22 pub fn new_iso_with_mapping(
23 cards: &[Card],
24 mapping: &mut SuitMapping,
25 ) -> Self {
26 create_iso_board(cards, mapping)
27 }
28
29 pub fn new_iso(cards: &[Card]) -> (Self, SuitMapping) {
30 let mut mapping = SuitMapping::default();
31 let iso = Self::new_iso_with_mapping(cards, &mut mapping);
32 (iso, mapping)
33 }
34}
35
36fn create_iso_array<const N: usize>(
37 cards: &[Card],
38 mapping: &mut SuitMapping,
39) -> [Card; N] {
40 let mut sorted = cards[..N]
41 .iter()
42 .map(|c| {
43 (
44 cards[..N].iter().filter(|&el| el.suit == c.suit).count(),
45 c.rank,
46 c,
47 )
48 })
49 .collect::<Vec<_>>();
50
51 sorted.sort_unstable();
52
53 let mut res = [Card::default(); N];
54
55 for (i, (_, _, card)) in sorted.into_iter().enumerate() {
56 res[i] = Card::new(card.rank, mapping.map_suit(card.suit));
57 }
58
59 res.sort_unstable();
60
61 res
62}
63
64fn create_iso_board(board_cards: &[Card], mapping: &mut SuitMapping) -> Board {
65 let n = board_cards.len();
66 let mut board = Board::default();
67
68 if n >= N_FLOP {
69 board.flop =
70 Some(Flop::new(create_iso_array(&board_cards[..N_FLOP], mapping)));
71 }
72
73 if n > IDX_TURN {
74 let card = board_cards[IDX_TURN];
75 board.turn = Some(Card::new(card.rank, mapping.map_suit(card.suit)));
76 }
77
78 if n > IDX_RIVER {
79 let card = board_cards[IDX_RIVER];
80 board.river = Some(Card::new(card.rank, mapping.map_suit(card.suit)));
81 }
82
83 board
84}
85
86pub const fn to_suitvar_char(s: Suit) -> char {
88 match s {
89 Suit::S => 'w',
90 Suit::H => 'x',
91 Suit::D => 'y',
92 Suit::C => 'z',
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use std::collections::{HashMap, HashSet};
99
100 use super::*;
101 use crate::*;
102
103 #[test]
104 fn test_to_suitvar_char() {
105 assert_eq!(to_suitvar_char(Suit::S), 'w');
106 assert_eq!(to_suitvar_char(Suit::H), 'x');
107 assert_eq!(to_suitvar_char(Suit::D), 'y');
108 assert_eq!(to_suitvar_char(Suit::C), 'z');
109 }
110
111 #[test]
112 fn test_iso() {
113 assert_eq!(
114 HandN::<5>::new_iso(&cards!("6s8h9dQdQc")).0,
115 HandN::<5>::new_iso(&cards!("6s8h9dQcQd")).0
116 );
117 }
118
119 #[test]
120 fn test_iso_flop() {
121 let mut res: HashMap<HandN<3>, HandN<3>> = HashMap::new();
122 let mut iso_set: HashSet<HandN<3>> = HashSet::default();
123 for hand in HandN::<3>::iter_all_short() {
124 let (iso, _) = HandN::new_iso(&hand.0);
125 res.insert(hand, iso);
126 iso_set.insert(iso);
127 }
128
129 assert_eq!(res.len(), 7140);
130 assert_eq!(iso_set.len(), 573);
131 }
132
133 #[test]
134 fn test_iso_board() {
135 fn assert_iso_eq(lhs: &str, rhs: &str) {
136 assert_eq!(
137 Board::new_iso(&cards!(lhs)).0,
138 Board::new_iso(&cards!(rhs)).0
139 );
140 }
141
142 assert_iso_eq("", "");
143 assert_iso_eq("AsKhQd", "AhKsQc");
144 assert_iso_eq("AsKhQdJdTd", "AhKsQcJcTc"); }
146}