use std::fmt;
use std::fmt::Display;
use crate::{Card, Color, Rank, Suit};
impl From<Rank> for char {
fn from(rank: Rank) -> Self {
match rank {
Rank::Ace => 'A',
Rank::Two => '2',
Rank::Three => '3',
Rank::Four => '4',
Rank::Five => '5',
Rank::Six => '6',
Rank::Seven => '7',
Rank::Eight => '8',
Rank::Nine => '9',
Rank::Ten => 'T',
Rank::Jack => 'J',
Rank::Queen => 'Q',
Rank::King => 'K',
}
}
}
impl From<Suit> for char {
fn from(suit: Suit) -> Self {
match suit {
Suit::Hearts => '♥',
Suit::Diamonds => '♦',
Suit::Spades => '♠',
Suit::Clubs => '♣',
}
}
}
impl From<Color> for char {
fn from(c: Color) -> char {
match c {
Color::Red => 'R',
Color::Black => 'B',
}
}
}
impl fmt::Display for Rank {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
char::from(*self).fmt(f)
}
}
impl fmt::Display for Suit {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
char::from(*self).fmt(f)
}
}
impl fmt::LowerHex for Suit {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Hearts => 'H',
Self::Diamonds => 'D',
Self::Spades => 'S',
Self::Clubs => 'C',
}
.fmt(f)
}
}
impl fmt::Display for Color {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
char::from(*self).fmt(f)
}
}
impl fmt::Display for Card {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Regular { rank, suit } => write!(f, "{rank}{suit}"),
Self::Joker(color) => write!(f, "{}J", color),
}
}
}
impl fmt::UpperHex for Card {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Joker(color) => match color {
Color::Red => write!(f, "🂿"),
Color::Black => write!(f, "🃏"),
},
Self::Regular { rank, suit } => {
let suit: u32 = match suit {
Suit::Spades => 0x1F0A,
Suit::Hearts => 0x1F0B,
Suit::Diamonds => 0x1F0C,
Suit::Clubs => 0x1F0D,
};
let rank: u32 = match rank {
Rank::Queen => 0x0D,
Rank::King => 0x0E,
Rank::Ace => 0x01,
_ => *rank as u32,
};
let codepoint: u32 = (suit << 4) + rank;
write!(f, "{}", char::from_u32(codepoint).unwrap())
}
}
}
}
impl fmt::LowerHex for Card {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Regular { rank, suit } => write!(f, "{rank}{suit:x}"),
Self::Joker(color) => write!(f, "{}J", color),
}
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::test::FULL_DECK_CARDS;
#[rustfmt::skip]
pub const ASCII_REPRS: [&str; 52] = [
"AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "TH", "JH", "QH", "KH",
"AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "TD", "JD", "QD", "KD",
"AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "TS", "JS", "QS", "KS",
"AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "TC", "JC", "QC", "KC",
];
#[rustfmt::skip]
pub const MIXED_REPRS: [&str; 52] = [
"A♥", "2♥", "3♥", "4♥", "5♥", "6♥", "7♥", "8♥", "9♥", "T♥", "J♥", "Q♥", "K♥",
"A♦", "2♦", "3♦", "4♦", "5♦", "6♦", "7♦", "8♦", "9♦", "T♦", "J♦", "Q♦", "K♦",
"A♠", "2♠", "3♠", "4♠", "5♠", "6♠", "7♠", "8♠", "9♠", "T♠", "J♠", "Q♠", "K♠",
"A♣", "2♣", "3♣", "4♣", "5♣", "6♣", "7♣", "8♣", "9♣", "T♣", "J♣", "Q♣", "K♣",
];
#[rustfmt::skip]
pub const UNICODE_REPRS: &str = "\
\u{1F0B1}\u{1F0B2}\u{1F0B3}\u{1F0B4}\u{1F0B5}\u{1F0B6}\u{1F0B7}\u{1F0B8}\u{1F0B9}\
\u{1F0BA}\u{1F0BB}\u{1F0BD}\u{1F0BE}\
\u{1F0C1}\u{1F0C2}\u{1F0C3}\u{1F0C4}\u{1F0C5}\u{1F0C6}\u{1F0C7}\u{1F0C8}\u{1F0C9}\
\u{1F0CA}\u{1F0CB}\u{1F0CD}\u{1F0CE}\
\u{1F0A1}\u{1F0A2}\u{1F0A3}\u{1F0A4}\u{1F0A5}\u{1F0A6}\u{1F0A7}\u{1F0A8}\u{1F0A9}\
\u{1F0AA}\u{1F0AB}\u{1F0AD}\u{1F0AE}\
\u{1F0D1}\u{1F0D2}\u{1F0D3}\u{1F0D4}\u{1F0D5}\u{1F0D6}\u{1F0D7}\u{1F0D8}\u{1F0D9}\
\u{1F0DA}\u{1F0DB}\u{1F0DD}\u{1F0DE}";
#[test]
fn card_mixed() {
for (card, exp_repr) in FULL_DECK_CARDS.iter().zip(MIXED_REPRS.iter()) {
assert_eq!(
&format!("{}", card),
exp_repr,
"Unexpected format for card {}. expected {}",
card,
exp_repr
);
}
assert_eq!(format!("{}", Card::Joker(Color::Black)), "BJ");
assert_eq!(format!("{}", Card::Joker(Color::Red)), "RJ");
}
#[test]
fn card_unicode() {
for (card, exp_repr) in FULL_DECK_CARDS.iter().zip(UNICODE_REPRS.chars()) {
assert_eq!(
format!("{card:X}"),
exp_repr.to_string(),
"Unexpected format for card {}. Expected {}",
card,
exp_repr
);
}
}
#[test]
fn card_ascii() {
for (card, exp_repr) in FULL_DECK_CARDS.iter().zip(ASCII_REPRS) {
assert_eq!(
format!("{card:x}"),
exp_repr.to_string(),
"Unexpected format for card {}. Expected {}",
card,
exp_repr
);
}
}
#[test]
fn rank() {
assert_eq!("A", format!("{}", Rank::Ace));
assert_eq!("2", format!("{}", Rank::Two));
assert_eq!("3", format!("{}", Rank::Three));
assert_eq!("6", format!("{}", Rank::Six));
assert_eq!("9", format!("{}", Rank::Nine));
assert_eq!("T", format!("{}", Rank::Ten));
assert_eq!("J", format!("{}", Rank::Jack));
assert_eq!("Q", format!("{}", Rank::Queen));
assert_eq!("K", format!("{}", Rank::King));
}
#[test]
fn suit() {
assert_eq!("♠", format!("{}", Suit::Spades));
assert_eq!("♥", format!("{}", Suit::Hearts));
assert_eq!("♦", format!("{}", Suit::Diamonds));
assert_eq!("♣", format!("{}", Suit::Clubs));
}
#[test]
fn suit_ascii() {
assert_eq!("S", format!("{:x}", Suit::Spades));
assert_eq!("H", format!("{:x}", Suit::Hearts));
assert_eq!("D", format!("{:x}", Suit::Diamonds));
assert_eq!("C", format!("{:x}", Suit::Clubs));
}
}