1#![cfg_attr(not(test), no_std)]
2#![warn(clippy::pedantic)]
3#![allow(clippy::unreadable_literal)]
4
5extern crate alloc;
6
7use crate::cards::binary_card::{BinaryCard, BC64};
8use crate::parse::get_rank_and_suit;
9use strum::EnumIter;
10
11pub mod cards;
12pub mod deck;
13pub mod hand_rank;
14mod lookups;
15pub mod parse;
16
17pub type CKCNumber = u32;
34
35pub struct CardNumber;
37
38#[rustfmt::skip]
39impl CardNumber {
40 pub const RANK_FLAG_FILTER: u32 = 0x1FFF0000; pub const RANK_FLAG_SHIFT: u32 = 16;
42 pub const RANK_PRIME_FILTER: u32 = 0b00111111;
43
44 pub const SUIT_FILTER: u32 = 0xF000; pub const SUIT_SHORT_MASK: u32 = 0b1111;
48 pub const SUIT_SHIFT: u32 = 12;
49
50 pub const PAIR: u32 = 536_870_912;
55 pub const TRIPS: u32 = 1_073_741_824;
56 pub const QUADS: u32 = 2_147_483_648;
57 pub const MULTIPLES_FILTER: u32 = 536_870_911;
58
59 pub const ACE_SPADES: CKCNumber = 0b010000000000001000110000101001;
63 pub const KING_SPADES: CKCNumber = 0b001000000000001000101100100101;
64 pub const QUEEN_SPADES: CKCNumber = 0b000100000000001000101000011111;
65 pub const JACK_SPADES: CKCNumber = 0b000010000000001000100100011101;
66 pub const TEN_SPADES: CKCNumber = 0b000001000000001000100000010111;
67 pub const NINE_SPADES: CKCNumber = 0b000000100000001000011100010011;
68 pub const EIGHT_SPADES: CKCNumber = 0b000000010000001000011000010001;
69 pub const SEVEN_SPADES: CKCNumber = 0b000000001000001000010100001101;
70 pub const SIX_SPADES: CKCNumber = 0b000000000100001000010000001011;
71 pub const FIVE_SPADES: CKCNumber = 0b000000000010001000001100000111;
72 pub const FOUR_SPADES: CKCNumber = 0b000000000001001000001000000101;
73 pub const TREY_SPADES: CKCNumber = 0b000000000000101000000100000011;
74 pub const DEUCE_SPADES: CKCNumber = 0b000000000000011000000000000010;
75 pub const ACE_HEARTS: CKCNumber = 0b010000000000000100110000101001;
76 pub const KING_HEARTS: CKCNumber = 0b001000000000000100101100100101;
77 pub const QUEEN_HEARTS: CKCNumber = 0b000100000000000100101000011111;
78 pub const JACK_HEARTS: CKCNumber = 0b000010000000000100100100011101;
79 pub const TEN_HEARTS: CKCNumber = 0b000001000000000100100000010111;
80 pub const NINE_HEARTS: CKCNumber = 0b000000100000000100011100010011;
81 pub const EIGHT_HEARTS: CKCNumber = 0b000000010000000100011000010001;
82 pub const SEVEN_HEARTS: CKCNumber = 0b000000001000000100010100001101;
83 pub const SIX_HEARTS: CKCNumber = 0b000000000100000100010000001011;
84 pub const FIVE_HEARTS: CKCNumber = 0b000000000010000100001100000111;
85 pub const FOUR_HEARTS: CKCNumber = 0b000000000001000100001000000101;
86 pub const TREY_HEARTS: CKCNumber = 0b000000000000100100000100000011;
87 pub const DEUCE_HEARTS: CKCNumber = 0b000000000000010100000000000010;
88 pub const ACE_DIAMONDS: CKCNumber = 0b010000000000000010110000101001;
89 pub const KING_DIAMONDS: CKCNumber = 0b001000000000000010101100100101;
90 pub const QUEEN_DIAMONDS: CKCNumber = 0b000100000000000010101000011111;
91 pub const JACK_DIAMONDS: CKCNumber = 0b000010000000000010100100011101;
92 pub const TEN_DIAMONDS: CKCNumber = 0b000001000000000010100000010111;
93 pub const NINE_DIAMONDS: CKCNumber = 0b000000100000000010011100010011;
94 pub const EIGHT_DIAMONDS: CKCNumber = 0b000000010000000010011000010001;
95 pub const SEVEN_DIAMONDS: CKCNumber = 0b000000001000000010010100001101;
96 pub const SIX_DIAMONDS: CKCNumber = 0b000000000100000010010000001011;
97 pub const FIVE_DIAMONDS: CKCNumber = 0b000000000010000010001100000111;
98 pub const FOUR_DIAMONDS: CKCNumber = 0b000000000001000010001000000101;
99 pub const TREY_DIAMONDS: CKCNumber = 0b000000000000100010000100000011;
100 pub const DEUCE_DIAMONDS: CKCNumber = 0b000000000000010010000000000010;
101 pub const ACE_CLUBS: CKCNumber = 0b010000000000000001110000101001;
102 pub const KING_CLUBS: CKCNumber = 0b001000000000000001101100100101;
103 pub const QUEEN_CLUBS: CKCNumber = 0b000100000000000001101000011111;
104 pub const JACK_CLUBS: CKCNumber = 0b000010000000000001100100011101;
105 pub const TEN_CLUBS: CKCNumber = 0b000001000000000001100000010111;
106 pub const NINE_CLUBS: CKCNumber = 0b000000100000000001011100010011;
107 pub const EIGHT_CLUBS: CKCNumber = 0b000000010000000001011000010001;
108 pub const SEVEN_CLUBS: CKCNumber = 0b000000001000000001010100001101;
109 pub const SIX_CLUBS: CKCNumber = 0b000000000100000001010000001011;
110 pub const FIVE_CLUBS: CKCNumber = 0b000000000010000001001100000111;
111 pub const FOUR_CLUBS: CKCNumber = 0b000000000001000001001000000101;
112 pub const TREY_CLUBS: CKCNumber = 0b000000000000100001000100000011;
113 pub const DEUCE_CLUBS: CKCNumber = 0b000000000000010001000000000010;
114 pub const BLANK: CKCNumber = 0;
115 #[must_use]
118 pub fn filter(number: CKCNumber) -> CKCNumber {
119 <CKCNumber as PokerCard>::filter(number)
120 }
121}
122
123#[cfg(test)]
124mod card_number_tests {
125 use super::*;
126
127 #[test]
128 fn filter() {
129 assert_eq!(CardNumber::filter(2), CardNumber::BLANK);
130 assert_eq!(CardNumber::filter(CardNumber::NINE_CLUBS), CardNumber::NINE_CLUBS);
131 }
132}
133
134#[derive(Clone, Copy, Debug, EnumIter, Eq, Hash, PartialEq)]
135pub enum CardRank {
136 ACE = 14,
137 KING = 13,
138 QUEEN = 12,
139 JACK = 11,
140 TEN = 10,
141 NINE = 9,
142 EIGHT = 8,
143 SEVEN = 7,
144 SIX = 6,
145 FIVE = 5,
146 FOUR = 4,
147 THREE = 3,
148 TWO = 2,
149 BLANK = 0,
150}
151
152impl CardRank {
153 #[must_use]
154 pub fn from_char(index: char) -> CardRank {
155 match index {
156 'A' | 'a' => CardRank::ACE,
157 'K' | 'k' => CardRank::KING,
158 'Q' | 'q' => CardRank::QUEEN,
159 'J' | 'j' => CardRank::JACK,
160 'T' | 't' | '0' => CardRank::TEN,
161 '9' => CardRank::NINE,
162 '8' => CardRank::EIGHT,
163 '7' => CardRank::SEVEN,
164 '6' => CardRank::SIX,
165 '5' => CardRank::FIVE,
166 '4' => CardRank::FOUR,
167 '3' => CardRank::THREE,
168 '2' => CardRank::TWO,
169 _ => CardRank::BLANK,
170 }
171 }
172
173 fn bits(self) -> u32 {
174 1 << (16 + self.number())
175 }
176
177 fn number(self) -> u32 {
178 match self {
179 CardRank::ACE => 12,
180 CardRank::KING => 11,
181 CardRank::QUEEN => 10,
182 CardRank::JACK => 9,
183 CardRank::TEN => 8,
184 CardRank::NINE => 7,
185 CardRank::EIGHT => 6,
186 CardRank::SEVEN => 5,
187 CardRank::SIX => 4,
188 CardRank::FIVE => 3,
189 CardRank::FOUR => 2,
190 CardRank::THREE => 1,
191 _ => 0,
192 }
193 }
194
195 fn prime(self) -> u32 {
196 match self {
197 CardRank::ACE => 41,
198 CardRank::KING => 37,
199 CardRank::QUEEN => 31,
200 CardRank::JACK => 29,
201 CardRank::TEN => 23,
202 CardRank::NINE => 19,
203 CardRank::EIGHT => 17,
204 CardRank::SEVEN => 13,
205 CardRank::SIX => 11,
206 CardRank::FIVE => 7,
207 CardRank::FOUR => 5,
208 CardRank::THREE => 3,
209 CardRank::TWO => 2,
210 CardRank::BLANK => 0,
211 }
212 }
213
214 fn shift8(self) -> u32 {
215 self.number() << 8
216 }
217}
218
219#[cfg(test)]
220mod card_rank_tests {
221 use super::*;
222 use rstest::rstest;
223
224 #[rstest]
225 #[case('A', CardRank::ACE)]
226 #[case('a', CardRank::ACE)]
227 #[case('K', CardRank::KING)]
228 #[case('k', CardRank::KING)]
229 #[case('Q', CardRank::QUEEN)]
230 #[case('q', CardRank::QUEEN)]
231 #[case('J', CardRank::JACK)]
232 #[case('j', CardRank::JACK)]
233 #[case('T', CardRank::TEN)]
234 #[case('t', CardRank::TEN)]
235 #[case('0', CardRank::TEN)]
236 #[case('9', CardRank::NINE)]
237 #[case('8', CardRank::EIGHT)]
238 #[case('7', CardRank::SEVEN)]
239 #[case('6', CardRank::SIX)]
240 #[case('5', CardRank::FIVE)]
241 #[case('4', CardRank::FOUR)]
242 #[case('3', CardRank::THREE)]
243 #[case('2', CardRank::TWO)]
244 #[case('_', CardRank::BLANK)]
245 #[case(' ', CardRank::BLANK)]
246 fn from_char(#[case] input: char, #[case] expected: CardRank) {
247 assert_eq!(expected, CardRank::from_char(input));
248 }
249}
250
251#[derive(Clone, Copy, Debug, EnumIter, Eq, Hash, PartialEq)]
252pub enum CardSuit {
253 SPADES = 4,
254 HEARTS = 3,
255 DIAMONDS = 2,
256 CLUBS = 1,
257 BLANK = 0,
258}
259
260impl CardSuit {
261 #[must_use]
262 pub fn binary_signature(&self) -> u32 {
263 match self {
264 CardSuit::SPADES => 0x8000,
265 CardSuit::HEARTS => 0x4000,
266 CardSuit::DIAMONDS => 0x2000,
267 CardSuit::CLUBS => 0x1000,
268 CardSuit::BLANK => 0,
269 }
270 }
271
272 #[must_use]
273 pub fn from_char(symbol: char) -> CardSuit {
274 match symbol {
275 '♤' | '♠' | 'S' | 's' => CardSuit::SPADES,
276 '♡' | '♥' | 'H' | 'h' => CardSuit::HEARTS,
277 '♢' | '♦' | 'D' | 'd' => CardSuit::DIAMONDS,
278 '♧' | '♣' | 'C' | 'c' => CardSuit::CLUBS,
279 _ => CardSuit::BLANK,
280 }
281 }
282}
283
284#[cfg(test)]
285mod card_suit_tests {
286 use super::*;
287 use rstest::rstest;
288
289 #[test]
290 fn binary_signature() {
291 assert_eq!(32768, CardSuit::SPADES.binary_signature());
292 assert_eq!(16384, CardSuit::HEARTS.binary_signature());
293 assert_eq!(8192, CardSuit::DIAMONDS.binary_signature());
294 assert_eq!(4096, CardSuit::CLUBS.binary_signature());
295 assert_eq!(0, CardSuit::BLANK.binary_signature());
296 }
297
298 #[rstest]
299 #[case('♠', CardSuit::SPADES)]
300 #[case('♤', CardSuit::SPADES)]
301 #[case('S', CardSuit::SPADES)]
302 #[case('s', CardSuit::SPADES)]
303 #[case('♥', CardSuit::HEARTS)]
304 #[case('♡', CardSuit::HEARTS)]
305 #[case('H', CardSuit::HEARTS)]
306 #[case('h', CardSuit::HEARTS)]
307 #[case('♦', CardSuit::DIAMONDS)]
308 #[case('♢', CardSuit::DIAMONDS)]
309 #[case('D', CardSuit::DIAMONDS)]
310 #[case('d', CardSuit::DIAMONDS)]
311 #[case('♣', CardSuit::CLUBS)]
312 #[case('♧', CardSuit::CLUBS)]
313 #[case('C', CardSuit::CLUBS)]
314 #[case('c', CardSuit::CLUBS)]
315 #[case(' ', CardSuit::BLANK)]
316 #[case('F', CardSuit::BLANK)]
317 fn from_char(#[case] input: char, #[case] expected: CardSuit) {
318 assert_eq!(expected, CardSuit::from_char(input));
319 }
320}
321
322pub mod evaluate {
323 use crate::cards::five::Five;
324 use crate::cards::HandRanker;
325 use crate::hand_rank::HandRankValue;
326 use crate::{CKCNumber, CardNumber};
327
328 pub const POSSIBLE_COMBINATIONS: usize = 7937;
329
330 #[must_use]
331 #[allow(clippy::cast_possible_truncation)]
332 pub fn five_cards(five_cards: [CKCNumber; 5]) -> HandRankValue {
333 Five::from(five_cards).hand_rank_value_validated()
334 }
335
336 #[must_use]
337 #[deprecated(since = "0.1.9", note = "use Five.is_flush()")]
338 pub fn is_flush(five_cards: [CKCNumber; 5]) -> bool {
339 (five_cards[0] & five_cards[1] & five_cards[2] & five_cards[3] & five_cards[4] & CardNumber::SUIT_FILTER) != 0
340 }
341
342 #[must_use]
345 #[deprecated(since = "0.1.9", note = "use Five.or_rank_bits()")]
346 pub fn or_rank_bits(five_cards: [CKCNumber; 5]) -> usize {
347 Five::from(five_cards).or_rank_bits() as usize
348 }
349}
350
351#[cfg(test)]
352mod evaluate_tests {
353 use super::*;
354
355 #[test]
356 fn five_cards_royal_flush() {
357 let cards = [
358 CardNumber::ACE_SPADES,
359 CardNumber::KING_SPADES,
360 CardNumber::QUEEN_SPADES,
361 CardNumber::JACK_SPADES,
362 CardNumber::TEN_SPADES,
363 ];
364 assert_eq!(evaluate::five_cards(cards), 1);
365 }
366
367 #[test]
368 fn five_cards_straight() {
369 let first = [
370 CardNumber::NINE_CLUBS,
371 CardNumber::KING_SPADES,
372 CardNumber::QUEEN_SPADES,
373 CardNumber::JACK_SPADES,
374 CardNumber::TEN_SPADES,
375 ];
376 let second = [
377 CardNumber::NINE_CLUBS,
378 CardNumber::QUEEN_SPADES,
379 CardNumber::JACK_SPADES,
380 CardNumber::TEN_SPADES,
381 CardNumber::EIGHT_CLUBS,
382 ];
383 assert_eq!(evaluate::five_cards(first), 1601);
384 assert_eq!(evaluate::five_cards(second), 1602);
385 }
386
387 #[test]
388 fn five_cards_two_pair() {
389 let cards = [
390 CardNumber::JACK_CLUBS,
391 CardNumber::DEUCE_CLUBS,
392 CardNumber::DEUCE_DIAMONDS,
393 CardNumber::JACK_SPADES,
394 CardNumber::TEN_SPADES,
395 ];
396 assert_eq!(evaluate::five_cards(cards), 2922);
397 }
398
399 #[test]
400 fn five_cards_king_high() {
401 let first = [
402 CardNumber::JACK_CLUBS,
403 CardNumber::DEUCE_CLUBS,
404 CardNumber::TREY_CLUBS,
405 CardNumber::KING_SPADES,
406 CardNumber::TEN_SPADES,
407 ];
408 let second = [
409 CardNumber::JACK_CLUBS,
410 CardNumber::QUEEN_DIAMONDS,
411 CardNumber::TREY_CLUBS,
412 CardNumber::KING_SPADES,
413 CardNumber::TEN_SPADES,
414 ];
415 assert_eq!(evaluate::five_cards(first), 6825);
416 assert_eq!(evaluate::five_cards(second), 6684);
417 }
418
419 #[test]
420 fn check_dupes() {
421 let hand = [
422 CardNumber::JACK_CLUBS,
423 CardNumber::DEUCE_CLUBS,
424 CardNumber::TREY_CLUBS,
425 CardNumber::KING_SPADES,
426 CardNumber::JACK_CLUBS,
427 ];
428 assert_eq!(evaluate::five_cards(hand), 0);
429 }
430
431 #[test]
432 fn check_corrupt() {
433 let first = [
434 CardNumber::JACK_CLUBS,
435 CardNumber::DEUCE_CLUBS,
436 23,
437 CardNumber::KING_SPADES,
438 CardNumber::TEN_SPADES,
439 ];
440 let second = [
441 CardNumber::JACK_CLUBS,
442 CardNumber::QUEEN_DIAMONDS,
443 CardNumber::TREY_CLUBS,
444 CardNumber::KING_SPADES,
445 CardNumber::BLANK,
446 ];
447 assert_eq!(evaluate::five_cards(first), 0);
448 assert_eq!(evaluate::five_cards(second), 0);
449 }
450}
451
452#[derive(Debug, PartialEq)]
453pub enum HandError {
454 BlankCard,
455 DuplicateCard,
456 Incomplete,
457 InvalidBinaryFormat,
458 InvalidCard,
459 InvalidCardCount,
460 InvalidIndex,
461 NotEnoughCards,
462 TooManyCards,
463}
464
465pub trait PokerCard {
466 #[must_use]
469 fn create(rank: CardRank, suit: CardSuit) -> CKCNumber {
470 CKCNumber::filter(rank.bits() | rank.prime() | rank.shift8() | suit.binary_signature())
471 }
472
473 #[must_use]
475 fn filter(number: CKCNumber) -> CKCNumber {
476 match number {
477 CardNumber::ACE_SPADES
478 | CardNumber::KING_SPADES
479 | CardNumber::QUEEN_SPADES
480 | CardNumber::JACK_SPADES
481 | CardNumber::TEN_SPADES
482 | CardNumber::NINE_SPADES
483 | CardNumber::EIGHT_SPADES
484 | CardNumber::SEVEN_SPADES
485 | CardNumber::SIX_SPADES
486 | CardNumber::FIVE_SPADES
487 | CardNumber::FOUR_SPADES
488 | CardNumber::TREY_SPADES
489 | CardNumber::DEUCE_SPADES
490 | CardNumber::ACE_HEARTS
491 | CardNumber::KING_HEARTS
492 | CardNumber::QUEEN_HEARTS
493 | CardNumber::JACK_HEARTS
494 | CardNumber::TEN_HEARTS
495 | CardNumber::NINE_HEARTS
496 | CardNumber::EIGHT_HEARTS
497 | CardNumber::SEVEN_HEARTS
498 | CardNumber::SIX_HEARTS
499 | CardNumber::FIVE_HEARTS
500 | CardNumber::FOUR_HEARTS
501 | CardNumber::TREY_HEARTS
502 | CardNumber::DEUCE_HEARTS
503 | CardNumber::ACE_DIAMONDS
504 | CardNumber::KING_DIAMONDS
505 | CardNumber::QUEEN_DIAMONDS
506 | CardNumber::JACK_DIAMONDS
507 | CardNumber::TEN_DIAMONDS
508 | CardNumber::NINE_DIAMONDS
509 | CardNumber::EIGHT_DIAMONDS
510 | CardNumber::SEVEN_DIAMONDS
511 | CardNumber::SIX_DIAMONDS
512 | CardNumber::FIVE_DIAMONDS
513 | CardNumber::FOUR_DIAMONDS
514 | CardNumber::TREY_DIAMONDS
515 | CardNumber::DEUCE_DIAMONDS
516 | CardNumber::ACE_CLUBS
517 | CardNumber::KING_CLUBS
518 | CardNumber::QUEEN_CLUBS
519 | CardNumber::JACK_CLUBS
520 | CardNumber::TEN_CLUBS
521 | CardNumber::NINE_CLUBS
522 | CardNumber::EIGHT_CLUBS
523 | CardNumber::SEVEN_CLUBS
524 | CardNumber::SIX_CLUBS
525 | CardNumber::FIVE_CLUBS
526 | CardNumber::FOUR_CLUBS
527 | CardNumber::TREY_CLUBS
528 | CardNumber::DEUCE_CLUBS => number,
529 _ => CardNumber::BLANK,
530 }
531 }
532
533 #[must_use]
534 fn from_binary_card(bc: BinaryCard) -> CKCNumber {
535 match bc {
536 BinaryCard::ACE_SPADES => CardNumber::ACE_SPADES,
537 BinaryCard::KING_SPADES => CardNumber::KING_SPADES,
538 BinaryCard::QUEEN_SPADES => CardNumber::QUEEN_SPADES,
539 BinaryCard::JACK_SPADES => CardNumber::JACK_SPADES,
540 BinaryCard::TEN_SPADES => CardNumber::TEN_SPADES,
541 BinaryCard::NINE_SPADES => CardNumber::NINE_SPADES,
542 BinaryCard::EIGHT_SPADES => CardNumber::EIGHT_SPADES,
543 BinaryCard::SEVEN_SPADES => CardNumber::SEVEN_SPADES,
544 BinaryCard::SIX_SPADES => CardNumber::SIX_SPADES,
545 BinaryCard::FIVE_SPADES => CardNumber::FIVE_SPADES,
546 BinaryCard::FOUR_SPADES => CardNumber::FOUR_SPADES,
547 BinaryCard::TREY_SPADES => CardNumber::TREY_SPADES,
548 BinaryCard::DEUCE_SPADES => CardNumber::DEUCE_SPADES,
549 BinaryCard::ACE_HEARTS => CardNumber::ACE_HEARTS,
550 BinaryCard::KING_HEARTS => CardNumber::KING_HEARTS,
551 BinaryCard::QUEEN_HEARTS => CardNumber::QUEEN_HEARTS,
552 BinaryCard::JACK_HEARTS => CardNumber::JACK_HEARTS,
553 BinaryCard::TEN_HEARTS => CardNumber::TEN_HEARTS,
554 BinaryCard::NINE_HEARTS => CardNumber::NINE_HEARTS,
555 BinaryCard::EIGHT_HEARTS => CardNumber::EIGHT_HEARTS,
556 BinaryCard::SEVEN_HEARTS => CardNumber::SEVEN_HEARTS,
557 BinaryCard::SIX_HEARTS => CardNumber::SIX_HEARTS,
558 BinaryCard::FIVE_HEARTS => CardNumber::FIVE_HEARTS,
559 BinaryCard::FOUR_HEARTS => CardNumber::FOUR_HEARTS,
560 BinaryCard::TREY_HEARTS => CardNumber::TREY_HEARTS,
561 BinaryCard::DEUCE_HEARTS => CardNumber::DEUCE_HEARTS,
562 BinaryCard::ACE_DIAMONDS => CardNumber::ACE_DIAMONDS,
563 BinaryCard::KING_DIAMONDS => CardNumber::KING_DIAMONDS,
564 BinaryCard::QUEEN_DIAMONDS => CardNumber::QUEEN_DIAMONDS,
565 BinaryCard::JACK_DIAMONDS => CardNumber::JACK_DIAMONDS,
566 BinaryCard::TEN_DIAMONDS => CardNumber::TEN_DIAMONDS,
567 BinaryCard::NINE_DIAMONDS => CardNumber::NINE_DIAMONDS,
568 BinaryCard::EIGHT_DIAMONDS => CardNumber::EIGHT_DIAMONDS,
569 BinaryCard::SEVEN_DIAMONDS => CardNumber::SEVEN_DIAMONDS,
570 BinaryCard::SIX_DIAMONDS => CardNumber::SIX_DIAMONDS,
571 BinaryCard::FIVE_DIAMONDS => CardNumber::FIVE_DIAMONDS,
572 BinaryCard::FOUR_DIAMONDS => CardNumber::FOUR_DIAMONDS,
573 BinaryCard::TREY_DIAMONDS => CardNumber::TREY_DIAMONDS,
574 BinaryCard::DEUCE_DIAMONDS => CardNumber::DEUCE_DIAMONDS,
575 BinaryCard::ACE_CLUBS => CardNumber::ACE_CLUBS,
576 BinaryCard::KING_CLUBS => CardNumber::KING_CLUBS,
577 BinaryCard::QUEEN_CLUBS => CardNumber::QUEEN_CLUBS,
578 BinaryCard::JACK_CLUBS => CardNumber::JACK_CLUBS,
579 BinaryCard::TEN_CLUBS => CardNumber::TEN_CLUBS,
580 BinaryCard::NINE_CLUBS => CardNumber::NINE_CLUBS,
581 BinaryCard::EIGHT_CLUBS => CardNumber::EIGHT_CLUBS,
582 BinaryCard::SEVEN_CLUBS => CardNumber::SEVEN_CLUBS,
583 BinaryCard::SIX_CLUBS => CardNumber::SIX_CLUBS,
584 BinaryCard::FIVE_CLUBS => CardNumber::FIVE_CLUBS,
585 BinaryCard::FOUR_CLUBS => CardNumber::FOUR_CLUBS,
586 BinaryCard::TREY_CLUBS => CardNumber::TREY_CLUBS,
587 BinaryCard::DEUCE_CLUBS => CardNumber::DEUCE_CLUBS,
588 _ => CardNumber::BLANK,
589 }
590 }
591
592 #[must_use]
593 fn from_index(index: &str) -> CKCNumber {
594 let (rank, suit) = get_rank_and_suit(index);
595 CKCNumber::create(rank, suit)
596 }
597
598 fn as_u32(&self) -> u32;
601
602 fn get_card_rank(&self) -> CardRank {
603 match self.get_rank_bit() {
604 4096 => CardRank::ACE,
605 2048 => CardRank::KING,
606 1024 => CardRank::QUEEN,
607 512 => CardRank::JACK,
608 256 => CardRank::TEN,
609 128 => CardRank::NINE,
610 64 => CardRank::EIGHT,
611 32 => CardRank::SEVEN,
612 16 => CardRank::SIX,
613 8 => CardRank::FIVE,
614 4 => CardRank::FOUR,
615 2 => CardRank::THREE,
616 1 => CardRank::TWO,
617 _ => CardRank::BLANK,
618 }
619 }
620
621 fn get_card_suit(&self) -> CardSuit {
622 match self.get_suit_bit() {
623 8 => CardSuit::SPADES,
624 4 => CardSuit::HEARTS,
625 2 => CardSuit::DIAMONDS,
626 1 => CardSuit::CLUBS,
627 _ => CardSuit::BLANK,
628 }
629 }
630
631 fn get_chen_points(&self) -> f32 {
632 match self.get_card_rank() {
633 CardRank::ACE => 10.0,
634 CardRank::KING => 8.0,
635 CardRank::QUEEN => 7.0,
636 CardRank::JACK => 6.0,
637 CardRank::BLANK => 0.0,
638 _ => f32::from(self.get_card_rank() as u8) / 2.0,
639 }
640 }
641
642 fn get_rank_bit(&self) -> u32 {
643 self.get_rank_flag() >> CardNumber::RANK_FLAG_SHIFT
644 }
645
646 fn get_rank_char(&self) -> char {
647 match self.get_rank_bit() {
648 4096 => 'A',
649 2048 => 'K',
650 1024 => 'Q',
651 512 => 'J',
652 256 => 'T',
653 128 => '9',
654 64 => '8',
655 32 => '7',
656 16 => '6',
657 8 => '5',
658 4 => '4',
659 2 => '3',
660 1 => '2',
661 _ => '_',
662 }
663 }
664
665 fn get_rank_flag(&self) -> u32 {
666 self.as_u32() & CardNumber::RANK_FLAG_FILTER
667 }
668
669 fn get_rank_prime(&self) -> u32 {
670 self.as_u32() & CardNumber::RANK_PRIME_FILTER
671 }
672
673 fn get_suit_bit(&self) -> u32 {
674 self.get_suit_flag() >> CardNumber::SUIT_SHIFT
675 }
676
677 fn get_suit_char(&self) -> char {
678 match self.get_suit_bit() {
679 8 => '♠',
680 4 => '♥',
681 2 => '♦',
682 1 => '♣',
683 _ => '_',
684 }
685 }
686
687 fn get_suit_letter(&self) -> char {
688 match self.get_suit_bit() {
689 8 => 'S',
690 4 => 'H',
691 2 => 'D',
692 1 => 'C',
693 _ => '_',
694 }
695 }
696
697 fn get_suit_flag(&self) -> u32 {
698 self.as_u32() & CardNumber::SUIT_FILTER
699 }
700
701 fn is_blank(&self) -> bool;
702
703 fn flag_as_pair(&self) -> CKCNumber {
706 self.as_u32() | CardNumber::PAIR
707 }
708
709 fn flag_as_trips(&self) -> CKCNumber {
710 self.as_u32() | CardNumber::TRIPS
711 }
712
713 fn flag_as_quads(&self) -> CKCNumber {
714 self.as_u32() | CardNumber::QUADS
715 }
716
717 fn next_suit(&self) -> CardSuit {
718 match self.get_card_suit() {
719 CardSuit::SPADES => CardSuit::HEARTS,
720 CardSuit::HEARTS => CardSuit::DIAMONDS,
721 CardSuit::DIAMONDS => CardSuit::CLUBS,
722 CardSuit::CLUBS => CardSuit::SPADES,
723 CardSuit::BLANK => CardSuit::BLANK,
724 }
725 }
726
727 fn strip_multiples_flags(&self) -> CKCNumber {
728 CardNumber::MULTIPLES_FILTER & self.as_u32()
729 }
730
731 }
733
734impl PokerCard for CKCNumber {
735 fn as_u32(&self) -> u32 {
736 *self
737 }
738
739 fn is_blank(&self) -> bool {
740 *self == CardNumber::BLANK
741 }
742}
743
744pub trait Shifty {
751 #[must_use]
752 fn shift_suit(&self) -> Self;
753}
754
755impl Shifty for CKCNumber {
756 fn shift_suit(&self) -> Self {
757 CKCNumber::create(self.get_card_rank(), self.next_suit())
758 }
759}
760
761#[cfg(test)]
762mod poker_card_tests {
763 use super::*;
764 use rstest::rstest;
765
766 #[test]
767 fn filter() {
768 assert_eq!(
769 <CKCNumber as PokerCard>::filter(CardNumber::ACE_SPADES),
770 CardNumber::ACE_SPADES
771 );
772 assert_eq!(
773 <CKCNumber as PokerCard>::filter(CardNumber::KING_CLUBS),
774 CardNumber::filter(CardNumber::KING_CLUBS)
775 );
776 assert_eq!(<CKCNumber as PokerCard>::filter(2), CardNumber::BLANK);
777 }
778
779 #[rstest]
780 #[case("A♠", CardNumber::ACE_SPADES)]
781 #[case("ks", CardNumber::KING_SPADES)]
782 #[case("QS", CardNumber::QUEEN_SPADES)]
783 #[case("J♠", CardNumber::JACK_SPADES)]
784 #[case("TS", CardNumber::TEN_SPADES)]
785 #[case("9s", CardNumber::NINE_SPADES)]
786 #[case("8♠", CardNumber::EIGHT_SPADES)]
787 #[case("7S", CardNumber::SEVEN_SPADES)]
788 #[case("6♠", CardNumber::SIX_SPADES)]
789 #[case("5S", CardNumber::FIVE_SPADES)]
790 #[case("4♠", CardNumber::FOUR_SPADES)]
791 #[case("3s", CardNumber::TREY_SPADES)]
792 #[case("2S", CardNumber::DEUCE_SPADES)]
793 #[case("A♥", CardNumber::ACE_HEARTS)]
794 #[case("k♥", CardNumber::KING_HEARTS)]
795 #[case("QH", CardNumber::QUEEN_HEARTS)]
796 #[case("jh", CardNumber::JACK_HEARTS)]
797 #[case("T♥", CardNumber::TEN_HEARTS)]
798 #[case("9♥", CardNumber::NINE_HEARTS)]
799 #[case("8h", CardNumber::EIGHT_HEARTS)]
800 #[case("7H", CardNumber::SEVEN_HEARTS)]
801 #[case("6h", CardNumber::SIX_HEARTS)]
802 #[case("5H", CardNumber::FIVE_HEARTS)]
803 #[case("4♥", CardNumber::FOUR_HEARTS)]
804 #[case("3♥", CardNumber::TREY_HEARTS)]
805 #[case("2h", CardNumber::DEUCE_HEARTS)]
806 #[case("A♦", CardNumber::ACE_DIAMONDS)]
807 #[case("k♦", CardNumber::KING_DIAMONDS)]
808 #[case("Q♦", CardNumber::QUEEN_DIAMONDS)]
809 #[case("Jd", CardNumber::JACK_DIAMONDS)]
810 #[case("tD", CardNumber::TEN_DIAMONDS)]
811 #[case("9♦", CardNumber::NINE_DIAMONDS)]
812 #[case("8D", CardNumber::EIGHT_DIAMONDS)]
813 #[case("7♦", CardNumber::SEVEN_DIAMONDS)]
814 #[case("6D", CardNumber::SIX_DIAMONDS)]
815 #[case("5D", CardNumber::FIVE_DIAMONDS)]
816 #[case("4♦", CardNumber::FOUR_DIAMONDS)]
817 #[case("3♦", CardNumber::TREY_DIAMONDS)]
818 #[case("2d", CardNumber::DEUCE_DIAMONDS)]
819 #[case("a♣", CardNumber::ACE_CLUBS)]
820 #[case("k♣", CardNumber::KING_CLUBS)]
821 #[case("QC", CardNumber::QUEEN_CLUBS)]
822 #[case("jc", CardNumber::JACK_CLUBS)]
823 #[case("tC", CardNumber::TEN_CLUBS)]
824 #[case("9♣", CardNumber::NINE_CLUBS)]
825 #[case("8♣", CardNumber::EIGHT_CLUBS)]
826 #[case("7c", CardNumber::SEVEN_CLUBS)]
827 #[case("6♣", CardNumber::SIX_CLUBS)]
828 #[case("5C", CardNumber::FIVE_CLUBS)]
829 #[case("4c", CardNumber::FOUR_CLUBS)]
830 #[case("3C", CardNumber::TREY_CLUBS)]
831 #[case("2C", CardNumber::DEUCE_CLUBS)]
832 fn from_index(#[case] index: &str, #[case] expected: CKCNumber) {
833 assert_eq!(CKCNumber::from_index(index), expected);
834 }
835
836 #[rstest]
837 #[case("A♠", 10.0)]
838 #[case("ks", 8.0)]
839 #[case("QS", 7.0)]
840 #[case("J♠", 6.0)]
841 #[case("TS", 5.0)]
842 #[case("9s", 4.5)]
843 #[case("8♠", 4.0)]
844 #[case("7S", 3.5)]
845 #[case("6♠", 3.0)]
846 #[case("5S", 2.5)]
847 #[case("4♠", 2.0)]
848 #[case("3s", 1.5)]
849 #[case("2S", 1.0)]
850 fn get_chen_points(#[case] index: &str, #[case] expected: f32) {
851 assert_eq!(CKCNumber::from_index(index).get_chen_points(), expected);
852 }
853
854 #[test]
855 fn get_rank() {
856 let card = CardNumber::ACE_CLUBS as CKCNumber;
857 assert_eq!(0b00010000_00000000, card.get_rank_bit());
858 assert_eq!(0b00101001, card.get_rank_prime());
859 assert_eq!(CardRank::ACE, card.get_card_rank());
860
861 let card = CardNumber::KING_DIAMONDS as CKCNumber;
862 assert_eq!(0b00001000_00000000, card.get_rank_bit());
863 assert_eq!(0b00100101, card.get_rank_prime());
864 assert_eq!(CardRank::KING, card.get_card_rank());
865
866 let card = CardNumber::QUEEN_SPADES as CKCNumber;
867 assert_eq!(0b00000100_00000000, card.get_rank_bit());
868 assert_eq!(0b00011111, card.get_rank_prime());
869 assert_eq!(CardRank::QUEEN, card.get_card_rank());
870
871 let card = CardNumber::JACK_HEARTS as CKCNumber;
872 assert_eq!(0b00000010_00000000, card.get_rank_bit());
873 assert_eq!(0b00011101, card.get_rank_prime());
874 assert_eq!(CardRank::JACK, card.get_card_rank());
875
876 let card = CardNumber::TEN_SPADES as CKCNumber;
877 assert_eq!(0b00000001_00000000, card.get_rank_bit());
878 assert_eq!(0b00010111, card.get_rank_prime());
879 assert_eq!(CardRank::TEN, card.get_card_rank());
880
881 let card = CardNumber::NINE_HEARTS as CKCNumber;
882 assert_eq!(0b00000000_10000000, card.get_rank_bit());
883 assert_eq!(0b00010011, card.get_rank_prime());
884 assert_eq!(CardRank::NINE, card.get_card_rank());
885
886 let card = CardNumber::EIGHT_DIAMONDS as CKCNumber;
887 assert_eq!(0b00000000_01000000, card.get_rank_bit());
888 assert_eq!(0b00010001, card.get_rank_prime());
889 assert_eq!(CardRank::EIGHT, card.get_card_rank());
890
891 let card = CardNumber::SEVEN_CLUBS as CKCNumber;
892 assert_eq!(0b00000000_00100000, card.get_rank_bit());
893 assert_eq!(0b00001101, card.get_rank_prime());
894 assert_eq!(CardRank::SEVEN, card.get_card_rank());
895
896 let card = CardNumber::SIX_SPADES as CKCNumber;
897 assert_eq!(0b00000000_00010000, card.get_rank_bit());
898 assert_eq!(0b00001011, card.get_rank_prime());
899 assert_eq!(CardRank::SIX, card.get_card_rank());
900
901 let card = CardNumber::FIVE_HEARTS as CKCNumber;
902 assert_eq!(0b00000000_00001000, card.get_rank_bit());
903 assert_eq!(0b00000111, card.get_rank_prime());
904 assert_eq!(CardRank::FIVE, card.get_card_rank());
905
906 let card = CardNumber::FOUR_DIAMONDS as CKCNumber;
907 assert_eq!(0b00000000_00000100, card.get_rank_bit());
908 assert_eq!(0b00000101, card.get_rank_prime());
909 assert_eq!(CardRank::FOUR, card.get_card_rank());
910
911 let card = CardNumber::TREY_CLUBS as CKCNumber;
912 assert_eq!(0b00000000_00000010, card.get_rank_bit());
913 assert_eq!(0b00000011, card.get_rank_prime());
914 assert_eq!(CardRank::THREE, card.get_card_rank());
915
916 let card = CardNumber::DEUCE_SPADES as CKCNumber;
917 assert_eq!(0b00000000_00000001, card.get_rank_bit());
918 assert_eq!(0b00000010, card.get_rank_prime());
919 assert_eq!(CardRank::TWO, card.get_card_rank());
920
921 let card = CardNumber::BLANK as CKCNumber;
922 assert_eq!(0b00000000_00000000, card.get_rank_bit());
923 assert_eq!(0b00000000, card.get_rank_prime());
924 assert_eq!(CardRank::BLANK, card.get_card_rank());
925 assert_eq!(CardSuit::BLANK, card.get_card_suit());
926 }
927
928 #[test]
929 fn get_rank_flag() {
930 let card = CardNumber::ACE_CLUBS as CKCNumber;
931 assert_eq!(0b00010000_00000000_00000000_00000000, card.get_rank_flag());
932 let card = CardNumber::KING_DIAMONDS as CKCNumber;
933 assert_eq!(0b00001000_00000000_00000000_00000000, card.get_rank_flag());
934 let card = CardNumber::QUEEN_SPADES as CKCNumber;
935 assert_eq!(0b00000100_00000000_00000000_00000000, card.get_rank_flag());
936 let card = CardNumber::JACK_HEARTS as CKCNumber;
937 assert_eq!(0b00000010_00000000_00000000_00000000, card.get_rank_flag());
938 let card = CardNumber::TEN_SPADES as CKCNumber;
939 assert_eq!(0b00000001_00000000_00000000_00000000, card.get_rank_flag());
940 let card = CardNumber::NINE_HEARTS as CKCNumber;
941 assert_eq!(0b00000000_10000000_00000000_00000000, card.get_rank_flag());
942 let card = CardNumber::EIGHT_DIAMONDS as CKCNumber;
943 assert_eq!(0b00000000_01000000_00000000_00000000, card.get_rank_flag());
944 let card = CardNumber::SEVEN_CLUBS as CKCNumber;
945 assert_eq!(0b00000000_00100000_00000000_00000000, card.get_rank_flag());
946 let card = CardNumber::SIX_SPADES as CKCNumber;
947 assert_eq!(0b00000000_00010000_00000000_00000000, card.get_rank_flag());
948 let card = CardNumber::FIVE_HEARTS as CKCNumber;
949 assert_eq!(0b00000000_00001000_00000000_00000000, card.get_rank_flag());
950 let card = CardNumber::FOUR_DIAMONDS as CKCNumber;
951 assert_eq!(0b00000000_00000100_00000000_00000000, card.get_rank_flag());
952 let card = CardNumber::TREY_CLUBS as CKCNumber;
953 assert_eq!(0b00000000_00000010_00000000_00000000, card.get_rank_flag());
954 let card = CardNumber::DEUCE_SPADES as CKCNumber;
955 assert_eq!(0b00000000_00000001_00000000_00000000, card.get_rank_flag());
956 }
957
958 #[test]
959 fn get_suit_bit() {
960 let card = CardNumber::SEVEN_SPADES as CKCNumber;
961 assert_eq!(0b1000, card.get_suit_bit());
962 assert_eq!(CardSuit::SPADES, card.get_card_suit());
963
964 let card = CardNumber::SEVEN_HEARTS as CKCNumber;
965 assert_eq!(0b0100, card.get_suit_bit());
966 assert_eq!(CardSuit::HEARTS, card.get_card_suit());
967
968 let card = CardNumber::SEVEN_DIAMONDS as CKCNumber;
969 assert_eq!(0b0010, card.get_suit_bit());
970 assert_eq!(CardSuit::DIAMONDS, card.get_card_suit());
971
972 let card = CardNumber::SEVEN_CLUBS as CKCNumber;
973 assert_eq!(0b0001, card.get_suit_bit());
974 assert_eq!(CardSuit::CLUBS, card.get_card_suit());
975 }
976
977 #[test]
978 fn get_suit_flag() {
979 let card = CardNumber::SEVEN_SPADES as CKCNumber;
980 assert_eq!(0b10000000_00000000, card.get_suit_flag());
981
982 let card = CardNumber::SEVEN_HEARTS as CKCNumber;
983 assert_eq!(0b01000000_00000000, card.get_suit_flag());
984
985 let card = CardNumber::SEVEN_DIAMONDS as CKCNumber;
986 assert_eq!(0b00100000_00000000, card.get_suit_flag());
987
988 let card = CardNumber::SEVEN_CLUBS as CKCNumber;
989 assert_eq!(0b00010000_00000000, card.get_suit_flag());
990 }
991
992 #[test]
993 fn is_blank() {
994 let card = CardNumber::BLANK;
995
996 assert!(card.is_blank());
997 assert!(0_u32.is_blank());
998 assert!(0.is_blank());
999 }
1000
1001 #[test]
1002 fn flag_as_pair() {
1003 assert_eq!(805_342_249, CardNumber::ACE_SPADES.flag_as_pair());
1004 }
1005
1006 #[test]
1007 fn flag_as_trips() {
1008 assert_eq!(1_342_213_161, CardNumber::ACE_SPADES.flag_as_trips());
1009 }
1010
1011 #[test]
1012 fn flag_as_quads() {
1013 assert_eq!(2_415_954_985, CardNumber::ACE_SPADES.flag_as_quads());
1014 }
1015
1016 #[test]
1017 fn next_suit() {
1018 assert_eq!(CardNumber::TEN_SPADES.next_suit(), CardSuit::HEARTS);
1019 assert_eq!(CardNumber::TEN_HEARTS.next_suit(), CardSuit::DIAMONDS);
1020 assert_eq!(CardNumber::TEN_DIAMONDS.next_suit(), CardSuit::CLUBS);
1021 assert_eq!(CardNumber::TEN_CLUBS.next_suit(), CardSuit::SPADES);
1022 assert_eq!(CardNumber::BLANK.next_suit(), CardSuit::BLANK);
1023 }
1024
1025 #[test]
1026 fn shift_suit() {
1027 assert_eq!(CardNumber::ACE_SPADES.shift_suit(), CardNumber::ACE_HEARTS);
1028 assert_eq!(CardNumber::ACE_HEARTS.shift_suit(), CardNumber::ACE_DIAMONDS);
1029 assert_eq!(CardNumber::ACE_DIAMONDS.shift_suit(), CardNumber::ACE_CLUBS);
1030 assert_eq!(CardNumber::ACE_CLUBS.shift_suit(), CardNumber::ACE_SPADES);
1031 assert_eq!(CardNumber::BLANK.shift_suit(), CardNumber::BLANK);
1032 }
1033
1034 #[test]
1035 fn strip_multiples_flags() {
1036 assert_eq!(
1037 CardNumber::ACE_SPADES,
1038 CardNumber::ACE_SPADES.flag_as_pair().strip_multiples_flags()
1039 );
1040 assert_eq!(
1041 CardNumber::ACE_SPADES,
1042 CardNumber::ACE_SPADES.flag_as_trips().strip_multiples_flags()
1043 );
1044 assert_eq!(
1045 CardNumber::ACE_SPADES,
1046 CardNumber::ACE_SPADES.flag_as_quads().strip_multiples_flags()
1047 );
1048 assert_eq!(
1049 CardNumber::ACE_SPADES,
1050 CardNumber::ACE_SPADES
1051 .flag_as_pair()
1052 .flag_as_trips()
1053 .flag_as_quads()
1054 .strip_multiples_flags()
1055 );
1056 }
1057
1058 #[test]
1059 fn scratch() {
1060 }
1062}