1use super::{
2 BitAnd, BitAndAssign, BitOr, BitOrAssign, Card, Card64, Hash, MASK16_RANKS,
3 N_RANKS, Not, PQLCardCount, RANK_NAMES, Rank, Suit, U16_LEADING_ONE, fmt,
4};
5
6#[cfg(any(test, feature = "benchmark"))]
7#[macro_export]
8macro_rules! r16 {
9 ($s:expr) => {
10 $crate::Rank16::from(
11 $s.chars()
12 .filter(|c| !c.is_whitespace())
13 .map(|c| $crate::Rank::try_from(c).unwrap())
14 .collect::<Vec<_>>()
15 .as_ref() as &[Rank],
16 )
17 };
18}
19
20#[derive(
44 Copy,
45 Clone,
46 PartialEq,
47 Eq,
48 BitAnd,
49 BitOr,
50 PartialOrd,
51 Ord,
52 Hash,
53 Default,
54 BitOrAssign,
55 BitAndAssign,
56)]
57pub struct Rank16(u16);
58
59impl Rank16 {
60 #[must_use]
73 #[inline]
74 pub const fn from_u16(v: u16) -> Self {
75 Self(v)
76 }
77
78 #[must_use]
91 #[inline]
92 pub const fn to_u16(self) -> u16 {
93 self.0
94 }
95
96 #[inline]
97 const fn from_rank(r: Rank) -> Self {
98 Self(1 << r as u8)
99 }
100
101 #[must_use]
113 #[inline]
114 pub const fn is_empty(self) -> bool {
115 self.0 == 0
116 }
117
118 #[inline]
131 pub const fn set(&mut self, r: Rank) {
132 self.0 |= 1 << r as i8;
133 }
134
135 #[inline]
148 pub const fn unset(&mut self, r: Rank) {
149 self.0 &= !(1 << r as i8);
150 }
151
152 #[must_use]
165 #[inline]
166 pub const fn contains_rank(self, r: Rank) -> bool {
167 let v = 1u16 << (r as usize);
168 v == v & self.0
169 }
170
171 #[must_use]
183 #[inline]
184 pub const fn count(self) -> PQLCardCount {
185 self.0.count_ones().to_le_bytes()[0]
186 }
187
188 #[must_use]
190 #[inline]
191 pub const fn min_rank(self) -> Option<Rank> {
192 match self.0.trailing_zeros() {
193 0 => Some(Rank::R2),
194 1 => Some(Rank::R3),
195 2 => Some(Rank::R4),
196 3 => Some(Rank::R5),
197 4 => Some(Rank::R6),
198 5 => Some(Rank::R7),
199 6 => Some(Rank::R8),
200 7 => Some(Rank::R9),
201 8 => Some(Rank::RT),
202 9 => Some(Rank::RJ),
203 10 => Some(Rank::RQ),
204 11 => Some(Rank::RK),
205 12 => Some(Rank::RA),
206 _ => None,
207 }
208 }
209
210 #[must_use]
212 #[inline]
213 pub const fn max_rank(self) -> Option<Rank> {
214 match (MASK16_RANKS & self.0).leading_zeros() {
215 15 => Some(Rank::R2),
216 14 => Some(Rank::R3),
217 13 => Some(Rank::R4),
218 12 => Some(Rank::R5),
219 11 => Some(Rank::R6),
220 10 => Some(Rank::R7),
221 9 => Some(Rank::R8),
222 8 => Some(Rank::R9),
223 7 => Some(Rank::RT),
224 6 => Some(Rank::RJ),
225 5 => Some(Rank::RQ),
226 4 => Some(Rank::RK),
227 3 => Some(Rank::RA),
228 _ => None,
229 }
230 }
231
232 #[must_use]
234 #[inline]
235 pub fn nth_rank(self, mut n: u8) -> Option<Rank> {
236 for rank in Rank::ARR_ALL.iter().rev() {
237 if self.contains_rank(*rank) {
238 if n == 1 {
239 return Some(*rank);
240 } else if n == 0 {
241 return None;
242 }
243
244 n -= 1;
245 }
246 }
247
248 None
249 }
250
251 #[must_use]
253 #[inline]
254 pub const fn higher_of(r: Self) -> Self {
255 if r.is_empty() {
256 Self(MASK16_RANKS)
257 } else {
258 let i = r.to_u16().leading_zeros();
259
260 Self(!((U16_LEADING_ONE >> i) * 2 - 1) & MASK16_RANKS)
261 }
262 }
263}
264
265impl Not for Rank16 {
266 type Output = Self;
267
268 fn not(self) -> Self::Output {
269 Self(!self.0 & MASK16_RANKS)
270 }
271}
272
273impl From<Rank> for Rank16 {
274 fn from(r: Rank) -> Self {
275 Self::from_rank(r)
276 }
277}
278
279impl From<&[Rank]> for Rank16 {
280 fn from(rs: &[Rank]) -> Self {
281 let mut res = Self::default();
282
283 for r in rs {
284 res.set(*r);
285 }
286
287 res
288 }
289}
290
291impl From<&[Card]> for Rank16 {
292 fn from(cs: &[Card]) -> Self {
293 let mut res = Self::default();
294
295 for c in cs {
296 res.set(c.rank);
297 }
298
299 res
300 }
301}
302
303impl From<Card64> for Rank16 {
304 fn from(c: Card64) -> Self {
305 c.ranks_by_suit(Suit::S)
306 | c.ranks_by_suit(Suit::H)
307 | c.ranks_by_suit(Suit::D)
308 | c.ranks_by_suit(Suit::C)
309 }
310}
311
312pub fn u16_to_rank_str(v: u16) -> String {
313 let to_c = |i: u8| {
314 if v & 1 << i == 0 {
315 '\0'
316 } else {
317 RANK_NAMES[i as usize]
318 }
319 };
320
321 (0..N_RANKS)
322 .map(to_c)
323 .filter(|c| c.is_alphanumeric())
324 .collect::<String>()
325}
326
327impl fmt::Debug for Rank16 {
328 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
329 f.write_str(&format!("Rank16<{}>", u16_to_rank_str(self.0)))
330 }
331}
332
333#[cfg(test)]
334mod tests {
335 use super::*;
336 use crate::*;
337
338 impl Arbitrary for Rank16 {
339 fn arbitrary(g: &mut quickcheck::Gen) -> Self {
340 let inner = u16::arbitrary(g);
341
342 Self(MASK16_RANKS & inner)
343 }
344 }
345
346 #[test]
347 fn test_empty() {
348 assert_eq!(Rank16::default(), Rank16(0));
349 assert!(Rank16::default().is_empty());
350 assert!(!Rank16(1).is_empty());
351 }
352
353 #[quickcheck]
354 fn test_set_and_contains(r: Rank) {
355 let mut ranks = Rank16::default();
356
357 ranks.set(r);
358
359 assert!(!ranks.is_empty());
360 assert!(ranks.contains_rank(r));
361
362 ranks.unset(r);
363
364 assert!(ranks.is_empty());
365 assert!(!ranks.contains_rank(r));
366 }
367
368 #[quickcheck]
369 fn test_u16(i: u16) -> TestResult {
370 if i > 0b1_1111_1111_1111 {
371 return TestResult::discard();
372 }
373
374 assert_eq!(Rank16(i), Rank16::from_u16(i));
375 assert_eq!(i, Rank16(i).to_u16());
376
377 TestResult::passed()
378 }
379
380 #[quickcheck]
381 fn test_from_rank(r1: Rank, r2: Rank) {
382 let ranks = Rank16::from(r1);
383
384 assert!(ranks.contains_rank(r1));
385
386 let ranks = Rank16::from([r1, r2].as_ref());
387
388 assert!(ranks.contains_rank(r1));
389 assert!(ranks.contains_rank(r2));
390 }
391
392 #[test]
393 fn test_bit_not() {
394 assert_eq!((!Rank16::default()).to_u16(), MASK16_RANKS);
395 }
396
397 #[quickcheck]
398 fn test_bit_and(r1: Rank, r2: Rank) {
399 let a = Rank16::from(r1);
400 let b = Rank16::from(r2);
401
402 assert_eq!((a & b).is_empty(), r1 != r2);
403 }
404
405 #[quickcheck]
406 fn test_bit_or(r1: Rank, r2: Rank) {
407 let a = Rank16::from(r1);
408 let b = Rank16::from(r2);
409
410 assert!((a | b).contains_rank(r1));
411 assert!((a | b).contains_rank(r2));
412 }
413
414 #[quickcheck]
415 fn test_count(r1: Rank, r2: Rank) {
416 let ranks = Rank16::from([r1, r2].as_ref());
417
418 let count = if r1 == r2 { 1 } else { 2 };
419
420 assert_eq!(count, ranks.count());
421 }
422
423 #[quickcheck]
424 fn test_min_max_rank(cards: CardN<3>) {
425 let ranks = Rank16::from(cards.as_ref());
426
427 let min_r = ranks.min_rank().unwrap();
428 let max_r = ranks.max_rank().unwrap();
429
430 let min_i = cards
431 .as_ref()
432 .iter()
433 .map(|c| c.rank as usize)
434 .min()
435 .unwrap();
436 let max_i = cards
437 .as_ref()
438 .iter()
439 .map(|c| c.rank as usize)
440 .max()
441 .unwrap();
442
443 for c in cards {
444 let r = Rank16::from(&[c] as &[Card]);
445 assert_eq!(c.rank, r.min_rank().unwrap());
446 assert_eq!(c.rank, r.max_rank().unwrap());
447 }
448
449 assert_eq!(min_i, min_r as usize);
450 assert_eq!(max_i, max_r as usize);
451 assert_eq!(None, Rank16::default().min_rank());
452 assert_eq!(None, Rank16::default().max_rank());
453 }
454
455 #[test]
456 fn test_nth_rank() {
457 let ranks = r16!("256KA");
458
459 assert_eq!(ranks.nth_rank(0), None);
460 assert_eq!(ranks.nth_rank(1), Some(Rank::RA));
461 assert_eq!(ranks.nth_rank(2), Some(Rank::RK));
462 assert_eq!(ranks.nth_rank(3), Some(Rank::R6));
463 assert_eq!(ranks.nth_rank(4), Some(Rank::R5));
464 assert_eq!(ranks.nth_rank(5), Some(Rank::R2));
465 assert_eq!(ranks.nth_rank(6), None);
466 }
467
468 #[test]
469 fn test_higher_of() {
470 assert_eq!(r16!("KA"), Rank16::higher_of(r16!("2Q")));
471 assert_eq!(!Rank16::default(), Rank16::higher_of(r16!("")));
472 assert_eq!(Rank16::default(), Rank16::higher_of(r16!("A")));
473 }
474
475 #[quickcheck]
476 fn test_from_card64(cards: Vec<Card>) -> TestResult {
477 let mut ranks = Rank16::default();
478
479 for i in 0..cards.len() {
480 ranks.set(cards[i].rank);
481
482 let c64: Card64 = cards[0..=i].into();
483
484 assert_eq!(Rank16::from(c64), ranks);
485 }
486
487 TestResult::passed()
488 }
489
490 #[test]
491 fn test_u16_to_rank_str() {
492 assert_eq!(u16_to_rank_str(0), "");
493 assert_eq!(u16_to_rank_str(1), "2");
494 assert_eq!(u16_to_rank_str(0b1), "2");
495 assert_eq!(u16_to_rank_str(0b10), "3");
496 assert_eq!(u16_to_rank_str(0b11), "23");
497 assert_eq!(u16_to_rank_str(0b1_0000_0000_0000), "A");
498 assert_eq!(u16_to_rank_str(0b1_0000_0000_0001), "2A");
499 assert_eq!(u16_to_rank_str(0b1_1111_1111_1111), "23456789TJQKA");
500 }
501
502 #[test]
503 fn test_debug() {
504 let s = format!("{:?}", r16!("J") | r16!("9"));
505 assert_eq!(s, "Rank16<9J>");
506 }
507}