use crate::types::arrays::Vectorable;
use crate::types::playing_card::PlayingCard;
use crate::types::playing_cards::PlayingCards;
use crate::types::poker_deck::PokerDeck;
use crate::types::U32Card;
use cardpack::{Pile, Standard52};
use ckc_rs::cards::two::Two;
use ckc_rs::{CKCNumber, CardNumber, CardRank, HandError, PokerCard};
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::fmt;
pub const POSSIBLE_COMBINATIONS: usize = 7937;
#[derive(Clone, Debug, Hash, PartialEq)]
pub struct PokerCards(Vec<U32Card>);
impl PokerCards {
#[must_use]
pub fn deck() -> PokerCards {
PokerDeck::poker_cards()
}
#[must_use]
pub fn from_index(index: &'static str) -> Result<PokerCards, HandError> {
let mut cards = PokerCards::default();
for s in index.split_whitespace() {
let card = CKCNumber::from_index(s);
if card.is_blank() {
return Err(HandError::InvalidCard);
}
cards.push(card);
}
Ok(cards)
}
#[must_use]
#[allow(clippy::needless_pass_by_value)]
pub fn from_index_string(index: String) -> Result<PokerCards, HandError> {
let mut cards = PokerCards::default();
for s in index.split_whitespace() {
let card = CKCNumber::from_index(s);
if card.is_blank() {
return Err(HandError::InvalidCard);
}
cards.push(card);
}
Ok(cards)
}
pub fn append(&mut self, other: &PokerCards) {
self.0.append(&mut other.0.clone());
}
#[must_use]
pub fn combine(self, other: &PokerCards) -> PokerCards {
let mut r = self;
r.append(&other.filter_blank());
r
}
#[must_use]
pub fn contains(&self, card: &U32Card) -> bool {
self.0.contains(card)
}
#[must_use]
pub fn deal(&mut self, number: usize) -> PokerCards {
if self.len() >= number {
let v: Vec<U32Card> = self.0.drain(0..number).collect();
PokerCards(v)
} else {
PokerCards::default()
}
}
#[must_use]
pub fn deal_from_standard52(standard52: &mut Standard52, number: usize) -> PokerCards {
let pile = standard52.draw(number).unwrap();
let mut cards = PokerCards::default();
for card in pile {
cards.push(PlayingCard::from(&card).as_u32());
}
cards
}
#[must_use]
pub fn deal_from_the_bottom(&mut self, num: usize) -> PokerCards {
let mut dealt = PokerCards::default();
for _ in 0..num {
let popped = self.pop();
if let Some(card) = popped {
dealt.push(card);
}
}
dealt.0.reverse();
dealt
}
#[must_use]
pub fn divisible_by(&self, x: usize) -> bool {
(self.len() % x) == 0
}
#[must_use]
pub fn filter_blank(&self) -> PokerCards {
PokerCards::from(
self.0
.clone()
.into_iter()
.filter(|c| *c != CardNumber::BLANK)
.collect::<Vec<U32Card>>(),
)
}
#[must_use]
pub fn filter_eqgt_on_rank(&self, rank: CardRank) -> PokerCards {
PokerCards::from(
self.0
.clone()
.into_iter()
.filter(|c| c.get_card_rank() as u8 >= rank as u8)
.collect::<Vec<U32Card>>(),
)
}
#[must_use]
pub fn get(&self, index: usize) -> Option<&U32Card> {
self.0.get(index)
}
#[must_use]
pub fn is_complete_hand(&self) -> bool {
self.len() == 5
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[must_use]
pub fn is_valid(&self) -> bool {
self.len() == PlayingCards::from(self).len()
}
pub fn iter(&self) -> impl Iterator<Item = &U32Card> {
self.0.iter()
}
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
pub fn pop(&mut self) -> Option<U32Card> {
self.0.pop()
}
#[must_use]
pub fn primes(&self) -> Vec<u32> {
let mut v: Vec<u32> = Vec::new();
for c in self.iter() {
v.push(c & 0xff);
}
v
}
pub fn pull(&mut self) -> U32Card {
if self.is_empty() {
return CardNumber::BLANK;
}
self.0.remove(0)
}
pub fn push(&mut self, ckc: U32Card) {
self.0.push(ckc);
}
#[must_use]
pub fn shuffle(&self) -> PokerCards {
let mut shuffled = self.clone();
shuffled.shuffle_in_place();
shuffled
}
pub fn shuffle_in_place(&mut self) {
self.0.shuffle(&mut thread_rng());
}
#[must_use]
pub fn sort(&self) -> PokerCards {
let mut cards = self.clone();
cards.sort_in_place();
cards
}
pub fn sort_in_place(&mut self) {
self.0.sort_unstable();
self.0.reverse();
}
#[must_use]
pub fn to_pile(&self) -> Pile {
let mut pile = Pile::default();
for card in &self.0 {
pile.push(PlayingCard::from(*card).as_card());
}
pile
}
#[must_use]
pub fn try_into_twos(&self) -> Result<Vec<Two>, HandError> {
if !self.divisible_by(2) {
return Err(HandError::InvalidCardCount);
}
let mut v: Vec<Two> = Vec::new();
let mut cards = self.clone();
loop {
let c1 = cards.pull();
if c1.is_blank() {
break;
}
v.push(Two::new(c1, cards.pull()));
}
Ok(v)
}
}
impl Default for PokerCards {
fn default() -> Self {
PokerCards::from(Vec::new())
}
}
impl fmt::Display for PokerCards {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_pile().to_symbol_index())
}
}
impl From<Pile> for PokerCards {
fn from(value: Pile) -> Self {
let mut pcks = PokerCards::default();
for card in value {
pcks.push(PlayingCard::from(&card).as_u32());
}
pcks
}
}
impl From<&PlayingCards> for PokerCards {
fn from(cards: &PlayingCards) -> Self {
PokerCards(cards.iter().map(PlayingCard::as_u32).collect())
}
}
impl From<Vec<U32Card>> for PokerCards {
fn from(value: Vec<U32Card>) -> Self {
PokerCards(value)
}
}
impl TryFrom<&'static str> for PokerCards {
type Error = HandError;
#[allow(clippy::missing_panics_doc)]
fn try_from(value: &'static str) -> Result<Self, Self::Error> {
PokerCards::from_index(value)
}
}
impl TryFrom<String> for PokerCards {
type Error = HandError;
#[allow(clippy::missing_panics_doc)]
fn try_from(value: String) -> Result<Self, Self::Error> {
PokerCards::from_index_string(value)
}
}
impl Vectorable for PokerCards {
#[must_use]
fn to_vec(&self) -> Vec<U32Card> {
self.0.clone()
}
}
#[cfg(test)]
#[allow(non_snake_case)]
mod poker_cards_tests {
use super::*;
use crate::types::poker_deck::PokerDeck;
#[test]
fn append() {
let standard52 = &mut Standard52::new_shuffled();
let hole_cards = PokerCards::deal_from_standard52(standard52, 2);
let flop = PokerCards::deal_from_standard52(standard52, 3);
let mut five_cards = hole_cards.clone();
five_cards.append(&flop);
assert_eq!(
format!("{}", five_cards),
format!("{} {}", hole_cards, flop)
);
}
#[test]
fn combine() {
let standard52 = &mut Standard52::new_shuffled();
let hole_cards = PokerCards::deal_from_standard52(standard52, 2);
let flop = PokerCards::deal_from_standard52(standard52, 3);
let five_cards = hole_cards.clone().combine(&flop);
assert_eq!(
format!("{}", five_cards),
format!("{} {}", hole_cards, flop)
);
}
#[test]
fn contains() {
let poker_cards = PokerCards::try_from("AS KS").unwrap();
assert!(poker_cards.contains(&CardNumber::ACE_SPADES));
assert!(poker_cards.contains(&CardNumber::KING_SPADES));
assert!(!poker_cards.contains(&CardNumber::QUEEN_SPADES));
}
#[test]
fn deal() {
let mut deck = PokerDeck::poker_cards_shuffled();
let hand1 = deck.deal(5);
let hand2 = deck.deal(5);
assert_eq!(deck.len(), 42);
assert_eq!(hand1.len(), 5);
assert_eq!(hand2.len(), 5);
}
#[test]
fn deal_overflow() {
let mut deck = PokerDeck::poker_cards_shuffled();
let hand1 = deck.deal(25);
let hand2 = deck.deal(25);
let hand3 = deck.deal(3);
assert_eq!(deck.len(), 2);
assert_eq!(hand1.len(), 25);
assert_eq!(hand2.len(), 25);
assert!(hand3.is_empty());
}
#[test]
fn filter_blank() {
let mut poker_cards = PokerCards::try_from("AS KS").unwrap();
poker_cards.push(CardNumber::BLANK);
poker_cards.push(CardNumber::BLANK);
poker_cards.push(CardNumber::TEN_SPADES);
assert_eq!(poker_cards.len(), 5);
assert_eq!("A♠ K♠ __ __ T♠", poker_cards.to_string());
assert_eq!("A♠ K♠ T♠", poker_cards.filter_blank().to_string());
}
#[test]
fn filter_gt_on_rank() {
let deck = PokerCards::deck();
let filtered = deck.filter_eqgt_on_rank(CardRank::KING);
assert_eq!(filtered.len(), 8);
for card in filtered.iter() {
println!("{}", card.to_string());
}
}
#[test]
fn deal_from_the_bottom() {
let mut hand = PokerCards::try_from("A♠ A♠ Q♠ J♠ T♠").unwrap();
let dealt = hand.deal_from_the_bottom(3);
assert_eq!("Q♠ J♠ T♠", dealt.to_string());
assert_eq!("A♠ A♠", hand.to_string());
}
#[test]
fn deal_from_the_bottom__some() {
let mut hand = PokerCards::try_from("J♠ T♠").unwrap();
let dealt = hand.deal_from_the_bottom(3);
assert_eq!(dealt.len(), 2);
assert_eq!("J♠ T♠", dealt.to_string());
assert!(hand.is_empty());
}
#[test]
fn deal_from_the_bottom__none() {
let mut hand = PokerCards::default();
let dealt = hand.deal_from_the_bottom(3);
assert_eq!(dealt, hand);
assert!(dealt.is_empty());
}
#[test]
fn is_valid() {
assert!(PokerCards::try_from(" A♠ Q♠ J♠ T♠ ")
.unwrap()
.is_valid());
assert!(!PokerCards::try_from("A♠ A♠ Q♠ J♠ T♠").unwrap().is_valid());
}
#[test]
fn pop() {
let mut hand = PokerCards::try_from("A♠ A♠ Q♠ J♠ T♠").unwrap();
let last = hand.pop().unwrap();
assert_eq!(last, CardNumber::TEN_SPADES);
assert_eq!("A♠ A♠ Q♠ J♠", hand.to_string());
}
#[test]
fn pop__empty() {
let mut hand = PokerCards::default();
let last = hand.pop();
assert!(last.is_none());
}
#[test]
#[ignore]
fn sort() {
let hand = PokerCards::try_from("KC AD KH KD AS").unwrap();
let sorted = hand.sort();
println!("{}", sorted);
let hand = PokerCards::try_from("KC AD KH KD AS").unwrap();
let sorted = hand.sort();
println!("{}", sorted);
}
#[test]
fn try_into_twos() {
let two = vec![
Two::try_from("J♠ T♠").unwrap(),
Two::try_from("A♠ K♠").unwrap(),
];
let cards = PokerCards::try_from("JS TS AS KS")
.unwrap()
.try_into_twos()
.unwrap();
assert_eq!(two, cards);
}
#[test]
fn try_into_twos__not_divisible_into_two() {
let cards = PokerCards::try_from("KC AD KH KD AS")
.unwrap()
.try_into_twos();
assert!(cards.is_err());
}
#[test]
fn try_from__index_str() {
assert_eq!(
"K♣ A♦ K♥ K♦ A♠",
PokerCards::try_from("KC AD KH KD AS").unwrap().to_string()
);
}
#[test]
fn try_from__index_str__invalid() {
let cards = PokerCards::try_from("KX AD KH KD AS");
assert!(cards.is_err());
assert_eq!(HandError::InvalidCard, cards.unwrap_err());
}
}