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