fudd/types/slots/
hole_cards.rs

1use crate::types::arrays::two_card::TwoCard;
2use crate::types::card_slot::CardSlot;
3use crate::types::playing_card::PlayingCard;
4use crate::types::playing_cards::PlayingCards;
5use crate::types::U32Card;
6use ckc_rs::PokerCard;
7use log::warn;
8use serde::{Deserialize, Serialize};
9use std::cell::Cell;
10use std::fmt;
11
12#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
13pub struct HoleCards(Cell<PlayingCard>, Cell<PlayingCard>);
14
15impl HoleCards {
16    #[must_use]
17    pub fn new(first: PlayingCard, second: PlayingCard) -> HoleCards {
18        HoleCards(Cell::new(first), Cell::new(second))
19    }
20
21    /// # Errors
22    ///
23    /// Will throw a `HandError::InvalidCard` if an invalid index is passed in.
24    ///
25    /// Will throw a `HandError::InvalidIndex` if the number of cards passed in
26    /// doesn't equal 2. (There must be two cards for each `Player`.)
27    #[must_use]
28    pub fn from_index(index: &'static str) -> HoleCards {
29        HoleCards::from(index)
30    }
31
32    pub fn get_first_card(&self) -> PlayingCard {
33        self.0.get()
34    }
35
36    pub fn get_second_card(&self) -> PlayingCard {
37        self.1.get()
38    }
39
40    pub fn take_first_card(&self, card: PlayingCard) {
41        self.0.set(card);
42    }
43
44    pub fn take_second_card(&self, card: PlayingCard) {
45        self.1.set(card);
46    }
47
48    #[must_use]
49    pub fn simple_index(&self) -> String {
50        format!(
51            "{} {}",
52            self.get_first_card().simple_index(),
53            self.get_second_card().simple_index()
54        )
55    }
56
57    #[must_use]
58    pub fn simple_index_short(&self) -> String {
59        format!(
60            "{}{}",
61            self.get_first_card().simple_index(),
62            self.get_second_card().simple_index()
63        )
64    }
65
66    pub fn to_array(&self) -> [U32Card; 2] {
67        [
68            self.get_first_card().as_u32(),
69            self.get_second_card().as_u32(),
70        ]
71    }
72}
73
74impl CardSlot for HoleCards {
75    fn take(&self, card: PlayingCard) -> bool {
76        if self.get_first_card().is_blank() {
77            self.take_first_card(card);
78            return true;
79        }
80        if self.get_second_card().is_blank() {
81            self.take_second_card(card);
82            return true;
83        }
84        false
85    }
86
87    fn fold(&self) -> PlayingCards {
88        let folded = self.to_playing_cards();
89        self.0.set(PlayingCard::default());
90        self.1.set(PlayingCard::default());
91        folded
92    }
93
94    fn is_dealt(&self) -> bool {
95        !self.get_first_card().is_blank() && !self.get_second_card().is_blank()
96    }
97
98    fn to_playing_cards(&self) -> PlayingCards {
99        let mut playing_cards = PlayingCards::default();
100        playing_cards.insert(self.0.get());
101        playing_cards.insert(self.1.get());
102        playing_cards
103    }
104}
105
106impl Default for HoleCards {
107    fn default() -> HoleCards {
108        HoleCards::new(PlayingCard::default(), PlayingCard::default())
109    }
110}
111
112impl fmt::Display for HoleCards {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        write!(f, "{} {}", self.get_first_card(), self.get_second_card())
115    }
116}
117
118impl From<&'static str> for HoleCards {
119    fn from(value: &'static str) -> HoleCards {
120        let hole_cards = HoleCards::default();
121        if !hole_cards.take_from_index(value) {
122            warn!("Invalid index: {}", value);
123        }
124        hole_cards
125    }
126}
127
128impl From<TwoCard> for HoleCards {
129    fn from(two_cards: TwoCard) -> Self {
130        HoleCards::new(
131            PlayingCard::from(two_cards.first()),
132            PlayingCard::from(two_cards.second()),
133        )
134    }
135}
136
137#[cfg(test)]
138#[allow(non_snake_case)]
139mod holdem_hole_cards_tests {
140    use super::*;
141    use ckc_rs::CardNumber;
142
143    #[test]
144    fn new() {
145        let first = PlayingCard::from("A♦");
146        let second = PlayingCard::from("K♦");
147
148        let hole = HoleCards::new(first, second);
149
150        assert_eq!("A♦ K♦", format!("{}", hole));
151        assert_eq!("A♦ K♦", format!("{}", hole.to_playing_cards()));
152        assert_eq!(2, hole.dealt().len());
153        assert!(hole.is_dealt());
154    }
155
156    #[test]
157    fn from_index() {
158        let slot = HoleCards::from("AS AD");
159
160        assert_eq!("A♠ A♦", format!("{}", slot));
161        assert!(slot.is_dealt());
162    }
163
164    #[test]
165    fn from_index__invalid() {
166        let slot = HoleCards::from("FF");
167
168        assert_eq!("__ __", format!("{}", slot));
169        assert!(!slot.is_dealt());
170    }
171
172    #[test]
173    fn is_dealt() {
174        let hole = HoleCards::default();
175
176        assert!(!hole.is_dealt());
177    }
178
179    #[test]
180    fn is_dealt__first_card_dealt__false() {
181        let hole = HoleCards::default();
182        hole.take_from_index("AS");
183
184        assert!(!hole.is_dealt());
185    }
186
187    #[test]
188    fn is_dealt__second_card_dealt__false() {
189        let hole = HoleCards::default();
190        hole.take_second_card(PlayingCard::from("A♦"));
191
192        assert!(!hole.is_dealt());
193    }
194
195    #[test]
196    fn is_dealt__both_cards_dealt__true() {
197        let hole = HoleCards::default();
198        hole.take_from_index("AS AD");
199
200        assert!(hole.is_dealt());
201    }
202
203    #[test]
204    fn to_array() {
205        let slot = HoleCards::from("AS AD");
206
207        assert_eq!(
208            [CardNumber::ACE_SPADES, CardNumber::ACE_DIAMONDS],
209            slot.to_array()
210        );
211    }
212
213    #[test]
214    fn to_array__default() {
215        assert_eq!(
216            [CardNumber::BLANK, CardNumber::BLANK],
217            HoleCards::default().to_array()
218        );
219    }
220
221    #[test]
222    fn default() {
223        let hole = HoleCards::default();
224
225        assert_eq!("__ __", format!("{}", hole));
226        assert_eq!("", format!("{}", hole.to_playing_cards()));
227        assert_eq!(0, hole.dealt().len());
228        assert!(!hole.is_dealt());
229    }
230
231    #[test]
232    fn display() {
233        let hole = HoleCards::default();
234        hole.take_from_index("AS");
235        hole.take_from_index("AD");
236
237        assert_eq!("A♠ A♦", format!("{}", hole));
238    }
239
240    #[test]
241    fn display__default() {
242        let hole = HoleCards::default();
243
244        assert_eq!("__ __", format!("{}", hole));
245    }
246
247    #[test]
248    fn display__one_card() {
249        let hole = HoleCards::default();
250        hole.take_from_index("AS");
251
252        assert_eq!("A♠ __", format!("{}", hole));
253    }
254
255    #[test]
256    fn display__only_second_card() {
257        let hole = HoleCards::default();
258        hole.take_second_card(PlayingCard::from("A♦"));
259
260        assert_eq!("__ A♦", format!("{}", hole));
261    }
262
263    #[test]
264    fn to_string() {
265        let cards = HoleCards::from("AS AD");
266
267        assert_eq!("A♠ A♦", cards.to_string());
268    }
269
270    #[test]
271    fn from__two_cards() {
272        let two_cards = TwoCard::try_from("AD AS").unwrap();
273        let expected = HoleCards::from("AS AD");
274
275        let actual = HoleCards::from(two_cards);
276
277        assert_eq!(actual, expected);
278    }
279}