use crate::analysis::eval::Eval;
use crate::types::arrays::five_card::FiveCard;
use crate::types::arrays::seven_card::SevenCard;
use crate::types::arrays::two_card::TwoCard;
use crate::types::arrays::{Evaluable, Vectorable};
use crate::types::playing_card::PlayingCard;
use crate::types::poker_cards::PokerCards;
use crate::types::poker_deck::PokerDeck;
use crate::types::U32Card;
use crate::util::random_ordering::RandomOrdering;
use cardpack::Pile;
use ckc_rs::{HandError, PokerCard};
use core::fmt;
use indexmap::set::Iter;
use indexmap::IndexSet;
use itertools::{Combinations, Itertools};
use rayon::prelude::*;
use std::fmt::Formatter;
const NUMBER_OF_SHUFFLES: u8 = 5;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct PlayingCards(IndexSet<PlayingCard>);
impl PlayingCards {
#[must_use]
pub fn deck() -> PlayingCards {
let set: Vec<PlayingCard> = PokerDeck::par_iter().map(PlayingCard::from).collect();
PlayingCards::from(set)
}
#[must_use]
pub fn deck_minus(playing_cards: &PlayingCards) -> PlayingCards {
let mut cards = PlayingCards::default();
let deck = PlayingCards::deck();
for card in deck.iter() {
if playing_cards.get(card).is_none() {
cards.insert(*card);
}
}
cards
}
#[must_use]
pub fn deck_shuffled() -> PlayingCards {
let mut deck = PlayingCards(PokerDeck::iter().map(PlayingCard::from).collect());
deck.shuffle_in_place();
deck
}
pub fn append(&mut self, playing_cards: &PlayingCards) {
for card in playing_cards.iter() {
self.insert(*card);
}
}
pub fn combinations(&self, k: usize) -> Combinations<Iter<'_, PlayingCard>> {
self.iter().combinations(k)
}
#[must_use]
pub fn combine(&self, playing_cards: &PlayingCards) -> PlayingCards {
let mut cards = self.clone();
cards.append(playing_cards);
cards
}
#[must_use]
pub fn contains(&self, playing_card: &PlayingCard) -> bool {
self.0.contains(playing_card)
}
pub fn deal_from_the_bottom(&mut self) -> Option<PlayingCard> {
self.0.pop()
}
#[must_use]
pub fn draw(&mut self, number: usize) -> PlayingCards {
PlayingCards(self.0.drain(0..number).collect())
}
#[must_use]
pub fn draw_from_the_bottom(&mut self, number: usize) -> PlayingCards {
let l = self.len();
PlayingCards(self.0.drain(l - number..l).collect())
}
pub fn draw_one(&mut self) -> PlayingCard {
self.draw(1).deal_from_the_bottom().unwrap()
}
#[allow(clippy::unnecessary_unwrap)]
pub fn eval_7cards(&self) -> Result<Eval, HandError> {
match self.to_seven_array() {
Ok(array) => Ok(array.eval()),
Err(e) => Err(e),
}
}
#[must_use]
pub fn get(&self, playing_card: &PlayingCard) -> Option<&PlayingCard> {
self.0.get(playing_card)
}
#[must_use]
pub fn get_index(&self, index: usize) -> Option<&PlayingCard> {
self.0.get_index(index)
}
pub fn insert(&mut self, playing_card: PlayingCard) -> bool {
if playing_card.is_blank() {
false
} else {
self.0.insert(playing_card)
}
}
#[must_use]
pub fn is_disjoint(&self, other: &PlayingCards) -> bool {
self.0.is_disjoint(&other.0)
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[must_use]
pub fn is_subset(&self, other: &PlayingCards) -> bool {
self.0.is_subset(&other.0)
}
#[must_use]
pub fn is_superset(&self, other: &PlayingCards) -> bool {
self.0.is_superset(&other.0)
}
#[must_use]
pub fn iter(&self) -> indexmap::set::Iter<'_, PlayingCard> {
self.0.iter()
}
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn peak(&self) -> Option<&PlayingCard> {
self.0.first()
}
pub fn reverse(&mut self) {
self.0.reverse();
}
#[must_use]
pub fn shuffle(&self) -> PlayingCards {
let mut shuffled = self.clone();
shuffled.shuffle_in_place();
shuffled
}
pub fn shuffle_in_place(&mut self) {
for _ in 0..NUMBER_OF_SHUFFLES {
self.0
.sort_by(|_, _| rand::random::<RandomOrdering>().into());
}
}
#[must_use]
pub fn sort(&self) -> PlayingCards {
let mut c = self.clone();
c.sort_in_place();
c
}
pub fn sort_in_place(&mut self) {
self.0.sort();
self.0.reverse();
}
#[allow(clippy::missing_panics_doc)]
pub fn to_five_array(&self) -> Result<[PlayingCard; 5], HandError> {
match self.len() {
0..=4 => Err(HandError::NotEnoughCards),
5 => Ok([
*self.get_index(0).unwrap(),
*self.get_index(1).unwrap(),
*self.get_index(2).unwrap(),
*self.get_index(3).unwrap(),
*self.get_index(4).unwrap(),
]),
_ => Err(HandError::TooManyCards),
}
}
pub fn to_five_cards(&self) -> Result<FiveCard, HandError> {
match self.to_five_array() {
Ok(hand) => Ok(FiveCard::from(hand)),
Err(e) => Err(e),
}
}
#[allow(clippy::missing_panics_doc)]
pub fn to_seven_array(&self) -> Result<SevenCard, HandError> {
SevenCard::try_from(self)
}
#[must_use]
pub fn to_vec(&self) -> Vec<PlayingCard> {
self.iter().copied().collect::<Vec<PlayingCard>>()
}
#[must_use]
pub fn two_cards(&self) -> Vec<TwoCard> {
self.combinations(2)
.map(TwoCard::from)
.collect::<Vec<TwoCard>>()
}
}
impl fmt::Display for PlayingCards {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let s = self
.iter()
.map(PlayingCard::to_string)
.collect::<Vec<String>>()
.join(" ");
write!(f, "{}", s)
}
}
impl indexmap::Equivalent<PlayingCard> for IndexSet<PlayingCard> {
fn equivalent(&self, key: &PlayingCard) -> bool {
self.get(key).is_some()
}
}
impl From<&Pile> for PlayingCards {
fn from(pile: &Pile) -> Self {
let filtered = pile.clone().into_iter().filter_map(|c| {
let pc = PlayingCard::from(&c);
if pc.is_blank() {
None
} else {
Some(pc)
}
});
PlayingCards(filtered.collect())
}
}
impl From<&PokerCards> for PlayingCards {
fn from(poker_cards: &PokerCards) -> Self {
PlayingCards::from(&poker_cards.to_vec())
}
}
impl From<&Vec<U32Card>> for PlayingCards {
fn from(v: &Vec<U32Card>) -> Self {
let filtered = v.iter().filter_map(|c| {
let pc = PlayingCard::from(*c);
if pc.is_blank() {
None
} else {
Some(pc)
}
});
PlayingCards(filtered.collect())
}
}
impl From<Vec<&PlayingCard>> for PlayingCards {
fn from(v: Vec<&PlayingCard>) -> Self {
let filtered = v.iter().filter_map(|c| {
let pc = **c;
if pc.is_blank() {
None
} else {
Some(pc)
}
});
PlayingCards(filtered.collect())
}
}
impl From<PlayingCard> for PlayingCards {
fn from(playing_card: PlayingCard) -> Self {
PlayingCards::from(vec![playing_card])
}
}
impl From<Vec<PlayingCard>> for PlayingCards {
fn from(value: Vec<PlayingCard>) -> Self {
PlayingCards(value.into_iter().collect::<IndexSet<_>>())
}
}
impl TryFrom<&'static str> for PlayingCards {
type Error = HandError;
#[allow(clippy::missing_panics_doc)]
fn try_from(value: &'static str) -> Result<Self, Self::Error> {
let mut cards = PlayingCards::default();
for s in value.split_whitespace() {
let card = PlayingCard::from(s);
if card.is_blank() {
return Err(HandError::InvalidCard);
}
cards.insert(card);
}
Ok(cards)
}
}
impl TryFrom<TwoCard> for PlayingCards {
type Error = HandError;
fn try_from(value: TwoCard) -> Result<Self, Self::Error> {
if value.is_dealt() {
let mut cards = PlayingCards::default();
cards.insert(PlayingCard::from(value.first()));
cards.insert(PlayingCard::from(value.second()));
Ok(cards)
} else {
Err(HandError::Incomplete)
}
}
}
#[cfg(test)]
#[allow(non_snake_case)]
mod playing_cards_tests {
use super::*;
fn royal_flush() -> PlayingCards {
PlayingCards::deck().draw(5)
}
fn is_royal_flush(cards: &PlayingCards) -> bool {
cards.contains(&PlayingCard::from("AS"))
&& cards.contains(&PlayingCard::from("KS"))
&& cards.contains(&PlayingCard::from("QS"))
&& cards.contains(&PlayingCard::from("JS"))
&& cards.contains(&PlayingCard::from("TS"))
&& cards.len() == 5
}
#[test]
fn is_royal_flush__test() {
let mut cards = royal_flush();
assert!(is_royal_flush(&cards));
cards.insert(PlayingCard::from("KD"));
assert!(!is_royal_flush(&cards));
}
#[test]
fn combinations() {
let aces = PlayingCards::try_from("AS AH AD AC").unwrap();
assert_eq!(6, aces.combinations(2).count());
assert_eq!(2_598_960, PlayingCards::deck().combinations(5).count());
}
#[test]
fn two_cards() {
let aces = PlayingCards::try_from("AS AH AD AC").unwrap().two_cards();
assert_eq!(6, aces.len());
}
#[test]
fn contains() {
let cards = royal_flush();
assert!(cards.contains(&PlayingCard::from("AS")));
assert!(!cards.contains(&PlayingCard::from("AD")));
}
#[test]
fn deal_from_the_bottom() {
let mut cards = PlayingCards::deck();
let card = cards.deal_from_the_bottom().unwrap();
assert_eq!(card, PlayingCard::from("2C"));
}
#[test]
fn draw() {
let mut cards = PlayingCards::deck();
let drawn = cards.draw(5);
assert!(is_royal_flush(&drawn));
assert_eq!(cards.len(), 47);
}
#[test]
fn draw_one() {
let mut cards = PlayingCards::deck();
let drawn = cards.draw_one();
assert_eq!(drawn, PlayingCard::from("AS"));
assert_eq!(cards.len(), 51);
}
#[test]
fn get() {
let cards = royal_flush();
let ace_spades = PlayingCard::from("AS");
assert_eq!(cards.get(&ace_spades).unwrap(), &ace_spades);
assert!(cards.get(&PlayingCard::from("AD")).is_none());
}
#[test]
fn get_index() {
let cards = royal_flush();
assert_eq!(cards.get_index(0).unwrap(), &PlayingCard::from("AS"));
assert_eq!(cards.get_index(1).unwrap(), &PlayingCard::from("KS"));
assert_eq!(cards.get_index(2).unwrap(), &PlayingCard::from("QS"));
assert_eq!(cards.get_index(3).unwrap(), &PlayingCard::from("JS"));
assert_eq!(cards.get_index(4).unwrap(), &PlayingCard::from("TS"));
assert!(cards.get_index(5).is_none());
}
#[test]
fn insert() {
let mut cards = royal_flush();
let result = cards.insert(PlayingCard::from("AS"));
assert!(!result);
assert!(is_royal_flush(&cards));
}
#[test]
fn is_disjoint() {
let mut deck = PlayingCards::deck();
let royal_flush = deck.draw(5);
let straight_flush = deck.draw(5);
assert!(royal_flush.is_disjoint(&straight_flush));
assert!(straight_flush.is_disjoint(&royal_flush));
assert!(straight_flush.is_disjoint(&deck));
assert!(royal_flush.is_disjoint(&deck));
assert!(deck.is_disjoint(&royal_flush));
assert!(deck.is_disjoint(&straight_flush));
assert!(!royal_flush.is_disjoint(&PlayingCards::deck().draw(2)));
}
#[test]
fn is_empty() {
assert!(PlayingCards::default().is_empty())
}
#[test]
fn is_subset() {
let cards = royal_flush();
let other = PlayingCards::deck_shuffled();
assert!(cards.is_subset(&other));
assert!(!other.is_subset(&cards));
}
#[test]
fn is_superset() {
let cards = royal_flush();
let other = PlayingCards::deck_shuffled();
assert!(other.is_superset(&cards));
assert!(!cards.is_superset(&other));
}
#[test]
fn len() {
assert_eq!(5, royal_flush().len())
}
#[test]
fn reverse() {
let mut cards = royal_flush();
cards.reverse();
assert_eq!("T♠ J♠ Q♠ K♠ A♠", cards.to_string());
}
#[test]
fn shuffle_in_place() {
let mut cards = PlayingCards::deck().draw(5);
cards.shuffle_in_place();
assert!(is_royal_flush(&cards));
cards.sort_in_place();
assert_eq!("A♠ K♠ Q♠ J♠ T♠", cards.to_string());
}
#[test]
fn to_vec() {
let v = vec![
PlayingCard::from("AS"),
PlayingCard::from("KS"),
PlayingCard::from("QS"),
PlayingCard::from("JS"),
PlayingCard::from("TS"),
];
assert_eq!(royal_flush().to_vec(), v);
}
#[test]
fn display() {
let cards = royal_flush();
assert_eq!("A♠ K♠ Q♠ J♠ T♠", cards.to_string());
}
#[test]
fn from__pile() {
let expected = PlayingCards::from(&Pile::french_deck());
let actual = PlayingCards::from(&Pile::french_deck_with_jokers());
assert_eq!(expected, actual);
assert_ne!(royal_flush(), actual);
assert!(PlayingCards::from(&Pile::skat_deck()).is_empty());
}
#[test]
fn try_from__static_str() {
let actual = PlayingCards::try_from("A♠ K♠ Q♠ J♠ T♠").unwrap();
assert_eq!(royal_flush(), actual);
}
#[test]
fn try_from__two_cards() {
let actual = PlayingCards::try_from(TwoCard::try_from("Q♠ J♠").unwrap()).unwrap();
assert_eq!("Q♠ J♠", actual.to_string());
}
#[test]
fn try_from__two_cards__invalid() {
let actual = PlayingCards::try_from(TwoCard::default());
assert!(actual.is_err());
}
}