Untitled

 avatar
unknown
rust
12 days ago
2.4 kB
10
Indexable
fn from(mut cards: [crate::Card; 5]) -> Self {
    let mut suits = [false; 4];
    let mut ranks = [0; 15];

    let mut set4 = None;
    let mut set3 = None;
    let mut set2 = [0; 2];

    for card in cards {
        suits[card.suit as usize] = true;

        ranks[card.rank as usize] += 1;
        match ranks[card.rank as usize] {
            0 => unreachable!(),
            1 => {}
            2 => {
                if set2[0] > 0 {
                    debug_assert_eq!(set2[1], 0);
                    set2[1] = card.rank;
                } else {
                    set2[0] = card.rank;
                }
            }
            3 => {
                debug_assert_eq!(set3, None);
                set3 = Some(card.rank);
                if set2[0] == card.rank {
                    set2[0] = set2[1];
                    set2[1] = 0;
                } else {
                    debug_assert_eq!(set2[1], card.rank);
                    set2[1] = 0;
                }
            }
            4 => {
                debug_assert_eq!(set4, None);
                set4 = Some(card.rank);
            }
            5 => {
                eprintln!("5 of a kind?")
            }
            _ => unreachable!(),
        }
    }

    if let Some(rank) = set4 {
        PokerHand::FourOfAKind(rank)
    } else if let Some(rank) = set3 {
        if set2[0] > 0 {
            PokerHand::FullHouse(rank, set2[0])
        } else {
            PokerHand::ThreeOfAKind(rank)
        }
    } else if set2[1] > 0 {
        cards.sort_unstable_by_key(|c| std::cmp::Reverse(*c));
        PokerHand::TwoPair(set2)
    } else if set2[0] > 0 {
        PokerHand::Pair(set2[0])
    } else {
        cards.sort_unstable_by_key(|c| std::cmp::Reverse(*c));

        let is_flush = suits.into_iter().filter(|y| *y).count() == 1;
        let is_straight = cards.windows(2)
            .all(|p| 
                p[0].rank == p[1].rank + 1
                || p[0].rank == 14 && p[1].rank == 5);

        // Handle Ace being high or low.
        let straight_rank = if ranks[2] > 0 { 5 } else { cards[0].rank };

        match (is_flush, is_straight) {
            (true, true) => PokerHand::StraightFlush(straight_rank),
            (true, false) => PokerHand::Flush(cards.map(|c| c.rank)),
            (false, true) => PokerHand::Straight(straight_rank),
            (false, false) => PokerHand::High(cards.map(|c| c.rank)),
        }
    }
}
Editor is loading...
Leave a Comment