use super::hand::Hand;
pub struct HandIterator {
next: u64,
mask: u64,
}
impl HandIterator {
pub fn combinations(&self) -> usize {
let n = 52 - Hand::from(self.mask).size(); let k = Hand::from(self.next).size(); (0..k).fold(1, |x, i| x * (n - i) / (i + 1))
}
fn exhausted(&self) -> bool {
if self.next == 0 {
true
} else {
(64 - 52) > self.next.leading_zeros()
}
}
fn permute(&self) -> u64 {
let x = self.next;
let a = x | (x - 1);
let b = a + 1;
let c = ! a;
let d = c & b;
let e = d - 1;
let f = 1 + x.trailing_zeros();
let g = e >> f;
let h = b | g;
h
}
fn current(&self) -> Hand {
Hand::from(self.next)
}
fn advance(&mut self) {
loop {
self.next = self.permute();
if self.next & self.mask == 0 {
break;
}
}
}
}
impl Iterator for HandIterator {
type Item = Hand;
fn next(&mut self) -> Option<Self::Item> {
if self.exhausted() {
None
} else {
let hand = self.current();
self.advance();
Some(hand)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let combos = self.combinations();
(combos, Some(combos))
}
}
impl From<(usize, Hand)> for HandIterator {
fn from((n, mask): (usize, Hand)) -> Self {
let mut this = Self {
next: (1 << n) - 1,
mask: u64::from(mask),
};
while this.next & this.mask > 0 {
this.next = this.permute();
}
this
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn five_choose_three() {
let mut iter = HandIterator::from((3, Hand::from(0)));
assert!(iter.next() == Some(Hand::from(0b00111)));
assert!(iter.next() == Some(Hand::from(0b01011)));
assert!(iter.next() == Some(Hand::from(0b01101)));
assert!(iter.next() == Some(Hand::from(0b01110)));
assert!(iter.next() == Some(Hand::from(0b10011)));
assert!(iter.next() == Some(Hand::from(0b10101)));
assert!(iter.next() == Some(Hand::from(0b10110)));
assert!(iter.next() == Some(Hand::from(0b11001)));
assert!(iter.next() == Some(Hand::from(0b11010)));
assert!(iter.next() == Some(Hand::from(0b11100)));
}
#[test]
fn five_choose_three_with_mask() {
let mask = Hand::from(0b000000000000000000000110);
let mut iter = HandIterator::from((3, mask));
assert!(iter.next() == Some(Hand::from(0b0011001)));
assert!(iter.next() == Some(Hand::from(0b0101001)));
assert!(iter.next() == Some(Hand::from(0b0110001)));
assert!(iter.next() == Some(Hand::from(0b0111000)));
assert!(iter.next() == Some(Hand::from(0b1001001)));
assert!(iter.next() == Some(Hand::from(0b1010001)));
assert!(iter.next() == Some(Hand::from(0b1011000)));
assert!(iter.next() == Some(Hand::from(0b1100001)));
assert!(iter.next() == Some(Hand::from(0b1101000)));
assert!(iter.next() == Some(Hand::from(0b1110000)));
}
}