use crate::types::arrays::Vectorable;
use crate::types::playing_card::PlayingCard;
use crate::types::playing_cards::PlayingCards;
use crate::types::{PileOfCards, U32Card};
use ckc_rs::cards::two::Two;
use ckc_rs::PokerCard;
use log::warn;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(
Serialize, Deserialize, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
)]
pub struct Hand(PlayingCard, PlayingCard);
impl Hand {
#[must_use]
pub fn new(first: PlayingCard, second: PlayingCard) -> Hand {
if !Hand::is_valid(Hand(first, second)) {
warn!("Invalid HoldemHand: {} {}", first, second);
return Hand::blank();
}
if first > second {
Hand(first, second)
} else {
Hand(second, first)
}
}
#[must_use]
pub fn blank() -> Hand {
Hand(PlayingCard::default(), PlayingCard::default())
}
#[must_use]
pub fn first(&self) -> PlayingCard {
self.0
}
#[must_use]
pub fn second(&self) -> PlayingCard {
self.1
}
#[must_use]
pub fn as_playing_cards(&self) -> PlayingCards {
PlayingCards::from(vec![self.0, self.1])
}
#[must_use]
pub fn as_two(&self) -> Two {
Two::new(self.first().as_u32(), self.second().as_u32())
}
#[must_use]
pub fn is_blank(&self) -> bool {
self.has(PlayingCard::BLANK)
}
#[must_use]
pub fn is_compatible(&self, other: &Hand) -> bool {
!self.has(other.first())
&& !self.has(other.second())
&& !self.is_blank()
&& !other.is_blank()
}
#[must_use]
fn is_valid(hand: Hand) -> bool {
!hand.first().is_blank() && !hand.second().is_blank() && hand.first() != hand.second()
}
}
impl PileOfCards<PlayingCard> for Hand {
fn has(&self, playing_card: PlayingCard) -> bool {
(self.0 == playing_card) || (self.1 == playing_card)
}
}
impl PileOfCards<U32Card> for Hand {
fn has(&self, card_number: U32Card) -> bool {
(self.0.as_u32() == card_number) || (self.1.as_u32() == card_number)
}
}
impl fmt::Display for Hand {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.0, self.1)
}
}
impl From<&'static str> for Hand {
fn from(s: &'static str) -> Self {
let v: Vec<&str> = s.split_whitespace().collect();
if v.len() == 2 {
Hand::new(
PlayingCard::from(*v.get(0).unwrap()),
PlayingCard::from(*v.get(1).unwrap()),
)
} else {
Hand::default()
}
}
}
impl Vectorable for Hand {
#[must_use]
fn to_vec(&self) -> Vec<U32Card> {
vec![self.first().as_u32(), self.second().as_u32()]
}
}
#[cfg(test)]
#[allow(non_snake_case)]
mod types_hands_holdem_hand {
use super::*;
use ckc_rs::CardNumber;
#[test]
fn new() {
let inverted = Hand::new(PlayingCard::KING_SPADES, PlayingCard::ACE_SPADES);
let same = Hand::new(PlayingCard::ACE_SPADES, PlayingCard::KING_SPADES);
let expected = Hand::new(PlayingCard::ACE_SPADES, PlayingCard::KING_SPADES);
assert_eq!(inverted, expected);
assert_eq!(same, expected);
}
#[test]
fn new__blank() {
assert!(Hand::new(PlayingCard::default(), PlayingCard::ACE_SPADES).is_blank());
assert!(Hand::new(PlayingCard::ACE_SPADES, PlayingCard::default()).is_blank());
assert!(Hand::new(PlayingCard::ACE_SPADES, PlayingCard::ACE_SPADES).is_blank());
assert!(Hand::new(PlayingCard::default(), PlayingCard::default()).is_blank());
assert!(!Hand::new(PlayingCard::ACE_SPADES, PlayingCard::KING_SPADES).is_blank());
}
#[test]
fn accessors() {
let actual = Hand::new(PlayingCard::KING_SPADES, PlayingCard::ACE_SPADES);
assert_eq!(actual.first(), PlayingCard::ACE_SPADES);
assert_eq!(actual.second(), PlayingCard::KING_SPADES);
}
#[test]
fn as_two() {
let hand = Hand::new(PlayingCard::KING_SPADES, PlayingCard::ACE_SPADES);
let expected = Two::new(CardNumber::ACE_SPADES, CardNumber::KING_SPADES);
assert_eq!(hand.as_two(), expected);
}
#[test]
fn contains() {
let hand = Hand::new(PlayingCard::KING_SPADES, PlayingCard::ACE_SPADES);
assert!(hand.has(CardNumber::ACE_SPADES));
assert!(hand.has(PlayingCard::KING_SPADES));
assert!(!hand.has(PlayingCard::QUEEN_SPADES));
}
#[test]
fn is_blank() {
assert!(Hand::blank().is_blank());
}
#[test]
fn is_compatible() {
let hand = Hand::new(PlayingCard::KING_SPADES, PlayingCard::ACE_SPADES);
assert!(hand.is_compatible(&Hand::new(
PlayingCard::ACE_CLUBS,
PlayingCard::KING_DIAMONDS
)));
assert!(!hand.is_compatible(&Hand::new(
PlayingCard::ACE_SPADES,
PlayingCard::KING_SPADES
)));
assert!(!hand.is_compatible(&Hand::new(PlayingCard::ACE_CLUBS, PlayingCard::KING_SPADES)));
assert!(!hand.is_compatible(&Hand::new(
PlayingCard::ACE_SPADES,
PlayingCard::KING_DIAMONDS
)));
assert!(!hand.is_compatible(&Hand::new(PlayingCard::ACE_SPADES, PlayingCard::ACE_SPADES)));
}
#[test]
fn fmt__to_string() {
let actual = Hand::new(PlayingCard::KING_SPADES, PlayingCard::ACE_SPADES);
assert_eq!(actual.to_string(), "A♠ K♠");
}
}