use core::hand::Hand;
use core::card::Value;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Rank {
HighCard(u32),
OnePair(u32),
TwoPair(u32),
ThreeOfAKind(u32),
Straight(u32),
Flush(u32),
FullHouse(u32),
FourOfAKind(u32),
StraightFlush(u32),
}
const STRAIGHT0: u32 = 1 << (Value::Ace as u32) | 1 << (Value::Two as u32) |
1 << (Value::Three as u32) |
1 << (Value::Four as u32) | 1 << (Value::Five as u32);
const STRAIGHT1: u32 = 1 << (Value::Two as u32) | 1 << (Value::Three as u32) |
1 << (Value::Four as u32) |
1 << (Value::Five as u32) | 1 << (Value::Six as u32);
const STRAIGHT2: u32 = 1 << (Value::Three as u32) | 1 << (Value::Four as u32) |
1 << (Value::Five as u32) |
1 << (Value::Six as u32) | 1 << (Value::Seven as u32);
const STRAIGHT3: u32 =
1 << (Value::Four as u32) | 1 << (Value::Five as u32) | 1 << (Value::Six as u32) |
1 << (Value::Seven as u32) | 1 << (Value::Eight as u32);
const STRAIGHT4: u32 =
1 << (Value::Five as u32) | 1 << (Value::Six as u32) | 1 << (Value::Seven as u32) |
1 << (Value::Eight as u32) | 1 << (Value::Nine as u32);
const STRAIGHT5: u32 = 1 << (Value::Six as u32) | 1 << (Value::Seven as u32) |
1 << (Value::Eight as u32) |
1 << (Value::Nine as u32) | 1 << (Value::Ten as u32);
const STRAIGHT6: u32 = 1 << (Value::Seven as u32) | 1 << (Value::Eight as u32) |
1 << (Value::Nine as u32) |
1 << (Value::Ten as u32) | 1 << (Value::Jack as u32);
const STRAIGHT7: u32 = 1 << (Value::Eight as u32) | 1 << (Value::Nine as u32) |
1 << (Value::Ten as u32) | 1 << (Value::Jack as u32) |
1 << (Value::Queen as u32);
const STRAIGHT8: u32 =
1 << (Value::Nine as u32) | 1 << (Value::Ten as u32) | 1 << (Value::Jack as u32) |
1 << (Value::Queen as u32) | 1 << (Value::King as u32);
const STRAIGHT9: u32 = 1 << (Value::Ten as u32) | 1 << (Value::Jack as u32) |
1 << (Value::Queen as u32) |
1 << (Value::King as u32) | 1 << (Value::Ace as u32);
pub trait Rankable {
fn rank(&self) -> Rank;
#[inline]
fn rank_straight(&self, hand_rank: &u32) -> Option<u32> {
match hand_rank {
&STRAIGHT0 => Some(0),
&STRAIGHT1 => Some(1),
&STRAIGHT2 => Some(2),
&STRAIGHT3 => Some(3),
&STRAIGHT4 => Some(4),
&STRAIGHT5 => Some(5),
&STRAIGHT6 => Some(6),
&STRAIGHT7 => Some(7),
&STRAIGHT8 => Some(8),
&STRAIGHT9 => Some(9),
_ => None,
}
}
}
impl Rankable for Hand {
fn rank(&self) -> Rank {
let mut suit_set: u32 = 0;
let mut value_set: u32 = 0;
let mut value_to_count: [u8; 13] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let mut count_to_value: [u32; 5] = [0, 0, 0, 0, 0];
for c in &self[..] {
let v = c.value as u8;
let s = c.suit as u8;
suit_set |= 1 << s;
value_set |= 1 << v;
value_to_count[v as usize] += 1;
}
for (value, &count) in value_to_count.iter().enumerate() {
count_to_value[count as usize] |= 1 << value;
}
let unique_card_count = value_set.count_ones();
match unique_card_count {
5 => {
let suit_count = suit_set.count_ones();
let is_flush = suit_count == 1;
match (self.rank_straight(&value_set), is_flush) {
(None, false) => Rank::HighCard(value_set),
(Some(rank), false) => Rank::Straight(rank),
(None, true) => Rank::Flush(value_set),
(Some(rank), true) => Rank::StraightFlush(rank),
}
}
4 => {
let major_rank = count_to_value[2];
let minor_rank = value_set ^ major_rank;
Rank::OnePair(major_rank << 13 | minor_rank)
}
3 => {
let three_value = count_to_value[3];
if three_value > 0 {
let major_rank = three_value;
let minor_rank = value_set ^ major_rank;
Rank::ThreeOfAKind(major_rank << 13 | minor_rank)
} else {
let major_rank = count_to_value[2];
let minor_rank = value_set ^ major_rank;
Rank::TwoPair(major_rank << 13 | minor_rank)
}
}
2 => {
let three_value = count_to_value[3];
if three_value > 0 {
let major_rank = three_value;
let minor_rank = value_set ^ major_rank;
Rank::FullHouse(major_rank << 13 | minor_rank)
} else {
let major_rank = count_to_value[4];
let minor_rank = value_set ^ major_rank;
Rank::FourOfAKind(major_rank << 13 | minor_rank)
}
}
_ => unreachable!(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::hand::*;
use core::card::*;
#[test]
fn test_cmp() {
assert!(Rank::HighCard(0) < Rank::StraightFlush(0));
assert!(Rank::HighCard(0) < Rank::FourOfAKind(0));
assert!(Rank::HighCard(0) < Rank::ThreeOfAKind(0));
}
#[test]
fn test_cmp_high() {
assert!(Rank::HighCard(0) < Rank::HighCard(100));
}
#[test]
fn test_high_card_hand() {
let hand = Hand::new_with_cards(vec![Card {
value: Value::Ace,
suit: Suit::Diamond,
},
Card {
value: Value::Eight,
suit: Suit::Heart,
},
Card {
value: Value::Nine,
suit: Suit::Club,
},
Card {
value: Value::Ten,
suit: Suit::Club,
},
Card {
value: Value::Five,
suit: Suit::Club,
}]);
let rank = 1 << Value::Ace as u32 | 1 << Value::Eight as u32 | 1 << Value::Nine as u32 |
1 << Value::Ten as u32 |
1 << Value::Five as u32;
assert!(Rank::HighCard(rank) == hand.rank());
}
#[test]
fn test_flush() {
let hand = Hand::new_with_cards(vec![Card {
value: Value::Ace,
suit: Suit::Diamond,
},
Card {
value: Value::Eight,
suit: Suit::Diamond,
},
Card {
value: Value::Nine,
suit: Suit::Diamond,
},
Card {
value: Value::Ten,
suit: Suit::Diamond,
},
Card {
value: Value::Five,
suit: Suit::Diamond,
}]);
let rank = 1 << Value::Ace as u32 | 1 << Value::Eight as u32 | 1 << Value::Nine as u32 |
1 << Value::Ten as u32 |
1 << Value::Five as u32;
assert!(Rank::Flush(rank) == hand.rank());
}
#[test]
fn test_full_house() {
let hand = Hand::new_with_cards(vec![Card {
value: Value::Ace,
suit: Suit::Diamond,
},
Card {
value: Value::Ace,
suit: Suit::Club,
},
Card {
value: Value::Nine,
suit: Suit::Diamond,
},
Card {
value: Value::Nine,
suit: Suit::Club,
},
Card {
value: Value::Nine,
suit: Suit::Spade,
}]);
let rank = (1 << (Value::Nine as u32)) << 13 | 1 << (Value::Ace as u32);
assert!(Rank::FullHouse(rank) == hand.rank());
}
#[test]
fn test_two_pair() {
let hand = Hand::new_with_cards(vec![Card {
value: Value::Ace,
suit: Suit::Diamond,
},
Card {
value: Value::Ace,
suit: Suit::Club,
},
Card {
value: Value::Nine,
suit: Suit::Diamond,
},
Card {
value: Value::Nine,
suit: Suit::Club,
},
Card {
value: Value::Ten,
suit: Suit::Spade,
}]);
let rank = (1 << Value::Ace as u32 | 1 << Value::Nine as u32) << 13 |
1 << Value::Ten as u32;
assert!(Rank::TwoPair(rank) == hand.rank());
}
#[test]
fn test_one_pair() {
let hand = Hand::new_with_cards(vec![Card {
value: Value::Ace,
suit: Suit::Diamond,
},
Card {
value: Value::Ace,
suit: Suit::Club,
},
Card {
value: Value::Nine,
suit: Suit::Diamond,
},
Card {
value: Value::Eight,
suit: Suit::Club,
},
Card {
value: Value::Ten,
suit: Suit::Spade,
}]);
let rank = (1 << Value::Ace as u32) << 13 | 1 << Value::Nine as u32 |
1 << Value::Eight as u32 | 1 << Value::Ten as u32;
assert!(Rank::OnePair(rank) == hand.rank());
}
#[test]
fn test_four_of_a_kind() {
let hand = Hand::new_with_cards(vec![Card {
value: Value::Ace,
suit: Suit::Diamond,
},
Card {
value: Value::Ace,
suit: Suit::Club,
},
Card {
value: Value::Ace,
suit: Suit::Spade,
},
Card {
value: Value::Ace,
suit: Suit::Heart,
},
Card {
value: Value::Ten,
suit: Suit::Spade,
}]);
assert!(Rank::FourOfAKind((1 << (Value::Ace as u32) << 13) | 1 << (Value::Ten as u32)) ==
hand.rank());
}
#[test]
fn test_wheel() {
let hand = Hand::new_with_cards(vec![Card {
value: Value::Ace,
suit: Suit::Diamond,
},
Card {
value: Value::Two,
suit: Suit::Club,
},
Card {
value: Value::Three,
suit: Suit::Spade,
},
Card {
value: Value::Four,
suit: Suit::Heart,
},
Card {
value: Value::Five,
suit: Suit::Spade,
}]);
assert!(Rank::Straight(0) == hand.rank());
}
#[test]
fn test_straight() {
let hand = Hand::new_with_cards(vec![Card {
value: Value::Two,
suit: Suit::Club,
},
Card {
value: Value::Three,
suit: Suit::Spade,
},
Card {
value: Value::Four,
suit: Suit::Heart,
},
Card {
value: Value::Five,
suit: Suit::Spade,
},
Card {
value: Value::Six,
suit: Suit::Diamond,
}]);
assert!(Rank::Straight(1) == hand.rank());
}
#[test]
fn test_three_of_a_kind() {
let hand = Hand::new_with_cards(vec![Card {
value: Value::Two,
suit: Suit::Club,
},
Card {
value: Value::Two,
suit: Suit::Spade,
},
Card {
value: Value::Two,
suit: Suit::Heart,
},
Card {
value: Value::Five,
suit: Suit::Spade,
},
Card {
value: Value::Six,
suit: Suit::Diamond,
}]);
let rank = (1 << (Value::Two as u32)) << 13 | 1 << (Value::Five as u32) |
1 << (Value::Six as u32);
assert!(Rank::ThreeOfAKind(rank) == hand.rank());
}
}