--- /dev/null
+use std::cmp::Ordering;
+use std::fmt::{self, Display, Formatter};
+
+use crate::card::*;
+use crate::card::Rank::*;
+use crate::card::Suit::*;
+
+use self::Hand::*;
+
+#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
+pub enum Hand {
+ HighCard{kickers: (Rank, Rank, Rank, Rank, Rank)},
+ Pair{pair: Rank, kickers: (Rank, Rank, Rank)},
+ TwoPair{pairs: (Rank, Rank), kicker: Rank},
+ ThreeOfAKind{trips: Rank, kickers: (Rank, Rank)},
+ Straight{high_card: Rank},
+ Flush{flush: (Rank, Rank, Rank, Rank, Rank)},
+ FullHouse{trips: Rank, pair: Rank},
+ FourOfAKind{quads: Rank, kicker: Rank},
+ StraightFlush{high_card: Rank},
+ RoyalFlush,
+}
+
+impl Display for Hand {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ match *self {
+ HighCard{kickers: (kicker1, kicker2, kicker3, kicker4, kicker5)} => write!(f, "High Card {}, {}{}{}{} Kickers", kicker1, kicker2, kicker3, kicker4, kicker5),
+ Pair{pair, kickers: (kicker1, kicker2, kicker3)} => write!(f, "Pair of {}s, {}{}{} Kickers", pair, kicker1, kicker2, kicker3),
+ TwoPair{pairs: (pair1, pair2), kicker} => write!(f, "Two Pair, {}s & {}s, {} Kicker", pair1, pair2, kicker),
+ ThreeOfAKind{trips, kickers: (kicker1, kicker2)} => write!(f, "Three of a Kind, {}s, {}{} Kickers", trips, kicker1, kicker2),
+ Straight{high_card} => write!(f, "Straight, {} High", high_card),
+ Flush{flush: (rank1, rank2, rank3, rank4, rank5)} => write!(f, "Flush, {}{}{}{}{}", rank1, rank2, rank3, rank4, rank5),
+ FullHouse{trips, pair} => write!(f, "Full House, {}s full of {}s", trips, pair),
+ FourOfAKind{quads, kicker} => write!(f, "Four of a Kind, {}s, {} Kicker", quads, kicker),
+ StraightFlush{high_card} => write!(f, "Straight Flush, {} High", high_card),
+ RoyalFlush => write!(f, "Royal Flush"),
+ }
+ }
+}
+
+pub fn rank_7_card_hand(mut cards: [Card; 7]) -> Hand {
+ cards.sort_by(|a, b| b.rank.cmp(&a.rank));
+ let ranks = [cards[0].rank, cards[1].rank, cards[2].rank, cards[3].rank, cards[4].rank, cards[5].rank, cards[6].rank];
+ cards.sort_by(|a, b| b.suit.cmp(&a.suit));
+ let suits = [cards[0].suit, cards[1].suit, cards[2].suit, cards[3].suit, cards[4].suit, cards[5].suit, cards[6].suit];
+
+ match suits {
+ [Spades, Spades, Spades, Spades, Spades, Spades, Spades] |
+ [Hearts, Hearts, Hearts, Hearts, Hearts, Hearts, Hearts] |
+ [Diamonds, Diamonds, Diamonds, Diamonds, Diamonds, Diamonds, Diamonds] |
+ [Clubs, Clubs, Clubs, Clubs, Clubs, Clubs, Clubs] =>
+ match ranks {
+ [Ace, King, Queen, Jack, Ten, _, _] => RoyalFlush,
+ [King, Queen, Jack, Ten, Nine, _, _] => StraightFlush{high_card: King},
+ [Queen, Jack, Ten, Nine, Eight, _, _] => StraightFlush{high_card: Queen},
+ [_, Queen, Jack, Ten, Nine, Eight, _] => StraightFlush{high_card: Queen},
+ [Jack, Ten, Nine, Eight, Seven, _, _] => StraightFlush{high_card: Jack},
+ [_, Jack, Ten, Nine, Eight, Seven, _] => StraightFlush{high_card: Jack},
+ [_, _, Jack, Ten, Nine, Eight, Seven] => StraightFlush{high_card: Jack},
+ [Ten, Nine, Eight, Seven, Six, _, _] => StraightFlush{high_card: Ten},
+ [_, Ten, Nine, Eight, Seven, Six, _] => StraightFlush{high_card: Ten},
+ [_, _, Ten, Nine, Eight, Seven, Six] => StraightFlush{high_card: Ten},
+ [Nine, Eight, Seven, Six, Five, _, _] => StraightFlush{high_card: Nine},
+ [_, Nine, Eight, Seven, Six, Five, _] => StraightFlush{high_card: Nine},
+ [_, _, Nine, Eight, Seven, Six, Five] => StraightFlush{high_card: Nine},
+ [Eight, Seven, Six, Five, Four, _, _] => StraightFlush{high_card: Eight},
+ [_, Eight, Seven, Six, Five, Four, _] => StraightFlush{high_card: Eight},
+ [_, _, Eight, Seven, Six, Five, Four] => StraightFlush{high_card: Eight},
+ [Seven, Six, Five, Four, Three, _, _] => StraightFlush{high_card: Seven},
+ [_, Seven, Six, Five, Four, Three, _] => StraightFlush{high_card: Seven},
+ [_, _, Seven, Six, Five, Four, Three] => StraightFlush{high_card: Seven},
+ [Six, Five, Four, Three, Two, _, _] => StraightFlush{high_card: Six},
+ [_, Six, Five, Four, Three, Two, _] => StraightFlush{high_card: Six},
+ [_, _, Six, Five, Four, Three, Two] => StraightFlush{high_card: Six},
+ [Ace, _, _, Five, Four, Three, Two] => StraightFlush{high_card: Five},
+ [rank1, rank2, rank3, rank4, rank5, _, _] => Flush{flush: (rank1, rank2, rank3, rank4, rank5)},
+ }
+ [Spades, Spades, Spades, Spades, Spades, Spades, _] |
+ [Hearts, Hearts, Hearts, Hearts, Hearts, Hearts, _] |
+ [Diamonds, Diamonds, Diamonds, Diamonds, Diamonds, Diamonds, _] =>
+ match [cards[0].rank, cards[1].rank, cards[2].rank, cards[3].rank, cards[4].rank, cards[5].rank] {
+ [Ace, King, Queen, Jack, Ten, _] => RoyalFlush,
+ [King, Queen, Jack, Ten, Nine, _] => StraightFlush{high_card: King},
+ [Queen, Jack, Ten, Nine, Eight, _] => StraightFlush{high_card: Queen},
+ [_, Queen, Jack, Ten, Nine, Eight] => StraightFlush{high_card: Queen},
+ [Jack, Ten, Nine, Eight, Seven, _] => StraightFlush{high_card: Jack},
+ [_, Jack, Ten, Nine, Eight, Seven] => StraightFlush{high_card: Jack},
+ [Ten, Nine, Eight, Seven, Six, _] => StraightFlush{high_card: Ten},
+ [_, Ten, Nine, Eight, Seven, Six] => StraightFlush{high_card: Ten},
+ [Nine, Eight, Seven, Six, Five, _] => StraightFlush{high_card: Nine},
+ [_, Nine, Eight, Seven, Six, Five] => StraightFlush{high_card: Nine},
+ [Eight, Seven, Six, Five, Four, _] => StraightFlush{high_card: Eight},
+ [_, Eight, Seven, Six, Five, Four] => StraightFlush{high_card: Eight},
+ [Seven, Six, Five, Four, Three, _] => StraightFlush{high_card: Seven},
+ [_, Seven, Six, Five, Four, Three] => StraightFlush{high_card: Seven},
+ [Six, Five, Four, Three, Two, _] => StraightFlush{high_card: Six},
+ [_, Six, Five, Four, Three, Two] => StraightFlush{high_card: Six},
+ [Ace, _, Five, Four, Three, Two] => StraightFlush{high_card: Five},
+ [rank1, rank2, rank3, rank4, rank5, _] => Flush{flush: (rank1, rank2, rank3, rank4, rank5)},
+ }
+ [_, Hearts, Hearts, Hearts, Hearts, Hearts, Hearts] |
+ [_, Diamonds, Diamonds, Diamonds, Diamonds, Diamonds, Diamonds] |
+ [_, Clubs, Clubs, Clubs, Clubs, Clubs, Clubs] =>
+ match [cards[1].rank, cards[2].rank, cards[3].rank, cards[4].rank, cards[5].rank, cards[6].rank] {
+ [Ace, King, Queen, Jack, Ten, _] => RoyalFlush,
+ [King, Queen, Jack, Ten, Nine, _] => StraightFlush{high_card: King},
+ [Queen, Jack, Ten, Nine, Eight, _] => StraightFlush{high_card: Queen},
+ [_, Queen, Jack, Ten, Nine, Eight] => StraightFlush{high_card: Queen},
+ [Jack, Ten, Nine, Eight, Seven, _] => StraightFlush{high_card: Jack},
+ [_, Jack, Ten, Nine, Eight, Seven] => StraightFlush{high_card: Jack},
+ [Ten, Nine, Eight, Seven, Six, _] => StraightFlush{high_card: Ten},
+ [_, Ten, Nine, Eight, Seven, Six] => StraightFlush{high_card: Ten},
+ [Nine, Eight, Seven, Six, Five, _] => StraightFlush{high_card: Nine},
+ [_, Nine, Eight, Seven, Six, Five] => StraightFlush{high_card: Nine},
+ [Eight, Seven, Six, Five, Four, _] => StraightFlush{high_card: Eight},
+ [_, Eight, Seven, Six, Five, Four] => StraightFlush{high_card: Eight},
+ [Seven, Six, Five, Four, Three, _] => StraightFlush{high_card: Seven},
+ [_, Seven, Six, Five, Four, Three] => StraightFlush{high_card: Seven},
+ [Six, Five, Four, Three, Two, _] => StraightFlush{high_card: Six},
+ [_, Six, Five, Four, Three, Two] => StraightFlush{high_card: Six},
+ [Ace, _, Five, Four, Three, Two] => StraightFlush{high_card: Five},
+ [rank1, rank2, rank3, rank4, rank5, _] => Flush{flush: (rank1, rank2, rank3, rank4, rank5)},
+ }
+ [Spades, Spades, Spades, Spades, Spades, _, _] |
+ [Hearts, Hearts, Hearts, Hearts, Hearts, _, _] |
+ [Diamonds, Diamonds, Diamonds, Diamonds, Diamonds, _, _] =>
+ match [cards[0].rank, cards[1].rank, cards[2].rank, cards[3].rank, cards[4].rank] {
+ [Ace, King, Queen, Jack, Ten] => RoyalFlush,
+ [King, Queen, Jack, Ten, Nine] => StraightFlush{high_card: King},
+ [Queen, Jack, Ten, Nine, Eight] => StraightFlush{high_card: Queen},
+ [Jack, Ten, Nine, Eight, Seven] => StraightFlush{high_card: Jack},
+ [Ten, Nine, Eight, Seven, Six] => StraightFlush{high_card: Ten},
+ [Nine, Eight, Seven, Six, Five] => StraightFlush{high_card: Nine},
+ [Eight, Seven, Six, Five, Four] => StraightFlush{high_card: Eight},
+ [Seven, Six, Five, Four, Three] => StraightFlush{high_card: Seven},
+ [Six, Five, Four, Three, Two] => StraightFlush{high_card: Six},
+ [Ace, Five, Four, Three, Two] => StraightFlush{high_card: Five},
+ [rank1, rank2, rank3, rank4, rank5] => Flush{flush: (rank1, rank2, rank3, rank4, rank5)},
+ }
+ [_, Hearts, Hearts, Hearts, Hearts, Hearts, _] |
+ [_, Diamonds, Diamonds, Diamonds, Diamonds, Diamonds, _] =>
+ match [cards[1].rank, cards[2].rank, cards[3].rank, cards[4].rank, cards[5].rank] {
+ [Ace, King, Queen, Jack, Ten] => RoyalFlush,
+ [King, Queen, Jack, Ten, Nine] => StraightFlush{high_card: King},
+ [Queen, Jack, Ten, Nine, Eight] => StraightFlush{high_card: Queen},
+ [Jack, Ten, Nine, Eight, Seven] => StraightFlush{high_card: Jack},
+ [Ten, Nine, Eight, Seven, Six] => StraightFlush{high_card: Ten},
+ [Nine, Eight, Seven, Six, Five] => StraightFlush{high_card: Nine},
+ [Eight, Seven, Six, Five, Four] => StraightFlush{high_card: Eight},
+ [Seven, Six, Five, Four, Three] => StraightFlush{high_card: Seven},
+ [Six, Five, Four, Three, Two] => StraightFlush{high_card: Six},
+ [Ace, Five, Four, Three, Two] => StraightFlush{high_card: Five},
+ [rank1, rank2, rank3, rank4, rank5] => Flush{flush: (rank1, rank2, rank3, rank4, rank5)},
+ }
+ [_, _, Hearts, Hearts, Hearts, Hearts, Hearts] |
+ [_, _, Diamonds, Diamonds, Diamonds, Diamonds, Diamonds] |
+ [_, _, Clubs, Clubs, Clubs, Clubs, Clubs] =>
+ match [cards[2].rank, cards[3].rank, cards[4].rank, cards[5].rank, cards[6].rank] {
+ [Ace, King, Queen, Jack, Ten] => RoyalFlush,
+ [King, Queen, Jack, Ten, Nine] => StraightFlush{high_card: King},
+ [Queen, Jack, Ten, Nine, Eight] => StraightFlush{high_card: Queen},
+ [Jack, Ten, Nine, Eight, Seven] => StraightFlush{high_card: Jack},
+ [Ten, Nine, Eight, Seven, Six] => StraightFlush{high_card: Ten},
+ [Nine, Eight, Seven, Six, Five] => StraightFlush{high_card: Nine},
+ [Eight, Seven, Six, Five, Four] => StraightFlush{high_card: Eight},
+ [Seven, Six, Five, Four, Three] => StraightFlush{high_card: Seven},
+ [Six, Five, Four, Three, Two] => StraightFlush{high_card: Six},
+ [Ace, Five, Four, Three, Two] => StraightFlush{high_card: Five},
+ [rank1, rank2, rank3, rank4, rank5] => Flush{flush: (rank1, rank2, rank3, rank4, rank5)},
+ }
+ [_, _, _, _, _, _, _] =>
+ match ranks {
+ [quad1, quad2, quad3, quad4, kicker, _, _] if quad1 == quad2 && quad2 == quad3 && quad3 == quad4 => FourOfAKind{quads: quad1, kicker: kicker},
+ [kicker, quad1, quad2, quad3, quad4, _, _] if quad1 == quad2 && quad2 == quad3 && quad3 == quad4 => FourOfAKind{quads: quad1, kicker: kicker},
+ [kicker, _, quad1, quad2, quad3, quad4, _] if quad1 == quad2 && quad2 == quad3 && quad3 == quad4 => FourOfAKind{quads: quad1, kicker: kicker},
+ [kicker, _, _, quad1, quad2, quad3, quad4] if quad1 == quad2 && quad2 == quad3 && quad3 == quad4 => FourOfAKind{quads: quad1, kicker: kicker},
+
+ [trip1, trip2, trip3, pair1, pair2, _, _] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [trip1, trip2, trip3, _, pair1, pair2, _] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [trip1, trip2, trip3, _, _, pair1, pair2] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [_, trip1, trip2, trip3, pair1, pair2, _] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [_, trip1, trip2, trip3, _, pair1, pair2] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [pair1, pair2, trip1, trip2, trip3, _, _] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [pair1, pair2, _, trip1, trip2, trip3, _] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [pair1, pair2, _, _, trip1, trip2, trip3] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [_, _, trip1, trip2, trip3, pair1, pair2] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [_, pair1, pair2, trip1, trip2, trip3, _] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [_, pair1, pair2, _, trip1, trip2, trip3] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [_, _, pair1, pair2, trip1, trip2, trip3] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+
+ [Ace, King, Queen, Jack, Ten, _, _] => Straight{high_card: Ace},
+ [Ace, King, Queen, Jack, _, Ten, _] => Straight{high_card: Ace},
+ [Ace, King, Queen, Jack, _, _, Ten] => Straight{high_card: Ace},
+ [Ace, King, Queen, _, Jack, Ten, _] => Straight{high_card: Ace},
+ [Ace, King, Queen, _, Jack, _, Ten] => Straight{high_card: Ace},
+ [Ace, King, Queen, _, _, Jack, Ten] => Straight{high_card: Ace},
+ [Ace, King, _, Queen, Jack, Ten, _] => Straight{high_card: Ace},
+ [Ace, King, _, Queen, Jack, _, Ten] => Straight{high_card: Ace},
+ [Ace, King, _, Queen, _, Jack, Ten] => Straight{high_card: Ace},
+ [Ace, King, _, _, Queen, Jack, Ten] => Straight{high_card: Ace},
+ [Ace, _, King, Queen, Jack, Ten, _] => Straight{high_card: Ace},
+ [Ace, _, King, Queen, Jack, _, Ten] => Straight{high_card: Ace},
+ [Ace, _, King, Queen, _, Jack, Ten] => Straight{high_card: Ace},
+ [Ace, _, King, _, Queen, Jack, Ten] => Straight{high_card: Ace},
+ [Ace, _, _, King, Queen, Jack, Ten] => Straight{high_card: Ace},
+ [_, Ace, King, Queen, Jack, Ten, _] => Straight{high_card: Ace},
+ [_, Ace, King, Queen, Jack, _, Ten] => Straight{high_card: Ace},
+ [_, Ace, King, Queen, _, Jack, Ten] => Straight{high_card: Ace},
+ [_, Ace, King, _, Queen, Jack, Ten] => Straight{high_card: Ace},
+ [_, Ace, _, King, Queen, Jack, Ten] => Straight{high_card: Ace},
+ [_, _, Ace, King, Queen, Jack, Ten] => Straight{high_card: Ace},
+
+ [King, Queen, Jack, Ten, Nine, _, _] => Straight{high_card: King},
+ [King, Queen, Jack, Ten, _, Nine, _] => Straight{high_card: King},
+ [King, Queen, Jack, Ten, _, _, Nine] => Straight{high_card: King},
+ [King, Queen, Jack, _, Ten, Nine, _] => Straight{high_card: King},
+ [King, Queen, Jack, _, Ten, _, Nine] => Straight{high_card: King},
+ [King, Queen, Jack, _, _, Ten, Nine] => Straight{high_card: King},
+ [King, Queen, _, Jack, Ten, Nine, _] => Straight{high_card: King},
+ [King, Queen, _, Jack, Ten, _, Nine] => Straight{high_card: King},
+ [King, Queen, _, Jack, _, Ten, Nine] => Straight{high_card: King},
+ [King, Queen, _, _, Jack, Ten, Nine] => Straight{high_card: King},
+ [King, _, Queen, Jack, Ten, Nine, _] => Straight{high_card: King},
+ [King, _, Queen, Jack, Ten, _, Nine] => Straight{high_card: King},
+ [King, _, Queen, Jack, _, Ten, Nine] => Straight{high_card: King},
+ [King, _, Queen, _, Jack, Ten, Nine] => Straight{high_card: King},
+ [King, _, _, Queen, Jack, Ten, Nine] => Straight{high_card: King},
+ [_, King, Queen, Jack, Ten, Nine, _] => Straight{high_card: King},
+ [_, King, Queen, Jack, Ten, _, Nine] => Straight{high_card: King},
+ [_, King, Queen, Jack, _, Ten, Nine] => Straight{high_card: King},
+ [_, King, Queen, _, Jack, Ten, Nine] => Straight{high_card: King},
+ [_, King, _, Queen, Jack, Ten, Nine] => Straight{high_card: King},
+ [_, _, King, Queen, Jack, Ten, Nine] => Straight{high_card: King},
+
+ [Queen, Jack, Ten, Nine, Eight, _, _] => Straight{high_card: Queen},
+ [Queen, Jack, Ten, Nine, _, Eight, _] => Straight{high_card: Queen},
+ [Queen, Jack, Ten, Nine, _, _, Eight] => Straight{high_card: Queen},
+ [Queen, Jack, Ten, _, Nine, Eight, _] => Straight{high_card: Queen},
+ [Queen, Jack, Ten, _, Nine, _, Eight] => Straight{high_card: Queen},
+ [Queen, Jack, Ten, _, _, Nine, Eight] => Straight{high_card: Queen},
+ [Queen, Jack, _, Ten, Nine, Eight, _] => Straight{high_card: Queen},
+ [Queen, Jack, _, Ten, Nine, _, Eight] => Straight{high_card: Queen},
+ [Queen, Jack, _, Ten, _, Nine, Eight] => Straight{high_card: Queen},
+ [Queen, Jack, _, _, Ten, Nine, Eight] => Straight{high_card: Queen},
+ [Queen, _, Jack, Ten, Nine, Eight, _] => Straight{high_card: Queen},
+ [Queen, _, Jack, Ten, Nine, _, Eight] => Straight{high_card: Queen},
+ [Queen, _, Jack, Ten, _, Nine, Eight] => Straight{high_card: Queen},
+ [Queen, _, Jack, _, Ten, Nine, Eight] => Straight{high_card: Queen},
+ [Queen, _, _, Jack, Ten, Nine, Eight] => Straight{high_card: Queen},
+ [_, Queen, Jack, Ten, Nine, Eight, _] => Straight{high_card: Queen},
+ [_, Queen, Jack, Ten, Nine, _, Eight] => Straight{high_card: Queen},
+ [_, Queen, Jack, Ten, _, Nine, Eight] => Straight{high_card: Queen},
+ [_, Queen, Jack, _, Ten, Nine, Eight] => Straight{high_card: Queen},
+ [_, Queen, _, Jack, Ten, Nine, Eight] => Straight{high_card: Queen},
+ [_, _, Queen, Jack, Ten, Nine, Eight] => Straight{high_card: Queen},
+
+ [Jack, Ten, Nine, Eight, Seven, _, _] => Straight{high_card: Jack},
+ [Jack, Ten, Nine, Eight, _, Seven, _] => Straight{high_card: Jack},
+ [Jack, Ten, Nine, Eight, _, _, Seven] => Straight{high_card: Jack},
+ [Jack, Ten, Nine, _, Eight, Seven, _] => Straight{high_card: Jack},
+ [Jack, Ten, Nine, _, Eight, _, Seven] => Straight{high_card: Jack},
+ [Jack, Ten, Nine, _, _, Eight, Seven] => Straight{high_card: Jack},
+ [Jack, Ten, _, Nine, Eight, Seven, _] => Straight{high_card: Jack},
+ [Jack, Ten, _, Nine, Eight, _, Seven] => Straight{high_card: Jack},
+ [Jack, Ten, _, Nine, _, Eight, Seven] => Straight{high_card: Jack},
+ [Jack, Ten, _, _, Nine, Eight, Seven] => Straight{high_card: Jack},
+ [Jack, _, Ten, Nine, Eight, Seven, _] => Straight{high_card: Jack},
+ [Jack, _, Ten, Nine, Eight, _, Seven] => Straight{high_card: Jack},
+ [Jack, _, Ten, Nine, _, Eight, Seven] => Straight{high_card: Jack},
+ [Jack, _, Ten, _, Nine, Eight, Seven] => Straight{high_card: Jack},
+ [Jack, _, _, Ten, Nine, Eight, Seven] => Straight{high_card: Jack},
+ [_, Jack, Ten, Nine, Eight, Seven, _] => Straight{high_card: Jack},
+ [_, Jack, Ten, Nine, Eight, _, Seven] => Straight{high_card: Jack},
+ [_, Jack, Ten, Nine, _, Eight, Seven] => Straight{high_card: Jack},
+ [_, Jack, Ten, _, Nine, Eight, Seven] => Straight{high_card: Jack},
+ [_, Jack, _, Ten, Nine, Eight, Seven] => Straight{high_card: Jack},
+ [_, _, Jack, Ten, Nine, Eight, Seven] => Straight{high_card: Jack},
+
+ [Ten, Nine, Eight, Seven, Six, _, _] => Straight{high_card: Ten},
+ [Ten, Nine, Eight, Seven, _, Six, _] => Straight{high_card: Ten},
+ [Ten, Nine, Eight, Seven, _, _, Six] => Straight{high_card: Ten},
+ [Ten, Nine, Eight, _, Seven, Six, _] => Straight{high_card: Ten},
+ [Ten, Nine, Eight, _, Seven, _, Six] => Straight{high_card: Ten},
+ [Ten, Nine, Eight, _, _, Seven, Six] => Straight{high_card: Ten},
+ [Ten, Nine, _, Eight, Seven, Six, _] => Straight{high_card: Ten},
+ [Ten, Nine, _, Eight, Seven, _, Six] => Straight{high_card: Ten},
+ [Ten, Nine, _, Eight, _, Seven, Six] => Straight{high_card: Ten},
+ [Ten, Nine, _, _, Eight, Seven, Six] => Straight{high_card: Ten},
+ [Ten, _, Nine, Eight, Seven, Six, _] => Straight{high_card: Ten},
+ [Ten, _, Nine, Eight, Seven, _, Six] => Straight{high_card: Ten},
+ [Ten, _, Nine, Eight, _, Seven, Six] => Straight{high_card: Ten},
+ [Ten, _, Nine, _, Eight, Seven, Six] => Straight{high_card: Ten},
+ [Ten, _, _, Nine, Eight, Seven, Six] => Straight{high_card: Ten},
+ [_, Ten, Nine, Eight, Seven, Six, _] => Straight{high_card: Ten},
+ [_, Ten, Nine, Eight, Seven, _, Six] => Straight{high_card: Ten},
+ [_, Ten, Nine, Eight, _, Seven, Six] => Straight{high_card: Ten},
+ [_, Ten, Nine, _, Eight, Seven, Six] => Straight{high_card: Ten},
+ [_, Ten, _, Nine, Eight, Seven, Six] => Straight{high_card: Ten},
+ [_, _, Ten, Nine, Eight, Seven, Six] => Straight{high_card: Ten},
+
+ [Nine, Eight, Seven, Six, Five, _, _] => Straight{high_card: Nine},
+ [Nine, Eight, Seven, Six, _, Five, _] => Straight{high_card: Nine},
+ [Nine, Eight, Seven, Six, _, _, Five] => Straight{high_card: Nine},
+ [Nine, Eight, Seven, _, Six, Five, _] => Straight{high_card: Nine},
+ [Nine, Eight, Seven, _, Six, _, Five] => Straight{high_card: Nine},
+ [Nine, Eight, Seven, _, _, Six, Five] => Straight{high_card: Nine},
+ [Nine, Eight, _, Seven, Six, Five, _] => Straight{high_card: Nine},
+ [Nine, Eight, _, Seven, Six, _, Five] => Straight{high_card: Nine},
+ [Nine, Eight, _, Seven, _, Six, Five] => Straight{high_card: Nine},
+ [Nine, Eight, _, _, Seven, Six, Five] => Straight{high_card: Nine},
+ [Nine, _, Eight, Seven, Six, Five, _] => Straight{high_card: Nine},
+ [Nine, _, Eight, Seven, Six, _, Five] => Straight{high_card: Nine},
+ [Nine, _, Eight, Seven, _, Six, Five] => Straight{high_card: Nine},
+ [Nine, _, Eight, _, Seven, Six, Five] => Straight{high_card: Nine},
+ [Nine, _, _, Eight, Seven, Six, Five] => Straight{high_card: Nine},
+ [_, Nine, Eight, Seven, Six, Five, _] => Straight{high_card: Nine},
+ [_, Nine, Eight, Seven, Six, _, Five] => Straight{high_card: Nine},
+ [_, Nine, Eight, Seven, _, Six, Five] => Straight{high_card: Nine},
+ [_, Nine, Eight, _, Seven, Six, Five] => Straight{high_card: Nine},
+ [_, Nine, _, Eight, Seven, Six, Five] => Straight{high_card: Nine},
+ [_, _, Nine, Eight, Seven, Six, Five] => Straight{high_card: Nine},
+
+ [Eight, Seven, Six, Five, Four, _, _] => Straight{high_card: Eight},
+ [Eight, Seven, Six, Five, _, Four, _] => Straight{high_card: Eight},
+ [Eight, Seven, Six, Five, _, _, Four] => Straight{high_card: Eight},
+ [Eight, Seven, Six, _, Five, Four, _] => Straight{high_card: Eight},
+ [Eight, Seven, Six, _, Five, _, Four] => Straight{high_card: Eight},
+ [Eight, Seven, Six, _, _, Five, Four] => Straight{high_card: Eight},
+ [Eight, Seven, _, Six, Five, Four, _] => Straight{high_card: Eight},
+ [Eight, Seven, _, Six, Five, _, Four] => Straight{high_card: Eight},
+ [Eight, Seven, _, Six, _, Five, Four] => Straight{high_card: Eight},
+ [Eight, Seven, _, _, Six, Five, Four] => Straight{high_card: Eight},
+ [Eight, _, Seven, Six, Five, Four, _] => Straight{high_card: Eight},
+ [Eight, _, Seven, Six, Five, _, Four] => Straight{high_card: Eight},
+ [Eight, _, Seven, Six, _, Five, Four] => Straight{high_card: Eight},
+ [Eight, _, Seven, _, Six, Five, Four] => Straight{high_card: Eight},
+ [Eight, _, _, Seven, Six, Five, Four] => Straight{high_card: Eight},
+ [_, Eight, Seven, Six, Five, Four, _] => Straight{high_card: Eight},
+ [_, Eight, Seven, Six, Five, _, Four] => Straight{high_card: Eight},
+ [_, Eight, Seven, Six, _, Five, Four] => Straight{high_card: Eight},
+ [_, Eight, Seven, _, Six, Five, Four] => Straight{high_card: Eight},
+ [_, Eight, _, Seven, Six, Five, Four] => Straight{high_card: Eight},
+ [_, _, Eight, Seven, Six, Five, Four] => Straight{high_card: Eight},
+
+ [Seven, Six, Five, Four, Three, _, _] => Straight{high_card: Seven},
+ [Seven, Six, Five, Four, _, Three, _] => Straight{high_card: Seven},
+ [Seven, Six, Five, Four, _, _, Three] => Straight{high_card: Seven},
+ [Seven, Six, Five, _, Four, Three, _] => Straight{high_card: Seven},
+ [Seven, Six, Five, _, Four, _, Three] => Straight{high_card: Seven},
+ [Seven, Six, Five, _, _, Four, Three] => Straight{high_card: Seven},
+ [Seven, Six, _, Five, Four, Three, _] => Straight{high_card: Seven},
+ [Seven, Six, _, Five, Four, _, Three] => Straight{high_card: Seven},
+ [Seven, Six, _, Five, _, Four, Three] => Straight{high_card: Seven},
+ [Seven, Six, _, _, Five, Four, Three] => Straight{high_card: Seven},
+ [Seven, _, Six, Five, Four, Three, _] => Straight{high_card: Seven},
+ [Seven, _, Six, Five, Four, _, Three] => Straight{high_card: Seven},
+ [Seven, _, Six, Five, _, Four, Three] => Straight{high_card: Seven},
+ [Seven, _, Six, _, Five, Four, Three] => Straight{high_card: Seven},
+ [Seven, _, _, Six, Five, Four, Three] => Straight{high_card: Seven},
+ [_, Seven, Six, Five, Four, Three, _] => Straight{high_card: Seven},
+ [_, Seven, Six, Five, Four, _, Three] => Straight{high_card: Seven},
+ [_, Seven, Six, Five, _, Four, Three] => Straight{high_card: Seven},
+ [_, Seven, Six, _, Five, Four, Three] => Straight{high_card: Seven},
+ [_, Seven, _, Six, Five, Four, Three] => Straight{high_card: Seven},
+ [_, _, Seven, Six, Five, Four, Three] => Straight{high_card: Seven},
+
+ [Six, Five, Four, Three, Two, _, _] => Straight{high_card: Six},
+ [Six, Five, Four, Three, _, Two, _] => Straight{high_card: Six},
+ [Six, Five, Four, Three, _, _, Two] => Straight{high_card: Six},
+ [Six, Five, Four, _, Three, Two, _] => Straight{high_card: Six},
+ [Six, Five, Four, _, Three, _, Two] => Straight{high_card: Six},
+ [Six, Five, Four, _, _, Three, Two] => Straight{high_card: Six},
+ [Six, Five, _, Four, Three, Two, _] => Straight{high_card: Six},
+ [Six, Five, _, Four, Three, _, Two] => Straight{high_card: Six},
+ [Six, Five, _, Four, _, Three, Two] => Straight{high_card: Six},
+ [Six, Five, _, _, Four, Three, Two] => Straight{high_card: Six},
+ [Six, _, Five, Four, Three, Two, _] => Straight{high_card: Six},
+ [Six, _, Five, Four, Three, _, Two] => Straight{high_card: Six},
+ [Six, _, Five, Four, _, Three, Two] => Straight{high_card: Six},
+ [Six, _, Five, _, Four, Three, Two] => Straight{high_card: Six},
+ [Six, _, _, Five, Four, Three, Two] => Straight{high_card: Six},
+ [_, Six, Five, Four, Three, Two, _] => Straight{high_card: Six},
+ [_, Six, Five, Four, Three, _, Two] => Straight{high_card: Six},
+ [_, Six, Five, Four, _, Three, Two] => Straight{high_card: Six},
+ [_, Six, Five, _, Four, Three, Two] => Straight{high_card: Six},
+ [_, Six, _, Five, Four, Three, Two] => Straight{high_card: Six},
+ [_, _, Six, Five, Four, Three, Two] => Straight{high_card: Six},
+
+ [Ace, Five, Four, Three, Two, _, _] => Straight{high_card: Five},
+ [Ace, Five, Four, Three, _, Two, _] => Straight{high_card: Five},
+ [Ace, Five, Four, Three, _, _, Two] => Straight{high_card: Five},
+ [Ace, Five, Four, _, Three, Two, _] => Straight{high_card: Five},
+ [Ace, Five, Four, _, Three, _, Two] => Straight{high_card: Five},
+ [Ace, Five, Four, _, _, Three, Two] => Straight{high_card: Five},
+ [Ace, Five, _, Four, Three, Two, _] => Straight{high_card: Five},
+ [Ace, Five, _, Four, Three, _, Two] => Straight{high_card: Five},
+ [Ace, Five, _, Four, _, Three, Two] => Straight{high_card: Five},
+ [Ace, Five, _, _, Four, Three, Two] => Straight{high_card: Five},
+ [Ace, _, Five, Four, Three, Two, _] => Straight{high_card: Five},
+ [Ace, _, Five, Four, Three, _, Two] => Straight{high_card: Five},
+ [Ace, _, Five, Four, _, Three, Two] => Straight{high_card: Five},
+ [Ace, _, Five, _, Four, Three, Two] => Straight{high_card: Five},
+ [Ace, _, _, Five, Four, Three, Two] => Straight{high_card: Five},
+ [_, Ace, Five, Four, Three, Two, _] => Straight{high_card: Five},
+ [_, Ace, Five, Four, Three, _, Two] => Straight{high_card: Five},
+ [_, Ace, Five, Four, _, Three, Two] => Straight{high_card: Five},
+ [_, Ace, Five, _, Four, Three, Two] => Straight{high_card: Five},
+ [_, Ace, _, Five, Four, Three, Two] => Straight{high_card: Five},
+ [_, _, Ace, Five, Four, Three, Two] => Straight{high_card: Five},
+
+ [trip1, trip2, trip3, kicker1, kicker2, _, _] if trip1 == trip2 && trip2 == trip3 => ThreeOfAKind{trips: trip1, kickers: (kicker1, kicker2)},
+ [kicker1, trip1, trip2, trip3, kicker2, _, _] if trip1 == trip2 && trip2 == trip3 => ThreeOfAKind{trips: trip1, kickers: (kicker1, kicker2)},
+ [kicker1, kicker2, trip1, trip2, trip3, _, _] if trip1 == trip2 && trip2 == trip3 => ThreeOfAKind{trips: trip1, kickers: (kicker1, kicker2)},
+ [kicker1, kicker2, _, trip1, trip2, trip3, _] if trip1 == trip2 && trip2 == trip3 => ThreeOfAKind{trips: trip1, kickers: (kicker1, kicker2)},
+ [kicker1, kicker2, _, _, trip1, trip2, trip3] if trip1 == trip2 && trip2 == trip3 => ThreeOfAKind{trips: trip1, kickers: (kicker1, kicker2)},
+
+ [pair1, pair2, pair3, pair4, kicker, _, _] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [pair1, pair2, kicker, pair3, pair4, _, _] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [pair1, pair2, kicker, _, pair3, pair4, _] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [pair1, pair2, kicker, _, _, pair3, pair4] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [kicker, pair1, pair2, pair3, pair4, _, _] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [kicker, pair1, pair2, _, pair3, pair4, _] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [kicker, pair1, pair2, _, _, pair3, pair4] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [kicker, _, pair1, pair2, pair3, pair4, _] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [kicker, _, pair1, pair2, _, pair3, pair4] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [kicker, _, _, pair1, pair2, pair3, pair4] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+
+ [pair1, pair2, kicker1, kicker2, kicker3, _, _] if pair1 == pair2 => Pair{pair: pair1, kickers: (kicker1, kicker2, kicker3)},
+ [kicker1, pair1, pair2, kicker2, kicker3, _, _] if pair1 == pair2 => Pair{pair: pair1, kickers: (kicker1, kicker2, kicker3)},
+ [kicker1, kicker2, pair1, pair2, kicker3, _, _] if pair1 == pair2 => Pair{pair: pair1, kickers: (kicker1, kicker2, kicker3)},
+ [kicker1, kicker2, kicker3, pair1, pair2, _, _] if pair1 == pair2 => Pair{pair: pair1, kickers: (kicker1, kicker2, kicker3)},
+ [kicker1, kicker2, kicker3, _, pair1, pair2, _] if pair1 == pair2 => Pair{pair: pair1, kickers: (kicker1, kicker2, kicker3)},
+ [kicker1, kicker2, kicker3, _, _, pair1, pair2] if pair1 == pair2 => Pair{pair: pair1, kickers: (kicker1, kicker2, kicker3)},
+
+ [rank1, rank2, rank3, rank4, rank5, _, _] => HighCard{kickers: (rank1, rank2, rank3, rank4, rank5)},
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct Odds {
+ player1_wins: usize,
+ player2_wins: usize,
+ draws: usize,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Player {
+ Player1,
+ Player2,
+ Draw,
+}
+
+impl Display for Player {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ f.write_str(match *self {
+ Player::Player1 => "Player 1",
+ Player::Player2 => "Player 2",
+ Player::Draw => "Draw",
+ })
+ }
+}
+
+impl Odds {
+ pub fn player1_probability(&self) -> f64 {
+ self.player1_wins as f64 / (self.player1_wins + self.player2_wins + self.draws) as f64
+ }
+
+ pub fn player2_probability(&self) -> f64 {
+ self.player2_wins as f64 / (self.player1_wins + self.player2_wins + self.draws) as f64
+ }
+
+ pub fn draw_probability(&self) -> f64 {
+ self.draws as f64 / (self.player1_wins + self.player2_wins + self.draws) as f64
+ }
+
+ pub fn favourite(&self) -> Player {
+ match self.player1_wins.cmp(&self.player2_wins) {
+ Ordering::Greater => Player::Player1,
+ Ordering::Less => Player::Player2,
+ Ordering::Equal => Player::Draw,
+ }
+ }
+}
+
+impl Display for Odds {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ write!(f, "Player 1: {:.02}%, Player 2: {:.02}%, Draw: {:.02}%",
+ self.player1_probability() * 100.0,
+ self.player2_probability() * 100.0,
+ self.draw_probability() * 100.0)
+ }
+}
+
+pub fn heads_up_odds(player1: [Card; 2], player2: [Card; 2]) -> Odds {
+ let mut odds = Odds {
+ player1_wins: 0,
+ player2_wins: 0,
+ draws: 0,
+ };
+ let cards: Vec<Card> = FIFTY_TWO_CARD_DECK.iter()
+ .filter(|&&card| card != player1[0])
+ .filter(|&&card| card != player1[1])
+ .filter(|&&card| card != player2[0])
+ .filter(|&&card| card != player2[1])
+ .cloned().collect();
+ for i in 0..48 {
+ for j in i+1..48 {
+ for k in j+1..48 {
+ for l in k+1..48 {
+ for m in l+1..48 {
+ let player1_rank = rank_7_card_hand([player1[0], player1[1], cards[i], cards[j], cards[k], cards[l], cards[m]]);
+ let player2_rank = rank_7_card_hand([player2[0], player2[1], cards[i], cards[j], cards[k], cards[l], cards[m]]);
+ match player1_rank.cmp(&player2_rank) {
+ Ordering::Greater => odds.player1_wins += 1,
+ Ordering::Less => odds.player2_wins += 1,
+ Ordering::Equal => odds.draws += 1,
+ }
+ }
+ }
+ }
+ }
+ }
+ odds
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ use rand::Rng;
+ use rand::seq::SliceRandom;
+
+ pub fn random_4_card_draw<R: Rng>(rng: &mut R) -> [Card; 4] {
+ let mut cards = FIFTY_TWO_CARD_DECK.choose_multiple(rng, 4);
+ [
+ *cards.next().unwrap(),
+ *cards.next().unwrap(),
+ *cards.next().unwrap(),
+ *cards.next().unwrap(),
+ ]
+ }
+
+ pub fn random_7_card_draw<R: Rng>(rng: &mut R) -> [Card; 7] {
+ let mut cards = FIFTY_TWO_CARD_DECK.choose_multiple(rng, 7);
+ [
+ *cards.next().unwrap(),
+ *cards.next().unwrap(),
+ *cards.next().unwrap(),
+ *cards.next().unwrap(),
+ *cards.next().unwrap(),
+ *cards.next().unwrap(),
+ *cards.next().unwrap(),
+ ]
+ }
+
+ fn rank_7_card_hand_naive(cards: [Card; 7]) -> Hand {
+ let rankings = [
+ rank_5_card_hand([cards[0], cards[1], cards[2], cards[3], cards[4]]),
+ rank_5_card_hand([cards[0], cards[1], cards[2], cards[3], cards[5]]),
+ rank_5_card_hand([cards[0], cards[1], cards[2], cards[3], cards[6]]),
+ rank_5_card_hand([cards[0], cards[1], cards[2], cards[4], cards[5]]),
+ rank_5_card_hand([cards[0], cards[1], cards[2], cards[4], cards[6]]),
+ rank_5_card_hand([cards[0], cards[1], cards[2], cards[5], cards[6]]),
+ rank_5_card_hand([cards[0], cards[1], cards[3], cards[4], cards[5]]),
+ rank_5_card_hand([cards[0], cards[1], cards[3], cards[4], cards[6]]),
+ rank_5_card_hand([cards[0], cards[1], cards[3], cards[5], cards[6]]),
+ rank_5_card_hand([cards[0], cards[1], cards[4], cards[5], cards[6]]),
+ rank_5_card_hand([cards[0], cards[2], cards[3], cards[4], cards[5]]),
+ rank_5_card_hand([cards[0], cards[2], cards[3], cards[4], cards[6]]),
+ rank_5_card_hand([cards[0], cards[2], cards[3], cards[5], cards[6]]),
+ rank_5_card_hand([cards[0], cards[2], cards[4], cards[5], cards[6]]),
+ rank_5_card_hand([cards[0], cards[3], cards[4], cards[5], cards[6]]),
+ rank_5_card_hand([cards[1], cards[2], cards[3], cards[4], cards[5]]),
+ rank_5_card_hand([cards[1], cards[2], cards[3], cards[4], cards[6]]),
+ rank_5_card_hand([cards[1], cards[2], cards[3], cards[5], cards[6]]),
+ rank_5_card_hand([cards[1], cards[2], cards[4], cards[5], cards[6]]),
+ rank_5_card_hand([cards[1], cards[3], cards[4], cards[5], cards[6]]),
+ rank_5_card_hand([cards[2], cards[3], cards[4], cards[5], cards[6]]),
+ ];
+ *rankings.iter().max().unwrap()
+ }
+
+ fn rank_5_card_hand(mut cards: [Card; 5]) -> Hand {
+ cards.sort_by(|a, b| b.rank.cmp(&a.rank));
+ let ranks = [cards[0].rank, cards[1].rank, cards[2].rank, cards[3].rank, cards[4].rank];
+ let suits = [cards[0].suit, cards[1].suit, cards[2].suit, cards[3].suit, cards[4].suit];
+
+ match suits {
+ [Spades, Spades, Spades, Spades, Spades] |
+ [Hearts, Hearts, Hearts, Hearts, Hearts] |
+ [Diamonds, Diamonds, Diamonds, Diamonds, Diamonds] |
+ [Clubs, Clubs, Clubs, Clubs, Clubs] =>
+ match ranks {
+ [Ace, King, Queen, Jack, Ten] => RoyalFlush,
+ [King, Queen, Jack, Ten, Nine] => StraightFlush{high_card: King},
+ [Queen, Jack, Ten, Nine, Eight] => StraightFlush{high_card: Queen},
+ [Jack, Ten, Nine, Eight, Seven] => StraightFlush{high_card: Jack},
+ [Ten, Nine, Eight, Seven, Six] => StraightFlush{high_card: Ten},
+ [Nine, Eight, Seven, Six, Five] => StraightFlush{high_card: Nine},
+ [Eight, Seven, Six, Five, Four] => StraightFlush{high_card: Eight},
+ [Seven, Six, Five, Four, Three] => StraightFlush{high_card: Seven},
+ [Six, Five, Four, Three, Two] => StraightFlush{high_card: Six},
+ [Ace, Five, Four, Three, Two] => StraightFlush{high_card: Five},
+ [rank1, rank2, rank3, rank4, rank5] => Flush{flush: (rank1, rank2, rank3, rank4, rank5)},
+ }
+ [_, _, _, _, _] =>
+ match ranks {
+ [quad1, quad2, quad3, quad4, kicker] if quad1 == quad2 && quad2 == quad3 && quad3 == quad4 => FourOfAKind{quads: quad1, kicker: kicker},
+ [kicker, quad1, quad2, quad3, quad4] if quad1 == quad2 && quad2 == quad3 && quad3 == quad4 => FourOfAKind{quads: quad1, kicker: kicker},
+ [trip1, trip2, trip3, pair1, pair2] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [pair1, pair2, trip1, trip2, trip3] if trip1 == trip2 && trip2 == trip3 && pair1 == pair2 => FullHouse{trips: trip1, pair: pair1},
+ [Ace, King, Queen, Jack, Ten] => Straight{high_card: Ace},
+ [King, Queen, Jack, Ten, Nine] => Straight{high_card: King},
+ [Queen, Jack, Ten, Nine, Eight] => Straight{high_card: Queen},
+ [Jack, Ten, Nine, Eight, Seven] => Straight{high_card: Jack},
+ [Ten, Nine, Eight, Seven, Six] => Straight{high_card: Ten},
+ [Nine, Eight, Seven, Six, Five] => Straight{high_card: Nine},
+ [Eight, Seven, Six, Five, Four] => Straight{high_card: Eight},
+ [Seven, Six, Five, Four, Three] => Straight{high_card: Seven},
+ [Six, Five, Four, Three, Two] => Straight{high_card: Six},
+ [Ace, Five, Four, Three, Two] => Straight{high_card: Five},
+ [trip1, trip2, trip3, kicker1, kicker2] if trip1 == trip2 && trip2 == trip3 => ThreeOfAKind{trips: trip1, kickers: (kicker1, kicker2)},
+ [kicker1, trip1, trip2, trip3, kicker2] if trip1 == trip2 && trip2 == trip3 => ThreeOfAKind{trips: trip1, kickers: (kicker1, kicker2)},
+ [kicker1, kicker2, trip1, trip2, trip3] if trip1 == trip2 && trip2 == trip3 => ThreeOfAKind{trips: trip1, kickers: (kicker1, kicker2)},
+ [pair1, pair2, pair3, pair4, kicker] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [pair1, pair2, kicker, pair3, pair4] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [kicker, pair1, pair2, pair3, pair4] if pair1 == pair2 && pair3 == pair4 => TwoPair{pairs: (pair1, pair3), kicker: kicker},
+ [pair1, pair2, kicker1, kicker2, kicker3] if pair1 == pair2 => Pair{pair: pair1, kickers: (kicker1, kicker2, kicker3)},
+ [kicker1, pair1, pair2, kicker2, kicker3] if pair1 == pair2 => Pair{pair: pair1, kickers: (kicker1, kicker2, kicker3)},
+ [kicker1, kicker2, pair1, pair2, kicker3] if pair1 == pair2 => Pair{pair: pair1, kickers: (kicker1, kicker2, kicker3)},
+ [kicker1, kicker2, kicker3, pair1, pair2] if pair1 == pair2 => Pair{pair: pair1, kickers: (kicker1, kicker2, kicker3)},
+ [rank1, rank2, rank3, rank4, rank5] => HighCard{kickers: (rank1, rank2, rank3, rank4, rank5)},
+ }
+ }
+ }
+
+ pub fn heads_up_odds_naive(player1: [Card; 2], player2: [Card; 2]) -> Odds {
+ let mut odds = Odds {
+ player1_wins: 0,
+ player2_wins: 0,
+ draws: 0,
+ };
+ let cards: Vec<Card> = FIFTY_TWO_CARD_DECK.iter()
+ .filter(|&&card| card != player1[0])
+ .filter(|&&card| card != player1[1])
+ .filter(|&&card| card != player2[0])
+ .filter(|&&card| card != player2[1])
+ .cloned().collect();
+ for i in 0..48 {
+ for j in i+1..48 {
+ for k in j+1..48 {
+ for l in k+1..48 {
+ for m in l+1..48 {
+ let player1_rank = rank_7_card_hand([player1[0], player1[1], cards[i], cards[j], cards[k], cards[l], cards[m]]);
+ let player2_rank = rank_7_card_hand([player2[0], player2[1], cards[i], cards[j], cards[k], cards[l], cards[m]]);
+ match player1_rank.cmp(&player2_rank) {
+ Ordering::Greater => odds.player1_wins += 1,
+ Ordering::Less => odds.player2_wins += 1,
+ Ordering::Equal => odds.draws += 1,
+ }
+ }
+ }
+ }
+ }
+ }
+ odds
+ }
+
+ #[test]
+ fn rank_royal_flush() {
+ assert_eq!(rank_5_card_hand([ACE_OF_SPADES, KING_OF_SPADES, QUEEN_OF_SPADES, JACK_OF_SPADES, TEN_OF_SPADES]), RoyalFlush);
+ assert_eq!(rank_5_card_hand([ACE_OF_CLUBS, KING_OF_CLUBS, QUEEN_OF_CLUBS, JACK_OF_CLUBS, TEN_OF_CLUBS]), RoyalFlush);
+ }
+
+ #[test]
+ fn rank_straight_flush() {
+ assert_eq!(rank_5_card_hand([KING_OF_SPADES, QUEEN_OF_SPADES, JACK_OF_SPADES, TEN_OF_SPADES, NINE_OF_SPADES]), StraightFlush{high_card: King});
+ assert_eq!(rank_5_card_hand([FIVE_OF_CLUBS, FOUR_OF_CLUBS, THREE_OF_CLUBS, TWO_OF_CLUBS, ACE_OF_CLUBS]), StraightFlush{high_card: Five});
+ }
+
+ #[test]
+ fn rank_four_of_a_kind() {
+ assert_eq!(rank_5_card_hand([THREE_OF_CLUBS, THREE_OF_DIAMONDS, THREE_OF_HEARTS, THREE_OF_SPADES, ACE_OF_CLUBS]), FourOfAKind{quads: Three, kicker: Ace});
+ assert_eq!(rank_5_card_hand([THREE_OF_CLUBS, TWO_OF_HEARTS, THREE_OF_HEARTS, THREE_OF_SPADES, THREE_OF_DIAMONDS]), FourOfAKind{quads: Three, kicker: Two});
+ }
+
+ #[test]
+ fn rank_full_house() {
+ assert_eq!(rank_5_card_hand([KING_OF_HEARTS, THREE_OF_DIAMONDS, THREE_OF_HEARTS, KING_OF_DIAMONDS, KING_OF_SPADES]), FullHouse{trips: King, pair: Three});
+ assert_eq!(rank_5_card_hand([THREE_OF_SPADES, THREE_OF_DIAMONDS, THREE_OF_HEARTS, KING_OF_DIAMONDS, KING_OF_SPADES]), FullHouse{trips: Three, pair: King});
+ }
+
+ #[test]
+ fn rank_flush() {
+ assert_eq!(rank_5_card_hand([THREE_OF_SPADES, SEVEN_OF_SPADES, ACE_OF_SPADES, FOUR_OF_SPADES, QUEEN_OF_SPADES]), Flush{flush: (Ace, Queen, Seven, Four, Three)});
+ assert_eq!(rank_5_card_hand([TWO_OF_HEARTS, EIGHT_OF_HEARTS, FIVE_OF_HEARTS, SEVEN_OF_HEARTS, NINE_OF_HEARTS]), Flush{flush: (Nine, Eight, Seven, Five, Two)});
+ }
+
+ #[test]
+ fn rank_straight() {
+ assert_eq!(rank_5_card_hand([EIGHT_OF_HEARTS, QUEEN_OF_SPADES, JACK_OF_SPADES, TEN_OF_SPADES, NINE_OF_SPADES]), Straight{high_card: Queen});
+ assert_eq!(rank_5_card_hand([FIVE_OF_CLUBS, FOUR_OF_SPADES, THREE_OF_CLUBS, TWO_OF_HEARTS, ACE_OF_CLUBS]), Straight{high_card: Five});
+ }
+
+ #[test]
+ fn rank_three_of_a_kind() {
+ assert_eq!(rank_5_card_hand([THREE_OF_CLUBS, THREE_OF_DIAMONDS, SEVEN_OF_CLUBS, THREE_OF_SPADES, ACE_OF_CLUBS]), ThreeOfAKind{trips: Three, kickers: (Ace, Seven)});
+ assert_eq!(rank_5_card_hand([THREE_OF_CLUBS, TWO_OF_HEARTS, THREE_OF_HEARTS, SIX_OF_CLUBS, THREE_OF_DIAMONDS]), ThreeOfAKind{trips: Three, kickers: (Six, Two)});
+ }
+
+ #[test]
+ fn rank_two_pair() {
+ assert_eq!(rank_5_card_hand([THREE_OF_CLUBS, SEVEN_OF_HEARTS, SEVEN_OF_CLUBS, THREE_OF_SPADES, ACE_OF_CLUBS]), TwoPair{pairs: (Seven, Three), kicker: Ace});
+ assert_eq!(rank_5_card_hand([THREE_OF_CLUBS, TWO_OF_HEARTS, SIX_OF_HEARTS, SIX_OF_CLUBS, THREE_OF_DIAMONDS]), TwoPair{pairs: (Six, Three), kicker: Two});
+ }
+
+ #[test]
+ fn rank_pair() {
+ assert_eq!(rank_5_card_hand([THREE_OF_CLUBS, SEVEN_OF_HEARTS, NINE_OF_HEARTS, THREE_OF_SPADES, ACE_OF_CLUBS]), Pair{pair: Three, kickers: (Ace, Nine, Seven)});
+ assert_eq!(rank_5_card_hand([THREE_OF_CLUBS, TWO_OF_HEARTS, SEVEN_OF_HEARTS, SIX_OF_CLUBS, THREE_OF_DIAMONDS]), Pair{pair: Three, kickers: (Seven, Six, Two)});
+ }
+
+ #[test]
+ fn rank_high_card() {
+ assert_eq!(rank_5_card_hand([ACE_OF_SPADES, TWO_OF_HEARTS, SEVEN_OF_HEARTS, SIX_OF_CLUBS, THREE_OF_DIAMONDS]), HighCard{kickers: (Ace, Seven, Six, Three, Two)});
+ assert_eq!(rank_5_card_hand([EIGHT_OF_SPADES, SIX_OF_DIAMONDS, SEVEN_OF_HEARTS, KING_OF_HEARTS, FOUR_OF_CLUBS]), HighCard{kickers: (King, Eight, Seven, Six, Four)});
+ }
+
+ #[test]
+ fn rank_7_card_pair() {
+ assert_eq!(rank_7_card_hand([NINE_OF_CLUBS, TWO_OF_SPADES, SIX_OF_CLUBS, ACE_OF_DIAMONDS, FOUR_OF_HEARTS, THREE_OF_HEARTS, FOUR_OF_CLUBS]), Pair{pair: Four, kickers: (Ace, Nine, Six)});
+ }
+
+ #[test]
+ fn rank_7_card_two_pair() {
+ assert_eq!(rank_7_card_hand([SIX_OF_HEARTS, JACK_OF_SPADES, TWO_OF_DIAMONDS, TEN_OF_CLUBS, TWO_OF_CLUBS, SIX_OF_DIAMONDS, FOUR_OF_SPADES]), TwoPair{pairs: (Six, Two), kicker: Jack});
+ }
+
+ #[test]
+ fn rank_7_card_hands_against_naive() {
+ let mut rng = rand::thread_rng();
+ for _ in 0..100000 {
+ let cards = random_7_card_draw(&mut rng);
+ let hand = rank_7_card_hand_naive(cards);
+ assert_eq!(hand, rank_7_card_hand(cards), "cards were: {} {} {} {} {} {} {}", cards[0], cards[1], cards[2], cards[3], cards[4], cards[5], cards[6]);
+ }
+ }
+
+ #[test]
+ fn heads_up_odds_against_naive() {
+ let mut rng = rand::thread_rng();
+ let cards = random_4_card_draw(&mut rng);
+ let player1 = [cards[0], cards[1]];
+ let player2 = [cards[2], cards[3]];
+ let odds = heads_up_odds_naive(player1, player2);
+ assert_eq!(odds, heads_up_odds(player1, player2), "cards were: {}{} vs {}{}", cards[0], cards[1], cards[2], cards[3]);
+ }
+}