use crate::deck::{Deck, DeckBuilder};
use failure_derive::Fail;
use std::fmt::Display;
use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Suit {
Spades,
Clubs,
Hearts,
Diamonds,
Joker,
}
use self::Suit::*;
impl Suit {
pub fn from_usize(u: usize) -> Option<Suit> {
match u {
0 => Some(Spades),
1 => Some(Clubs),
2 => Some(Hearts),
3 => Some(Diamonds),
4 => Some(Joker),
_ => None,
}
}
pub fn from_char(c: char) -> Option<Suit> {
match c {
's' | 'S' => Some(Spades),
'c' | 'C' => Some(Clubs),
'h' | 'H' => Some(Hearts),
'd' | 'D' => Some(Diamonds),
'j' | 'J' => Some(Joker),
_ => None,
}
}
pub fn as_char(&self) -> char {
match self {
Spades => 'S',
Hearts => 'H',
Clubs => 'C',
Diamonds => 'D',
Joker => 'J',
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PCard {
pub suit: Suit,
pub num: u8,
}
pub fn pcard_deck_builder(jokers: bool) -> DeckBuilder<PCard> {
let mut rvec = Vec::new();
for suit in 0..4 {
for val in 1..14 {
rvec.push(PCard::new(Suit::from_usize(suit).unwrap(), val));
}
}
if jokers {
rvec.push(PCard::new(Joker, 0));
rvec.push(PCard::new(Joker, 1));
}
DeckBuilder::new().draw_pile(rvec)
}
pub fn pcard_deck(jokers: bool) -> Deck<PCard> {
pcard_deck_builder(jokers).done()
}
pub trait ToCVal {
fn to_card_val(self) -> u8;
}
impl ToCVal for u8 {
fn to_card_val(self) -> u8 {
self
}
}
impl ToCVal for char {
fn to_card_val(self) -> u8 {
match self {
'a' | 'A' => 1,
't' | 'T' => 10,
'j' | 'J' => 11,
'q' | 'Q' => 12,
'k' | 'K' => 13,
'1'...'9' => (self as u8) - 48,
_ => 0,
}
}
}
impl PCard {
pub fn new<CV: ToCVal>(suit: Suit, v: CV) -> PCard {
PCard {
suit: suit,
num: v.to_card_val(),
}
}
pub fn s<CV: ToCVal>(v: CV) -> PCard {
PCard::new(Spades, v)
}
pub fn c<CV: ToCVal>(v: CV) -> PCard {
PCard::new(Clubs, v)
}
pub fn h<CV: ToCVal>(v: CV) -> PCard {
PCard::new(Hearts, v)
}
pub fn d<CV: ToCVal>(v: CV) -> PCard {
PCard::new(Diamonds, v)
}
pub fn jk(v: u8) -> PCard {
PCard::new(Joker, v)
}
}
#[derive(Clone, Debug, Copy,PartialEq, Fail)]
pub enum ParseErr {
#[fail(display = "Could not parse Card")]
BadParse,
#[fail(display = "Input ran out")]
TooShort,
}
impl FromStr for PCard {
type Err = ParseErr;
fn from_str(s: &str) -> Result<PCard, ParseErr> {
let mut it = s.chars();
let c = it.next().ok_or(ParseErr::TooShort)?;
let mut num = c.to_card_val();
let mut next = it.next().ok_or(ParseErr::TooShort)?;
if c == '1' {
if next == '0'{
num = 10;
next = it.next().ok_or(ParseErr::TooShort)?;
}
}
if c == 'J' {
if next == 'k' {
return Ok(PCard::jk(1))
}
}
let suit =
Suit::from_char(next).ok_or(ParseErr::BadParse)?;
Ok(PCard { suit, num })
}
}
impl Display for PCard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
if self.suit == Joker {
return write!(f, "Jk");
}
let c = match self.num {
1 => 'A',
2...9 => (self.num + 48) as char,
10 => return write!(f, "10{}", self.suit.as_char()),
11 => 'J',
12 => 'Q',
13 => 'K',
_ => 'E',
};
write!(f, "{}{}", c, self.suit.as_char())
}
}
#[cfg(test)]
mod test_playing_cards {
use super::*;
#[test]
pub fn test_pcard_from_str() {
assert_eq!(PCard::from_str("10S").unwrap(), PCard::s(10));
assert_eq!(PCard::from_str("1S").unwrap(), PCard::s(1),"1 spades");
assert_eq!(PCard::from_str("5H").unwrap(), PCard::h(5),"5 hearts");
assert_eq!(PCard::from_str("Jk").unwrap(), PCard::jk(1));
assert_eq!(PCard::from_str("JS").unwrap(), PCard::s(11));
assert_eq!(PCard::from_str("JH").unwrap(), PCard::h('j'));
}
}