85 lines
2.5 KiB
Rust
85 lines
2.5 KiB
Rust
pub struct HandEval;
|
|
|
|
impl HandEval {
|
|
pub fn encode(card: u8) -> u64 {
|
|
1 << (card / 4 * 13 + card % 4)
|
|
}
|
|
|
|
pub fn encode_hand(cards: &[u8]) -> u64 {
|
|
cards.iter().fold(0, |acc, &c| acc | Self::encode(c))
|
|
}
|
|
|
|
pub fn hand7_eval(hand: u64) -> u32 {
|
|
let c = (hand & 0x1FFF) as u32;
|
|
let d = ((hand >> 13) & 0x1FFF) as u32;
|
|
let h = ((hand >> 26) & 0x1FFF) as u32;
|
|
let s = ((hand >> 39) & 0x1FFF) as u32;
|
|
let ranks = c | d | h | s;
|
|
|
|
match ranks.count_ones() {
|
|
5 => Self::eval_5_card_hand(ranks, c, d, h, s),
|
|
6 => Self::eval_6_card_hand(ranks, c, d, h, s),
|
|
7 => Self::eval_7_card_hand(ranks, c, d, h, s),
|
|
_ => 0,
|
|
}
|
|
}
|
|
|
|
fn eval_5_card_hand(ranks: u32, c: u32, d: u32, h: u32, s: u32) -> u32 {
|
|
if Self::is_flush(c, d, h, s) {
|
|
return Self::flush_or_straight_flush(ranks);
|
|
}
|
|
Self::rank_hand_category(ranks)
|
|
}
|
|
|
|
fn eval_6_card_hand(ranks: u32, c: u32, d: u32, h: u32, s: u32) -> u32 {
|
|
let mut best_rank = u32::MAX;
|
|
for i in 0..6 {
|
|
let modified_ranks = ranks & !(1 << i);
|
|
best_rank = best_rank.min(Self::eval_5_card_hand(modified_ranks, c, d, h, s));
|
|
}
|
|
best_rank
|
|
}
|
|
|
|
fn eval_7_card_hand(ranks: u32, c: u32, d: u32, h: u32, s: u32) -> u32 {
|
|
let mut best_rank = u32::MAX;
|
|
for i in 0..7 {
|
|
for j in (i + 1)..7 {
|
|
let modified_ranks = ranks & !(1 << i) & !(1 << j);
|
|
best_rank = best_rank.min(Self::eval_5_card_hand(modified_ranks, c, d, h, s));
|
|
}
|
|
}
|
|
best_rank
|
|
}
|
|
|
|
fn is_flush(c: u32, d: u32, h: u32, s: u32) -> bool {
|
|
c.count_ones() >= 5 || d.count_ones() >= 5 || h.count_ones() >= 5 || s.count_ones() >= 5
|
|
}
|
|
|
|
fn flush_or_straight_flush(ranks: u32) -> u32 {
|
|
if Self::is_straight(ranks) {
|
|
return 9; // Straight flush category
|
|
}
|
|
6 // Flush category
|
|
}
|
|
|
|
fn is_straight(ranks: u32) -> bool {
|
|
let mut sequence = ranks;
|
|
while sequence > 0 {
|
|
if sequence & 0b11111 == 0b11111 {
|
|
return true;
|
|
}
|
|
sequence >>= 1;
|
|
}
|
|
false
|
|
}
|
|
|
|
fn rank_hand_category(ranks: u32) -> u32 {
|
|
match ranks.count_ones() {
|
|
5 => 1, // High card
|
|
4 => 2, // One pair
|
|
3 => 4, // Three of a kind
|
|
2 => 7, // Full house
|
|
_ => 0,
|
|
}
|
|
}
|
|
}
|