use crate::types::arrays::Vectorable;
use crate::types::playing_card::PlayingCard;
use crate::types::playing_cards::PlayingCards;
use crate::types::ranges::two_cards_set::TwoCardsSet;
use crate::types::slots::hole_cards::HoleCards;
use crate::types::U32Card;
use ckc_rs::cards::two::Two;
use ckc_rs::{CardNumber, HandError, PokerCard};
use serde::{Deserialize, Serialize};
use std::fmt;
use std::slice::Iter;
#[derive(
Serialize, Deserialize, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
)]
pub struct TwoCard([U32Card; 2]);
impl TwoCard {
#[allow(clippy::comparison_chain)]
pub fn new(first: U32Card, second: U32Card) -> Result<TwoCard, HandError> {
if first == second {
Err(HandError::DuplicateCard)
} else if first == CardNumber::BLANK || second == CardNumber::BLANK {
Err(HandError::BlankCard)
} else if first > second {
Ok(TwoCard([
PlayingCard::from(first).as_u32(),
PlayingCard::from(second).as_u32(),
]))
} else {
Ok(TwoCard([
PlayingCard::from(second).as_u32(),
PlayingCard::from(first).as_u32(),
]))
}
}
pub fn from_index(index: &'static str) -> Result<TwoCard, HandError> {
TwoCard::try_from(index)
}
#[must_use]
pub fn chen_formula(&self) -> i8 {
Two::from(self.to_arr()).chen_formula()
}
#[must_use]
#[allow(clippy::missing_panics_doc)]
pub fn every_other(&self) -> TwoCardsSet {
TwoCardsSet::from(self.remaining())
}
#[must_use]
pub fn is_dealt(&self) -> bool {
(self.0[0] != CardNumber::BLANK) && (self.0[1] != CardNumber::BLANK)
}
#[must_use]
pub fn is_pocket_pair(&self) -> bool {
self.rank_count() == 1
}
#[must_use]
pub fn is_suited(&self) -> bool {
self.suit_count() == 1
}
#[must_use]
pub fn iter(&self) -> Iter<'_, U32Card> {
self.0.iter()
}
#[must_use]
pub fn to_arr(&self) -> [U32Card; 2] {
self.0
}
#[must_use]
pub fn first(&self) -> U32Card {
self.0[0]
}
#[must_use]
pub fn second(&self) -> U32Card {
self.0[1]
}
pub const POCKET_ROCKETS: [U32Card; 2] = [CardNumber::ACE_DIAMONDS, CardNumber::ACE_CLUBS];
pub const COWBOYS: [U32Card; 2] = [CardNumber::KING_DIAMONDS, CardNumber::KING_CLUBS];
pub const LADIES: [U32Card; 2] = [CardNumber::QUEEN_DIAMONDS, CardNumber::QUEEN_CLUBS];
pub const FISHHOOKS: [U32Card; 2] = [CardNumber::JACK_DIAMONDS, CardNumber::JACK_CLUBS];
pub const DIMES: [U32Card; 2] = [CardNumber::TEN_DIAMONDS, CardNumber::TEN_CLUBS];
pub const POPEYES: [U32Card; 2] = [CardNumber::NINE_DIAMONDS, CardNumber::NINE_CLUBS];
pub const SNOWMEN: [U32Card; 2] = [CardNumber::EIGHT_DIAMONDS, CardNumber::EIGHT_CLUBS];
pub const WALKING_STICKS: [U32Card; 2] = [CardNumber::SEVEN_DIAMONDS, CardNumber::SEVEN_CLUBS];
pub const ROUTE_66: [U32Card; 2] = [CardNumber::SIX_DIAMONDS, CardNumber::SIX_CLUBS];
pub const SPEED_LIMIT: [U32Card; 2] = [CardNumber::FIVE_DIAMONDS, CardNumber::FIVE_CLUBS];
pub const SAILBOATS: [U32Card; 2] = [CardNumber::FOUR_DIAMONDS, CardNumber::FOUR_CLUBS];
pub const CRABS: [U32Card; 2] = [CardNumber::TREY_DIAMONDS, CardNumber::TREY_CLUBS];
pub const DUCKS: [U32Card; 2] = [CardNumber::DEUCE_DIAMONDS, CardNumber::DEUCE_CLUBS];
}
impl Vectorable for TwoCard {
#[must_use]
fn to_vec(&self) -> Vec<U32Card> {
self.0.to_vec()
}
}
impl fmt::Display for TwoCard {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} {}",
PlayingCard::from(self.0[0]),
PlayingCard::from(self.0[1])
)
}
}
impl From<&[U32Card; 2]> for TwoCard {
fn from(array: &[U32Card; 2]) -> Self {
TwoCard(*array)
}
}
impl From<[U32Card; 2]> for TwoCard {
fn from(array: [U32Card; 2]) -> Self {
TwoCard(array)
}
}
impl From<Vec<U32Card>> for TwoCard {
fn from(v: Vec<U32Card>) -> Self {
let one = match v.get(0) {
Some(c) => *c,
_ => CardNumber::BLANK,
};
let two = match v.get(1) {
Some(c) => *c,
_ => CardNumber::BLANK,
};
match TwoCard::new(one, two) {
Ok(two_cards) => two_cards,
_ => TwoCard::default(),
}
}
}
impl From<Two> for TwoCard {
fn from(two: Two) -> Self {
TwoCard::from(two.to_arr())
}
}
impl From<Vec<&PlayingCard>> for TwoCard {
fn from(v: Vec<&PlayingCard>) -> Self {
if v.len() < 2 {
return TwoCard::default();
}
let first = *(*v.get(0).unwrap());
let second = *(*v.get(1).unwrap());
match TwoCard::new(first.as_u32(), second.as_u32()) {
Ok(two_card) => two_card,
Err(_) => TwoCard::default(),
}
}
}
impl TryFrom<HoleCards> for TwoCard {
type Error = HandError;
fn try_from(value: HoleCards) -> Result<Self, Self::Error> {
TwoCard::new(
value.get_first_card().as_u32(),
value.get_second_card().as_u32(),
)
}
}
impl TryFrom<&'static str> for TwoCard {
type Error = HandError;
#[allow(clippy::missing_panics_doc)]
fn try_from(value: &'static str) -> Result<Self, Self::Error> {
match PlayingCards::try_from(value) {
Ok(cards) => {
if cards.len() == 2 {
TwoCard::new(
cards.get_index(0).unwrap().as_u32(),
cards.get_index(1).unwrap().as_u32(),
)
} else {
Err(HandError::InvalidCardCount)
}
}
Err(e) => Err(e),
}
}
}
#[cfg(test)]
#[allow(non_snake_case)]
mod arrays_two_card_tests {
use super::*;
#[test]
fn new() {
let cards = TwoCard::new(CardNumber::ACE_CLUBS, CardNumber::ACE_SPADES);
assert!(cards.is_ok());
assert_eq!("A♠ A♣", cards.unwrap().to_string());
}
#[test]
fn new__blank() {
let err = TwoCard::new(CardNumber::ACE_CLUBS, CardNumber::BLANK);
assert!(err.is_err());
assert_eq!(err.unwrap_err(), HandError::BlankCard);
}
#[test]
fn new__duplicate() {
let err = TwoCard::new(CardNumber::ACE_CLUBS, CardNumber::ACE_CLUBS);
assert!(err.is_err());
assert_eq!(err.unwrap_err(), HandError::DuplicateCard);
}
#[test]
fn array() {
assert_eq!([0, 0], TwoCard::default().to_arr());
}
#[test]
fn is_suited() {
assert!(!TwoCard::new(CardNumber::ACE_CLUBS, CardNumber::ACE_SPADES)
.unwrap()
.is_suited());
assert!(TwoCard::new(CardNumber::ACE_CLUBS, CardNumber::KING_CLUBS)
.unwrap()
.is_suited());
}
#[test]
fn every_other() {
let hand = TwoCard::new(CardNumber::ACE_CLUBS, CardNumber::ACE_SPADES).unwrap();
let every_other = hand.every_other();
assert!(!every_other.contains(&hand));
}
#[test]
fn display() {
let two = TwoCard::default();
assert_eq!("__ __", two.to_string());
}
#[test]
fn try_from__index() {
let two = TwoCard::try_from("AS AC").unwrap();
assert_eq!("A♠ A♣", two.to_string());
}
#[test]
fn try_from__index_duplicate() {
let err = TwoCard::try_from("AC AC");
assert!(err.is_err());
assert_eq!(err.unwrap_err(), HandError::InvalidCardCount);
}
#[test]
fn try_from__index__sort() {
assert_eq!("A♠ A♣", TwoCard::try_from("AC AS").unwrap().to_string());
assert_eq!("K♣ 9♠", TwoCard::try_from("9S KC").unwrap().to_string());
}
}