use crate::card::{CardValue, PlayingCard}; use core::fmt; use std::collections::HashMap; #[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Debug)] pub enum HandType { HighCard, OnePair, TwoPair, ThreeOfAKind, Straight, Flush, FullHouse, FourOfAKind, StraightFlush, } #[derive(PartialEq)] pub struct PokerHand { cards: Vec, } impl fmt::Display for PokerHand { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self.hand_type() { HandType::HighCard => write!(f, "{}", self.card_str()), HandType::OnePair => { for val in self.hash_map() { if val.1 == 2 { return write!(f, "{} | Pair of {:?}'s", self.card_str(), val); } } return write!(f, "???"); } HandType::TwoPair => todo!(), HandType::ThreeOfAKind => todo!(), HandType::Straight => todo!(), HandType::Flush => todo!(), HandType::FullHouse => todo!(), HandType::FourOfAKind => todo!(), HandType::StraightFlush => todo!(), }; s } } impl PartialOrd for PokerHand { fn partial_cmp(&self, other: &Self) -> Option { if self.hand_type() != other.hand_type() { return self.hand_type().partial_cmp(&other.hand_type()); } let selfmap = self.hash_map(); let othermap = other.hash_map(); match self.hand_type() { HandType::HighCard => { // Compare high cards self.cards.partial_cmp(&other.cards) } HandType::OnePair => { let selfpair: Vec<(&CardValue, &u8)> = selfmap.iter().filter(|&p| *p.1 == 2).collect(); let otherpair: Vec<(&CardValue, &u8)> = othermap.iter().filter(|&p| *p.1 == 2).collect(); let pairvalue = selfpair[0].0; let otherpairvalue = otherpair[0].0; if pairvalue != otherpairvalue { return pairvalue.partial_cmp(otherpairvalue); } self.cards.partial_cmp(&other.cards) } HandType::TwoPair => { let selfpairs: Vec<(&CardValue, &u8)> = selfmap.iter().filter(|&p| *p.1 == 2).collect(); let otherpairs: Vec<(&CardValue, &u8)> = othermap.iter().filter(|&p| *p.1 == 2).collect(); for i in 0..1 { let pairvalue = selfpairs[i].0; let otherpairvalue = otherpairs[i].0; if pairvalue != otherpairvalue { return pairvalue.partial_cmp(otherpairvalue); } } self.cards.partial_cmp(&other.cards) } HandType::ThreeOfAKind => { let selfpairs: Vec<(&CardValue, &u8)> = selfmap.iter().filter(|&p| *p.1 == 3).collect(); let otherpairs: Vec<(&CardValue, &u8)> = othermap.iter().filter(|&p| *p.1 == 3).collect(); let pairvalue = selfpairs[0].0; let otherpairvalue = otherpairs[0].0; if pairvalue != otherpairvalue { return pairvalue.partial_cmp(otherpairvalue); } self.cards.partial_cmp(&other.cards) } HandType::Straight => self.cards.partial_cmp(&other.cards), HandType::Flush => self.cards.partial_cmp(&other.cards), HandType::FullHouse => { let threes: Vec<(&CardValue, &u8)> = selfmap.iter().filter(|&p| *p.1 == 3).collect(); let otherthrees: Vec<(&CardValue, &u8)> = othermap.iter().filter(|&p| *p.1 == 3).collect(); if threes[0].0 != otherthrees[0].0 { return threes[0].0.partial_cmp(otherthrees[0].0); } let twos: Vec<(&CardValue, &u8)> = selfmap.iter().filter(|&p| *p.1 == 2).collect(); let othertwos: Vec<(&CardValue, &u8)> = othermap.iter().filter(|&p| *p.1 == 2).collect(); if twos[0].0 != othertwos[0].0 { return twos[0].0.partial_cmp(othertwos[0].0); } self.cards.partial_cmp(&other.cards) } HandType::FourOfAKind => { let fours: Vec<(&CardValue, &u8)> = selfmap.iter().filter(|&p| *p.1 == 4).collect(); let otherfours: Vec<(&CardValue, &u8)> = othermap.iter().filter(|&p| *p.1 == 4).collect(); if fours[0].0 != otherfours[0].0 { return fours[0].0.partial_cmp(otherfours[0].0); } self.cards.partial_cmp(&other.cards) } HandType::StraightFlush => self.cards.partial_cmp(&other.cards), } } } impl PokerHand { pub fn new(mut cards: Vec) -> Self { assert!(cards.len() == 5); // Sorted highest card first cards.sort_unstable(); cards.reverse(); PokerHand { cards } } fn card_str(&self) -> String { let mut cardstr: String = "".to_owned(); for card in &self.cards { cardstr.push_str(&card.to_string()); cardstr.push(' '); } cardstr } fn hash_map(&self) -> HashMap { let mut count: HashMap = HashMap::new(); for card in &self.cards { *count.entry(card.value).or_insert(0) += 1; } count } pub fn hand_type(&self) -> HandType { if is_straight_flush(self) { return HandType::StraightFlush; } if is_four_of_a_kind(self) { return HandType::FourOfAKind; } if is_full_house(self) { return HandType::FullHouse; } if is_flush(self) { return HandType::Flush; } if is_straight(self) { return HandType::Straight; } if is_three_of_a_kind(self) { return HandType::ThreeOfAKind; } if is_two_pair(self) { return HandType::TwoPair; } if is_one_pair(self) { return HandType::OnePair; } return HandType::HighCard; } } fn is_straight_flush(hand: &PokerHand) -> bool { let hand = &hand.cards; assert!(hand.len() == 5); let suit = hand[0].suit; let mut min_val = CardValue::Ace; let mut max_val = CardValue::Two; // Must all be the same suit for i in 0..5 { let card = &hand[i]; for k in (i + 1)..5 { if hand[k].value == card.value { return false; } } if card.value < min_val { min_val = card.value; }; if card.value > max_val { max_val = card.value; } if card.suit != suit { return false; } } let max_val = max_val as u8; let min_val = min_val as u8; if max_val - min_val > 4 { return false; } true } fn is_four_of_a_kind(hand: &PokerHand) -> bool { for e in hand.hash_map() { if e.1 == 4 { return true; } } false } fn is_full_house(hand: &PokerHand) -> bool { let map = hand.hash_map(); if map.len() != 2 { return false; } let count: Vec = map.into_values().collect(); // https://stackoverflow.com/questions/45353757/how-to-count-the-elements-in-a-vector-with-some-value-without-looping if count.iter().filter(|&n| *n == 2).count() != 1 { return false; } if count.iter().filter(|&n| *n == 2).count() != 1 { return false; } true } fn is_flush(hand: &PokerHand) -> bool { let suit = hand.cards[0].suit; for card in &hand.cards { if card.suit != suit { return false; } } true } fn is_straight(hand: &PokerHand) -> bool { for i in 1..4 { let current_card = hand.cards[i].value as u8; let previous_card = hand.cards[i - 1].value as u8; if current_card != previous_card - 1 { return false; } } true } fn is_three_of_a_kind(hand: &PokerHand) -> bool { let map = hand.hash_map(); let count: Vec = map.into_values().collect(); count.contains(&3) } fn is_two_pair(hand: &PokerHand) -> bool { let map = hand.hash_map(); let count: Vec = map.into_values().collect(); // https://stackoverflow.com/questions/45353757/how-to-count-the-elements-in-a-vector-with-some-value-without-looping count.iter().filter(|&n| *n == 2).count() == 2 } fn is_one_pair(hand: &PokerHand) -> bool { let map = hand.hash_map(); let count: Vec = map.into_values().collect(); // https://stackoverflow.com/questions/45353757/how-to-count-the-elements-in-a-vector-with-some-value-without-looping count.iter().filter(|&n| *n == 2).count() == 1 } #[cfg(test)] mod tests { use crate::card::CardSuit; use super::*; #[test] fn one_pair_test() { let card1 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Ace, }; let card2 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Ace, }; let card3 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Two, }; let card4 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Five, }; let card5 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Eight, }; let pair = vec![card1, card2, card3, card4, card5]; let hand = PokerHand::new(pair); assert_eq!(hand.hand_type(), HandType::OnePair); let card1 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Ace, }; let card2 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::King, }; let card3 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Two, }; let card4 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Five, }; let card5 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Eight, }; let nopair = vec![card1, card2, card3, card4, card5]; let hand = PokerHand::new(nopair); assert_eq!(hand.hand_type(), HandType::HighCard); } #[test] fn two_pair_test() { let card1 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Ace, }; let card2 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Ace, }; let card3 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Two, }; let card4 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Five, }; let card5 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Five, }; let pair = vec![card1, card2, card3, card4, card5]; let hand = PokerHand::new(pair); assert_eq!(hand.hand_type(), HandType::TwoPair); } #[test] fn three_of_a_kind_tests() { let card1 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Ace, }; let card2 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Ace, }; let card3 = PlayingCard { suit: CardSuit::Spades, value: CardValue::Ace, }; let card4 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Five, }; let card5 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Two, }; let pair = vec![card1, card2, card3, card4, card5]; let hand = PokerHand::new(pair); assert_eq!(hand.hand_type(), HandType::ThreeOfAKind); } #[test] fn staight_test() { let card1 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Six, }; let card2 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Eight, }; let card3 = PlayingCard { suit: CardSuit::Spades, value: CardValue::Seven, }; let card4 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Five, }; let card5 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Nine, }; let pair = vec![card1, card2, card3, card4, card5]; let hand = PokerHand::new(pair); assert_eq!(hand.hand_type(), HandType::Straight); } #[test] fn flush_test() { let card1 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Six, }; let card2 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Two, }; let card3 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Queen, }; let card4 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Jack, }; let card5 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Ace, }; let pair = vec![card1, card2, card3, card4, card5]; let hand = PokerHand::new(pair); assert_eq!(hand.hand_type(), HandType::Flush); } #[test] fn full_house_test() { let card1 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Six, }; let card2 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Six, }; let card3 = PlayingCard { suit: CardSuit::Spades, value: CardValue::Two, }; let card4 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Six, }; let card5 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Two, }; let pair = vec![card1, card2, card3, card4, card5]; let hand = PokerHand::new(pair); assert_eq!(hand.hand_type(), HandType::FullHouse); } #[test] fn four_of_a_kind_test() { let card1 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Six, }; let card2 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Six, }; let card3 = PlayingCard { suit: CardSuit::Spades, value: CardValue::Six, }; let card4 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Six, }; let card5 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Two, }; let pair = vec![card1, card2, card3, card4, card5]; let hand = PokerHand::new(pair); assert_eq!(hand.hand_type(), HandType::FourOfAKind); } #[test] fn straight_flush_test() { let card1 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Jack, }; let card2 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Ten, }; let card3 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Nine, }; let card4 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Seven, }; let card5 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Eight, }; let pair = vec![card1, card2, card3, card4, card5]; let hand = PokerHand::new(pair); assert_eq!(hand.hand_type(), HandType::StraightFlush); } #[test] fn comp_test1() { // Hand 1 let card1 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Jack, }; let card2 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Jack, }; let card3 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Nine, }; let card4 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Ace, }; let card5 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Eight, }; // Hand 2 let card6 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Queen, }; let card7 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Ten, }; let card8 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Queen, }; let card9 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Two, }; let card10 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Eight, }; let cardset1 = vec![card1, card2, card3, card4, card5]; let cardset2 = vec![card6, card7, card8, card9, card10]; let flush = PokerHand::new(cardset1); let onepair = PokerHand::new(cardset2); assert!(flush > onepair); } #[test] fn straight_flush_ord_test() { // Hand 1 let card1 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Jack, }; let card2 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Ten, }; let card3 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Nine, }; let card4 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Eight, }; let card5 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Seven, }; // Hand 2 let card6 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Queen, }; let card7 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Jack, }; let card8 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Ten, }; let card9 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Nine, }; let card10 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Eight, }; let cardset1 = vec![card1, card2, card3, card4, card5]; let cardset2 = vec![card6, card7, card8, card9, card10]; let hand1 = PokerHand::new(cardset1); let hand2 = PokerHand::new(cardset2); assert!(hand1 < hand2); assert!(hand1 >= hand1); assert!(hand2 <= hand2); } #[test] fn four_kind_ord_test() { // Hand 1 let card1 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Jack, }; let card2 = PlayingCard { suit: CardSuit::Hearts, value: CardValue::Jack, }; let card3 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Jack, }; let card4 = PlayingCard { suit: CardSuit::Spades, value: CardValue::Jack, }; let card5 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Seven, }; // Hand 2 let card6 = PlayingCard { suit: CardSuit::Spades, value: CardValue::Queen, }; let card7 = PlayingCard { suit: CardSuit::Hearts, value: CardValue::Queen, }; let card8 = PlayingCard { suit: CardSuit::Clubs, value: CardValue::Queen, }; let card9 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Queen, }; let card10 = PlayingCard { suit: CardSuit::Diamonds, value: CardValue::Eight, }; let cardset1 = vec![card1, card2, card3, card4, card5]; let cardset2 = vec![card6, card7, card8, card9, card10]; let hand1 = PokerHand::new(cardset1); let hand2 = PokerHand::new(cardset2); assert!(hand1 < hand2); assert!(hand1 >= hand1); assert!(hand2 <= hand2); } }