deuces_rs/
builder.rs

1use rand::Rng;
2
3use crate::{
4    card::Card,
5    evaluator::Evaluator,
6    model::{Board, Deal, Hand, PlayerHand},
7};
8
9static CARDS: [&str; 52] = [
10    "Ac", "Ad", "Ah", "As", "2c", "2d", "2h", "2s", "3c", "3d", "3h", "3s", "4c", "4d", "4h", "4s",
11    "5c", "5d", "5h", "5s", "6c", "6d", "6h", "6s", "7c", "7d", "7h", "7s", "8c", "8d", "8h", "8s",
12    "9c", "9d", "9h", "9s", "Tc", "Td", "Th", "Ts", "Jc", "Jd", "Jh", "Js", "Qc", "Qd", "Qh", "Qs",
13    "Kc", "Kd", "Kh", "Ks",
14];
15
16// Define the interface
17pub trait CardShuffler {
18    fn shuffle(&self) -> Vec<&'static str>;
19}
20
21// Implement the interface for a struct
22pub struct RandomCardShuffler;
23
24impl CardShuffler for RandomCardShuffler {
25    fn shuffle(&self) -> Vec<&'static str> {
26        let mut rng = rand::thread_rng();
27        let mut sample = CARDS.clone();
28        for i in 0..CARDS.len() {
29            let rand: usize = rng.gen_range(0..=i);
30            sample.swap(i, rand);
31        }
32        sample.to_vec()
33    }
34}
35
36struct IndexGenerator {
37    index: usize,
38}
39
40impl IndexGenerator {
41    fn new() -> IndexGenerator {
42        IndexGenerator { index: 0 }
43    }
44}
45
46impl Iterator for IndexGenerator {
47    type Item = usize;
48
49    fn next(&mut self) -> Option<Self::Item> {
50        let current_index = self.index;
51        self.index += 1;
52        Some(current_index)
53    }
54}
55
56pub trait Dealer {
57    fn deal(&self, player_count: usize) -> Deal;
58}
59
60pub struct GameDealer<S: CardShuffler> {
61    shuffler: S,
62}
63
64impl<S: CardShuffler> GameDealer<S> {
65    #[allow(dead_code)]
66    pub fn new(shuffler: S) -> Self {
67        GameDealer { shuffler }
68    }
69}
70
71impl<S: CardShuffler> Dealer for GameDealer<S> {
72    fn deal(&self, player_count: usize) -> Deal {
73        let evaluator = Evaluator::new();
74        let cards = self.shuffler.shuffle();
75        let mut hands: Vec<PlayerHand> = Vec::new();
76        let mut nextn = IndexGenerator::new();
77        let players: Vec<_> = (0..player_count).collect();
78        let pl = players.len();
79        for _ in players {
80            let i = nextn.next().unwrap();
81            let player_hand: Vec<String> = vec![cards[i].to_string(), cards[i + pl].to_string()];
82            let scores: Vec<u32> = player_hand.iter().map(|card| Card::new(card).0).collect();
83            hands.push(PlayerHand {
84                hand: player_hand,
85                score: scores,
86            });
87        }
88        let flop = vec![
89            cards[nextn.next().unwrap() + pl].to_string(),
90            cards[nextn.next().unwrap() + pl].to_string(),
91            cards[nextn.next().unwrap() + pl].to_string(),
92        ];
93        let flop_score: Vec<u32> = flop.iter().map(|card| Card::new(card.as_str()).0).collect();
94        let turn = cards[nextn.next().unwrap() + pl];
95        let turn_score = Card::new(turn).0;
96        let river = cards[nextn.next().unwrap() + pl];
97        let river_score = Card::new(river).0;
98        let mut player_hands: Vec<Hand> = Vec::new();
99        for hand in hands {
100            let mut combined_score = flop_score.clone();
101            combined_score.push(turn_score);
102            combined_score.push(river_score);
103            let hand_score = evaluator.evaluate(hand.score, combined_score);
104            let score = evaluator.get_rank_class(hand_score);
105            let percentage = 1.0 - evaluator.get_five_card_rank_percentage(hand_score);
106            let description = evaluator.class_to_string(score.unwrap());
107            player_hands.push(Hand {
108                cards: hand.hand.clone(),
109                score: percentage,
110                description,
111            });
112        }
113        let board = Board {
114            flop: flop.clone(),
115            turn: turn.to_string(),
116            river: river.to_string(),
117        };
118        Deal {
119            board,
120            hands: player_hands,
121        }
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    struct MockCardShuffler;
130
131    impl CardShuffler for MockCardShuffler {
132        fn shuffle(&self) -> Vec<&'static str> {
133            CARDS.to_vec()
134        }
135    }
136
137    #[test]
138    fn test_deal() {
139        let expected_deal = Deal {
140            board: Board {
141                flop: vec!["2h".to_string(), "2s".to_string(), "3c".to_string()],
142                turn: "3d".to_string(),
143                river: "3h".to_string(),
144            },
145            hands: vec![
146                Hand {
147                    cards: vec!["Ac".to_string(), "As".to_string()],
148                    score: 0.9599303135888502,
149                    description: "Full House".to_string(),
150                },
151                Hand {
152                    cards: vec!["Ad".to_string(), "2c".to_string()],
153                    score: 0.9584561779683731,
154                    description: "Full House".to_string(),
155                },
156                Hand {
157                    cards: vec!["Ah".to_string(), "2d".to_string()],
158                    score: 0.9584561779683731,
159                    description: "Full House".to_string(),
160                },
161            ],
162        };
163        let mock_shuffler = MockCardShuffler;
164        let dealer = GameDealer::new(mock_shuffler);
165        let deal = dealer.deal(3);
166        assert!(deal == expected_deal);
167    }
168}