1use std::fmt;
2use std::fmt::Display;
3
4use crate::{Card, Color, Rank, Suit};
5
6impl From<Rank> for char {
7 fn from(rank: Rank) -> Self {
9 match rank {
10 Rank::Ace => 'A',
11 Rank::Two => '2',
12 Rank::Three => '3',
13 Rank::Four => '4',
14 Rank::Five => '5',
15 Rank::Six => '6',
16 Rank::Seven => '7',
17 Rank::Eight => '8',
18 Rank::Nine => '9',
19 Rank::Ten => 'T',
20 Rank::Jack => 'J',
21 Rank::Queen => 'Q',
22 Rank::King => 'K',
23 }
24 }
25}
26
27impl From<Suit> for char {
28 fn from(suit: Suit) -> Self {
30 match suit {
31 Suit::Hearts => '♥',
32 Suit::Diamonds => '♦',
33 Suit::Spades => '♠',
34 Suit::Clubs => '♣',
35 }
36 }
37}
38
39impl From<Color> for char {
40 fn from(c: Color) -> char {
41 match c {
42 Color::Red => 'R',
43 Color::Black => 'B',
44 }
45 }
46}
47
48impl fmt::Display for Rank {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51 char::from(*self).fmt(f)
52 }
53}
54
55impl fmt::Display for Suit {
56 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58 char::from(*self).fmt(f)
59 }
60}
61
62impl fmt::LowerHex for Suit {
63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65 match self {
66 Self::Hearts => 'H',
67 Self::Diamonds => 'D',
68 Self::Spades => 'S',
69 Self::Clubs => 'C',
70 }
71 .fmt(f)
72 }
73}
74
75impl fmt::Display for Color {
76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 char::from(*self).fmt(f)
79 }
80}
81
82impl fmt::Display for Card {
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86 match self {
87 Self::Regular { rank, suit } => write!(f, "{rank}{suit}"),
88 Self::Joker(color) => write!(f, "{}J", color),
89 }
90 }
91}
92
93impl fmt::UpperHex for Card {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96 match self {
97 Self::Joker(color) => match color {
98 Color::Red => write!(f, "🂿"),
99 Color::Black => write!(f, "🃏"),
100 },
101 Self::Regular { rank, suit } => {
102 let suit: u32 = match suit {
103 Suit::Spades => 0x1F0A,
104 Suit::Hearts => 0x1F0B,
105 Suit::Diamonds => 0x1F0C,
106 Suit::Clubs => 0x1F0D,
107 };
108 let rank: u32 = match rank {
109 Rank::Queen => 0x0D,
111 Rank::King => 0x0E,
112 Rank::Ace => 0x01,
113 _ => *rank as u32,
114 };
115 let codepoint: u32 = (suit << 4) + rank;
116 write!(f, "{}", char::from_u32(codepoint).unwrap())
117 }
118 }
119 }
120}
121
122impl fmt::LowerHex for Card {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 match self {
126 Self::Regular { rank, suit } => write!(f, "{rank}{suit:x}"),
127 Self::Joker(color) => write!(f, "{}J", color),
128 }
129 }
130}
131
132#[cfg(test)]
133pub mod tests {
134 use super::*;
135 use crate::test::FULL_DECK_CARDS;
136
137 #[rustfmt::skip]
139 pub const ASCII_REPRS: [&str; 52] = [
140 "AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "TH", "JH", "QH", "KH",
141 "AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "TD", "JD", "QD", "KD",
142 "AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "TS", "JS", "QS", "KS",
143 "AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "TC", "JC", "QC", "KC",
144 ];
145 #[rustfmt::skip]
147 pub const MIXED_REPRS: [&str; 52] = [
148 "A♥", "2♥", "3♥", "4♥", "5♥", "6♥", "7♥", "8♥", "9♥", "T♥", "J♥", "Q♥", "K♥",
149 "A♦", "2♦", "3♦", "4♦", "5♦", "6♦", "7♦", "8♦", "9♦", "T♦", "J♦", "Q♦", "K♦",
150 "A♠", "2♠", "3♠", "4♠", "5♠", "6♠", "7♠", "8♠", "9♠", "T♠", "J♠", "Q♠", "K♠",
151 "A♣", "2♣", "3♣", "4♣", "5♣", "6♣", "7♣", "8♣", "9♣", "T♣", "J♣", "Q♣", "K♣",
152 ];
153 #[rustfmt::skip]
155 pub const UNICODE_REPRS: &str = "\
156 \u{1F0B1}\u{1F0B2}\u{1F0B3}\u{1F0B4}\u{1F0B5}\u{1F0B6}\u{1F0B7}\u{1F0B8}\u{1F0B9}\
157 \u{1F0BA}\u{1F0BB}\u{1F0BD}\u{1F0BE}\
158 \u{1F0C1}\u{1F0C2}\u{1F0C3}\u{1F0C4}\u{1F0C5}\u{1F0C6}\u{1F0C7}\u{1F0C8}\u{1F0C9}\
159 \u{1F0CA}\u{1F0CB}\u{1F0CD}\u{1F0CE}\
160 \u{1F0A1}\u{1F0A2}\u{1F0A3}\u{1F0A4}\u{1F0A5}\u{1F0A6}\u{1F0A7}\u{1F0A8}\u{1F0A9}\
161 \u{1F0AA}\u{1F0AB}\u{1F0AD}\u{1F0AE}\
162 \u{1F0D1}\u{1F0D2}\u{1F0D3}\u{1F0D4}\u{1F0D5}\u{1F0D6}\u{1F0D7}\u{1F0D8}\u{1F0D9}\
163 \u{1F0DA}\u{1F0DB}\u{1F0DD}\u{1F0DE}";
164
165 #[test]
166 fn card_mixed() {
167 for (card, exp_repr) in FULL_DECK_CARDS.iter().zip(MIXED_REPRS.iter()) {
168 assert_eq!(
169 &format!("{}", card),
170 exp_repr,
171 "Unexpected format for card {}. expected {}",
172 card,
173 exp_repr
174 );
175 }
176 assert_eq!(format!("{}", Card::Joker(Color::Black)), "BJ");
177 assert_eq!(format!("{}", Card::Joker(Color::Red)), "RJ");
178 }
179 #[test]
180 fn card_unicode() {
181 for (card, exp_repr) in FULL_DECK_CARDS.iter().zip(UNICODE_REPRS.chars()) {
182 assert_eq!(
183 format!("{card:X}"),
184 exp_repr.to_string(),
185 "Unexpected format for card {}. Expected {}",
186 card,
187 exp_repr
188 );
189 }
190 }
191 #[test]
192 fn card_ascii() {
193 for (card, exp_repr) in FULL_DECK_CARDS.iter().zip(ASCII_REPRS) {
194 assert_eq!(
195 format!("{card:x}"),
196 exp_repr.to_string(),
197 "Unexpected format for card {}. Expected {}",
198 card,
199 exp_repr
200 );
201 }
202 }
203
204 #[test]
205 fn rank() {
206 assert_eq!("A", format!("{}", Rank::Ace));
207 assert_eq!("2", format!("{}", Rank::Two));
208 assert_eq!("3", format!("{}", Rank::Three));
209 assert_eq!("6", format!("{}", Rank::Six));
210 assert_eq!("9", format!("{}", Rank::Nine));
211 assert_eq!("T", format!("{}", Rank::Ten));
212 assert_eq!("J", format!("{}", Rank::Jack));
213 assert_eq!("Q", format!("{}", Rank::Queen));
214 assert_eq!("K", format!("{}", Rank::King));
215 }
216 #[test]
217 fn suit() {
218 assert_eq!("♠", format!("{}", Suit::Spades));
219 assert_eq!("♥", format!("{}", Suit::Hearts));
220 assert_eq!("♦", format!("{}", Suit::Diamonds));
221 assert_eq!("♣", format!("{}", Suit::Clubs));
222 }
223 #[test]
224 fn suit_ascii() {
225 assert_eq!("S", format!("{:x}", Suit::Spades));
226 assert_eq!("H", format!("{:x}", Suit::Hearts));
227 assert_eq!("D", format!("{:x}", Suit::Diamonds));
228 assert_eq!("C", format!("{:x}", Suit::Clubs));
229 }
230}