use std::error::Error;
use crate::card::{Card, Rank, Suit};
use super::evaluator::evaluator::evaluate;
const MIN_CARDS: usize = 2;
const MAX_CARDS: usize = 9;
#[derive(Clone)]
pub struct Hand {
cards: Vec<Card>,
}
impl Hand {
pub fn new(cards: Vec<Card>) -> Result<Hand, Box<dyn Error>> {
let num_cards = cards.len();
if num_cards < MIN_CARDS || num_cards > MAX_CARDS {
return Err(format!(
"A poker hand must have between {} and {} cards.",
MIN_CARDS, MAX_CARDS
)
.into());
}
Ok(Hand { cards })
}
pub fn new_from_str(s: &str) -> Result<Self, Box<dyn Error>> {
let strings: Vec<&str> = s.split_whitespace().collect();
if strings.len() < MIN_CARDS || strings.len() > MAX_CARDS {
return Err(format!(
"A poker hand must have between {} and {} cards.",
MIN_CARDS, MAX_CARDS
)
.into());
}
let mut cards = Vec::new();
for s in strings {
let card = Card::new_from_str(s).map_err(|_| format!("Invalid card string: {}", s))?;
cards.push(card);
}
Ok(Hand { cards })
}
pub fn add_card(&mut self, new_card: Card) -> Result<(), Box<dyn Error>> {
if self.cards.len() + 1 > MAX_CARDS {
return Err("Too many cards in the hand.".into());
}
self.cards.push(new_card);
Ok(())
}
pub fn add_cards(&mut self, new_cards: Vec<Card>) -> Result<(), Box<dyn Error>> {
if self.cards.len() + new_cards.len() > MAX_CARDS {
return Err("Too many cards to add.".into());
}
for card in new_cards {
self.cards.push(card);
}
Ok(())
}
pub fn get_cards(&self) -> &Vec<Card> {
&self.cards
}
pub fn get_count(&self) -> usize {
self.cards.len()
}
pub fn get_score(&self) -> u32 {
evaluate(self)
}
pub fn get_ranks(&self) -> Vec<Rank> {
self.cards.iter().map(|card| card.rank).collect()
}
pub fn as_str(&self) -> String {
self.cards
.iter()
.map(|card| card.as_str())
.collect::<Vec<_>>()
.join(" ")
}
pub fn sort_by_suit(&mut self) {
self.cards
.sort_by(|a, b| a.suit.partial_cmp(&b.suit).unwrap());
}
pub fn sort_by_rank(&mut self, ascending: bool) -> Result<(), Box<dyn Error>> {
if ascending {
self.cards
.sort_by(|a, b| a.rank.partial_cmp(&b.rank).unwrap());
} else {
self.cards
.sort_by(|a, b| b.rank.partial_cmp(&a.rank).unwrap());
}
Ok(())
}
pub fn cards_of_suit(&self, suit: Suit) -> Vec<Card> {
self.cards
.iter()
.filter(|&card| card.suit == suit)
.cloned()
.collect()
}
}
#[test]
fn test_create_hand() {
let cards = vec![
Card::new_from_str("2h").unwrap(),
Card::new_from_str("3d").unwrap(),
Card::new_from_str("4s").unwrap(),
Card::new_from_str("5c").unwrap(),
Card::new_from_str("6h").unwrap(),
Card::new_from_str("7d").unwrap(),
Card::new_from_str("8s").unwrap(),
];
let hand = Hand::new(cards);
assert!(hand.is_ok());
let hand = hand.unwrap();
assert_eq!(hand.get_cards().len(), 7)
}
#[test]
fn test_create_hand_with_wrong_number_of_cards() {
let cards = vec![Card::new_from_str("3d").unwrap()];
let result = Hand::new(cards);
assert!(result.is_err());
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_straight_flushes() {
let hand = Hand::new_from_str("2s As Js Ks Qs 9c Ts").unwrap();
let score = hand.get_score();
assert_eq!(score, 8_000_000 + 14);
let hand = Hand::new_from_str("2s Kc Js Ks Qs 9s Ts").unwrap();
let score = hand.get_score();
assert_eq!(score, 8_000_000 + 13);
let hand = Hand::new_from_str("9h 8h Jc Tc Qh Jh Th").unwrap();
let score = hand.get_score();
assert_eq!(score, 8_000_000 + 12);
let hand = Hand::new_from_str("2s 7s Js 9s 8s 9c Ts").unwrap();
let score = hand.get_score();
assert_eq!(score, 8_000_000 + 11);
let hand = Hand::new_from_str("9d 8d Td 7d 6d 3c Th Kh Qd").unwrap();
let score = hand.get_score();
assert_eq!(score, 8_000_000 + 10);
let hand = Hand::new_from_str("9d 8d 5d 6d 7d").unwrap();
let score = hand.get_score();
assert_eq!(score, 8_000_000 + 9);
let hand = Hand::new_from_str("4c 5c 6c 7c 8c 3c 2c").unwrap();
let score = hand.get_score();
assert_eq!(score, 8_000_000 + 8);
let hand = Hand::new_from_str("7d 7c 7s 6d 5d 3d 4d").unwrap();
let score = hand.get_score();
assert_eq!(score, 8_000_000 + 7);
let hand = Hand::new_from_str("6d 5d 4d 3d 2d Ad").unwrap();
let score = hand.get_score();
assert_eq!(score, 8_000_000 + 6);
let hand = Hand::new_from_str("2d Ad 3d 4d 5d 3c Th").unwrap();
let score = hand.get_score();
assert_eq!(score, 8_000_000 + 5);
}
#[test]
fn test_four_of_a_kind() {
let hand = Hand::new_from_str("As Ac Ad Ah Ts 9c Qs").unwrap();
let score = hand.get_score();
assert_eq!(score, 7_000_000 + (14 << 4) + 12);
let hand = Hand::new_from_str("As Ac Ad Ah").unwrap();
let score = hand.get_score();
assert_eq!(score, 7_000_000 + 14);
let hand = Hand::new_from_str("9c Ks Kc Kd Kh Ts 2s").unwrap();
let score = hand.get_score();
assert_eq!(score, 7_000_000 + (13 << 4) + 10);
let hand = Hand::new_from_str("Qs Qc Qd Qh 8s 9c 9s").unwrap();
let score = hand.get_score();
assert_eq!(score, 7_000_000 + (12 << 4) + 9);
let hand = Hand::new_from_str("2s 2c 2d 2h As 9c Qs").unwrap();
let score = hand.get_score();
assert_eq!(score, 7_000_000 + (2 << 4) + 14);
}
#[test]
fn test_full_house() {
let hand = Hand::new_from_str("As Ac Ad Kh Ts Kc Qs").unwrap();
let score = hand.get_score();
assert_eq!(score, 6_000_000 + (14 << 4) + 13);
let hand = Hand::new_from_str("Ks Qc Kd Kh Qd").unwrap();
let score = hand.get_score();
assert_eq!(score, 6_000_000 + (13 << 4) + 12);
let hand = Hand::new_from_str("Tc 9s 9c Td 9h Ts 2s").unwrap();
let score = hand.get_score();
assert_eq!(score, 6_000_000 + (10 << 4) + 9);
let hand = Hand::new_from_str("4s 4c 4d 5h 5s 9c 9s").unwrap();
let score = hand.get_score();
assert_eq!(score, 6_000_000 + (4 << 4) + 9);
let hand = Hand::new_from_str("2s 2c 2d 3h As 3c Qs").unwrap();
let score = hand.get_score();
assert_eq!(score, 6_000_000 + (2 << 4) + 3);
}
#[test]
fn test_flush() {
let hand = Hand::new_from_str("As Ks Qs Js 9s 8s 7s").unwrap();
let score = hand.get_score();
assert_eq!(
score,
5_000_000 + (14 << 16) + (13 << 12) + (12 << 8) + (11 << 4) + 9
);
let hand = Hand::new_from_str("2s 2c 2d 3h As 3c Qs").unwrap();
let score_low_fh = hand.get_score();
assert!(score < score_low_fh);
let hand = Hand::new_from_str("Ks Kd Qs Js 9s 9d 7s").unwrap();
let score = hand.get_score();
assert_eq!(
score,
5_000_000 + (13 << 16) + (12 << 12) + (11 << 8) + (9 << 4) + 7
);
let hand = Hand::new_from_str("Qs Js 9s 8s 7s").unwrap();
let score = hand.get_score();
assert_eq!(
score,
5_000_000 + (12 << 16) + (11 << 12) + (9 << 8) + (8 << 4) + 7
);
let hand = Hand::new_from_str("7s Kd Qd 4s 5s 3s 2s").unwrap();
let score = hand.get_score();
assert_eq!(
score,
5_000_000 + (7 << 16) + (5 << 12) + (4 << 8) + (3 << 4) + 2
);
}
#[test]
fn test_straight() {
let hand = Hand::new_from_str("2d Ac Js Ks Qs 9c Ts").unwrap();
let score = hand.get_score();
assert_eq!(score, 4_000_000 + 14);
let hand = Hand::new_from_str("2s Kc Jh Kd Qs 9s Ts").unwrap();
let score = hand.get_score();
assert_eq!(score, 4_000_000 + 13);
let hand = Hand::new_from_str("9c 8h Jc Tc Qs Jh Th").unwrap();
let score = hand.get_score();
assert_eq!(score, 4_000_000 + 12);
let hand = Hand::new_from_str("2c 7c Js 9s 8h 9c Ts").unwrap();
let score = hand.get_score();
assert_eq!(score, 4_000_000 + 11);
let hand = Hand::new_from_str("9h 8d Ts 7d 6c 3c Th Kh Qd").unwrap();
let score = hand.get_score();
assert_eq!(score, 4_000_000 + 10);
let hand = Hand::new_from_str("9c 8h 5d 6d 7d").unwrap();
let score = hand.get_score();
assert_eq!(score, 4_000_000 + 9);
let hand = Hand::new_from_str("4c 5d 6c 7h 8c 3d 2c").unwrap();
let score = hand.get_score();
assert_eq!(score, 4_000_000 + 8);
let hand = Hand::new_from_str("7d 7c 7s 6d 5c 3d 4d").unwrap();
let score = hand.get_score();
assert_eq!(score, 4_000_000 + 7);
let hand = Hand::new_from_str("6d 5d 4d 3c 2d Ac").unwrap();
let score = hand.get_score();
assert_eq!(score, 4_000_000 + 6);
let hand = Hand::new_from_str("2d Ac 3d 4d 5d 3c Th").unwrap();
let score = hand.get_score();
assert_eq!(score, 4_000_000 + 5);
}
#[test]
fn test_three_of_a_kind() {
let hand = Hand::new_from_str("2s Ac Ad Ah Ts 9c Qs").unwrap();
let score = hand.get_score();
assert_eq!(score, 3_000_000 + (14 << 8) + (12 << 4) + 10);
let hand = Hand::new_from_str("As Ac Ad 2h").unwrap();
let score = hand.get_score();
assert_eq!(score, 3_000_000 + (14 << 4) + 2);
let hand = Hand::new_from_str("As Ac Ad").unwrap();
let score = hand.get_score();
assert_eq!(score, 3_000_000 + 14);
let hand = Hand::new_from_str("9c Ks Kc Kd Ah Ts 2s").unwrap();
let score = hand.get_score();
assert_eq!(score, 3_000_000 + (13 << 8) + (14 << 4) + 10);
let hand = Hand::new_from_str("9c 3s 2c 2d Kh Ts 2s").unwrap();
let score = hand.get_score();
assert_eq!(score, 3_000_000 + (2 << 8) + (13 << 4) + 10);
let hand = Hand::new_from_str("2s 2c 2d").unwrap();
let score = hand.get_score();
assert_eq!(score, 3_000_000 + 2);
}
#[test]
fn test_two_pair() {
let hand = Hand::new_from_str("Ks Ac Ad Kh Ts 2c Qs").unwrap();
let score = hand.get_score();
assert_eq!(score, 2_000_000 + (14 << 8) + (13 << 4) + 12);
let hand = Hand::new_from_str("Ks Qc Kd Ah Qd").unwrap();
let score = hand.get_score();
assert_eq!(score, 2_000_000 + (13 << 8) + (12 << 4) + 14);
let hand = Hand::new_from_str("Ks Qc Kd Qd").unwrap();
let score = hand.get_score();
assert_eq!(score, 2_000_000 + (13 << 4) + 12);
let hand = Hand::new_from_str("Tc 8s 9c 8d 9h Ts 2s").unwrap();
let score = hand.get_score();
assert_eq!(score, 2_000_000 + (10 << 8) + (9 << 4) + 8);
let hand = Hand::new_from_str("4s 4c 2d 5h 5s 9c 9s").unwrap();
let score = hand.get_score();
assert_eq!(score, 2_000_000 + (9 << 8) + (5 << 4) + 4);
let hand = Hand::new_from_str("2s 2c 3h 3c").unwrap();
let score = hand.get_score();
assert_eq!(score, 2_000_000 + (3 << 4) + 2);
}
#[test]
fn test_pair() {
let hand = Hand::new_from_str("Ks Ac Ad 9h Js 2c Qs").unwrap();
let score = hand.get_score();
assert_eq!(score, 1_000_000 + (14 << 12) + (13 << 8) + (12 << 4) + 11);
let hand = Hand::new_from_str("Ks 2c Kd Ah Qd").unwrap();
let score = hand.get_score();
assert_eq!(score, 1_000_000 + (13 << 12) + (14 << 8) + (12 << 4) + 2);
let hand = Hand::new_from_str("Ks 2c Kd Qd").unwrap();
let score = hand.get_score();
assert_eq!(score, 1_000_000 + (13 << 8) + (12 << 4) + 2);
let hand = Hand::new_from_str("Ks 2c Kd").unwrap();
let score = hand.get_score();
assert_eq!(score, 1_000_000 + (13 << 4) + 2);
let hand = Hand::new_from_str("Ks Kd").unwrap();
let score = hand.get_score();
assert_eq!(score, 1_000_000 + 13);
let hand = Hand::new_from_str("Tc 3s 5c 8d 9h Ts 2s").unwrap();
let score = hand.get_score();
assert_eq!(score, 1_000_000 + (10 << 12) + (9 << 8) + (8 << 4) + 5);
let hand = Hand::new_from_str("4s 4c 2d 3h 5s 9c Ts").unwrap();
let score = hand.get_score();
assert_eq!(score, 1_000_000 + (4 << 12) + (10 << 8) + (9 << 4) + 5);
let hand = Hand::new_from_str("2s 2c Ah Kc").unwrap();
let score = hand.get_score();
assert_eq!(score, 1_000_000 + (2 << 8) + (14 << 4) + 13);
}
#[test]
fn test_high_card() {
let hand = Hand::new_from_str("Ks Ac 9d 8h Js 2c Qs").unwrap();
let score = hand.get_score();
assert_eq!(score, (14 << 16) + (13 << 12) + (12 << 8) + (11 << 4) + 9);
let hand = Hand::new_from_str("Ks 2c Jd Ah Qd").unwrap();
let score = hand.get_score();
assert_eq!(score, (14 << 16) + (13 << 12) + (12 << 8) + (11 << 4) + 2);
let hand = Hand::new_from_str("Ks 2c 3d Qd").unwrap();
let score = hand.get_score();
assert_eq!(score, (13 << 12) + (12 << 8) + (3 << 4) + 2);
let hand = Hand::new_from_str("Ks 2c 4d").unwrap();
let score = hand.get_score();
assert_eq!(score, (13 << 8) + (4 << 4) + 2);
let hand = Hand::new_from_str("As Kd").unwrap();
let score = hand.get_score();
assert_eq!(score, (14 << 4) + 13);
let hand = Hand::new_from_str("Ac 3s 5c 8d 9h Ts 2s").unwrap();
let score = hand.get_score();
assert_eq!(score, (14 << 16) + (10 << 12) + (9 << 8) + (8 << 4) + 5);
let hand = Hand::new_from_str("7s 4c 2d 3h 5s 8c 9s").unwrap();
let score = hand.get_score();
assert_eq!(score, (9 << 16) + (8 << 12) + (7 << 8) + (5 << 4) + 4);
let hand = Hand::new_from_str("2s 3c 4h 5c 7s").unwrap();
let score = hand.get_score();
assert_eq!(score, (7 << 16) + (5 << 12) + (4 << 8) + (3 << 4) + 2);
}
#[test]
fn test_corner_cases() {
let hand1 = Hand::new_from_str("2d Ad 3d 4d 5d").unwrap();
let score1 = hand1.get_score();
assert_eq!(score1, 8_000_000 + 5);
let hand2 = Hand::new_from_str("As Ac Ad Ah Ks").unwrap();
let score2 = hand2.get_score();
assert_eq!(score2, 7_000_000 + (14 << 4) + 13);
assert!(score1 > score2);
let hand1 = Hand::new_from_str("2s 2c 2d 2h").unwrap();
let score1 = hand1.get_score();
assert_eq!(score1, 7_000_000 + 2);
let hand2 = Hand::new_from_str("As Ac Ad Kh Kc").unwrap();
let score2 = hand2.get_score();
assert_eq!(score2, 6_000_000 + (14 << 4) + 13);
assert!(score1 > score2);
let hand1 = Hand::new_from_str("2s 2c 2d 3h 3c").unwrap();
let score1 = hand1.get_score();
assert_eq!(score1, 6_000_000 + (2 << 4) + 3);
let hand2 = Hand::new_from_str("As Ks Qs Js 9s").unwrap();
let score2 = hand2.get_score();
assert_eq!(
score2,
5_000_000 + (14 << 16) + (13 << 12) + (12 << 8) + (11 << 4) + 9
);
assert!(score1 > score2);
let hand1 = Hand::new_from_str("7s 4s 5s 3s 2s").unwrap();
let score1 = hand1.get_score();
assert_eq!(
score1,
5_000_000 + (7 << 16) + (5 << 12) + (4 << 8) + (3 << 4) + 2
);
let hand2 = Hand::new_from_str("Ac Js Ks Qs Ts").unwrap();
let score2 = hand2.get_score();
assert_eq!(score2, 4_000_000 + 14);
assert!(score1 > score2);
let hand1 = Hand::new_from_str("2d Ac 3d 4d 5d").unwrap();
let score1 = hand1.get_score();
assert_eq!(score1, 4_000_000 + 5);
let hand2 = Hand::new_from_str("Ks Ac Ad Ah Qs").unwrap();
let score2 = hand2.get_score();
assert_eq!(score2, 3_000_000 + (14 << 8) + (13 << 4) + 12);
assert!(score1 > score2);
let hand1 = Hand::new_from_str("2s 2c 2d").unwrap();
let score1 = hand1.get_score();
assert_eq!(score1, 3_000_000 + 2);
let hand2 = Hand::new_from_str("Ks Ac Ad Kh Qs").unwrap();
let score2 = hand2.get_score();
assert_eq!(score2, 2_000_000 + (14 << 8) + (13 << 4) + 12);
assert!(score1 > score2);
let hand1 = Hand::new_from_str("2s 2c 3h 3c").unwrap();
let score1 = hand1.get_score();
assert_eq!(score1, 2_000_000 + (3 << 4) + 2);
let hand2 = Hand::new_from_str("Ks Ac Ad Js Qs").unwrap();
let score2 = hand2.get_score();
assert_eq!(score2, 1_000_000 + (14 << 12) + (13 << 8) + (12 << 4) + 11);
assert!(score1 > score2);
let hand1 = Hand::new_from_str("2s 2c").unwrap();
let score1 = hand1.get_score();
assert_eq!(score1, 1_000_000 + 2);
let hand2 = Hand::new_from_str("Ks Ac 9d Js Qs").unwrap();
let score2 = hand2.get_score();
assert_eq!(score2, (14 << 16) + (13 << 12) + (12 << 8) + (11 << 4) + 9);
assert!(score1 > score2);
}
}