summaryrefslogtreecommitdiffstats
path: root/tests/blackjack.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-29 18:22:40 +0100
committersalmonik <salmonik@tuta.io>2026-10-29 18:22:40 +0100
commitb5a52fc0312afdf5d5fbe53275dc88d6d881c2ff (patch)
treed12e3c7f6c23ae1698199d16ee763551edfd8c12 /tests/blackjack.rs
parentv2.1.2: ignore ANSI when measuring board height (diff)
downloadzagan-bet-b5a52fc0312afdf5d5fbe53275dc88d6d881c2ff.tar.gz
zagan-bet-b5a52fc0312afdf5d5fbe53275dc88d6d881c2ff.zip
v2.2.0: add blackjack with reserved bets and hit/stand/double
Diffstat (limited to 'tests/blackjack.rs')
-rw-r--r--tests/blackjack.rs139
1 files changed, 139 insertions, 0 deletions
diff --git a/tests/blackjack.rs b/tests/blackjack.rs
new file mode 100644
index 0000000..79721d3
--- /dev/null
+++ b/tests/blackjack.rs
@@ -0,0 +1,139 @@
1use zagan_bet::blackjack::{
2 card_label, card_value, fresh_shoe, hand_total, is_blackjack, BlackjackState,
3};
4use zagan_bet::server::games::blackjack::BlackjackGame;
5
6fn hand(deck: &[&str], bet: u64) -> zagan_bet::server::games::blackjack::BlackjackHand {
7 let deck = deck.iter().map(|card| card.to_string()).collect();
8 BlackjackGame::with_deck(deck).deal(bet)
9}
10
11#[test]
12fn card_values_and_soft_totals_are_correct() {
13 assert_eq!(card_value("AS"), 11);
14 assert_eq!(card_value("10H"), 10);
15 assert_eq!(card_value("KD"), 10);
16 assert_eq!(card_label("AS"), "A♠");
17 assert_eq!(card_label("10H"), "10♥");
18
19 let cards = |values: &[&str]| values.iter().map(|card| card.to_string()).collect::<Vec<_>>();
20 assert_eq!(hand_total(&cards(&["AS", "10H"])), 21);
21 assert_eq!(hand_total(&cards(&["AS", "9H"])), 20);
22 assert_eq!(hand_total(&cards(&["AS", "AS", "9H"])), 21);
23 assert!(is_blackjack(&cards(&["AS", "KH"])));
24 assert!(!is_blackjack(&cards(&["AS", "9H"])));
25}
26
27#[test]
28fn a_six_deck_shoe_has_312_cards() {
29 let shoe = fresh_shoe();
30 assert_eq!(shoe.len(), 312);
31 assert_eq!(shoe.iter().filter(|card| card.as_str() == "AS").count(), 6);
32}
33
34#[test]
35fn a_natural_blackjack_settles_immediately() {
36 let hand = hand(&["AS", "9D", "KH", "8C"], 10);
37
38 assert!(hand.is_done());
39 assert_eq!(hand.result, "blackjack");
40 assert_eq!(hand.winnings, 25); // 10 + 15
41 assert_eq!(hand.player_total(), 21);
42}
43
44#[test]
45fn a_player_hand_can_hit_to_21() {
46 let mut hand = hand(&["10S", "9D", "6H", "8C", "5D"], 10);
47 assert_eq!(hand.player_total(), 16);
48 assert_eq!(hand.dealer_total(), 17);
49
50 hand.hit().unwrap();
51
52 assert!(hand.is_done());
53 assert_eq!(hand.player_total(), 21);
54 assert_eq!(hand.result, "win");
55 assert_eq!(hand.winnings, 20);
56}
57
58#[test]
59fn hitting_over_21_busts() {
60 let mut hand = hand(&["10S", "9D", "6H", "8C", "KD"], 10);
61 hand.hit().unwrap();
62
63 assert!(hand.is_done());
64 assert_eq!(hand.result, "bust");
65 assert_eq!(hand.winnings, 0);
66}
67
68#[test]
69fn doubling_adds_the_base_bet_and_draws_one_card() {
70 let mut hand = hand(&["5S", "9D", "5H", "8C", "10D"], 10);
71 assert_eq!(hand.player_total(), 10);
72
73 hand.double().unwrap();
74
75 assert_eq!(hand.player.len(), 3);
76 assert_eq!(hand.bet, 20);
77 assert_eq!(hand.player_total(), 20);
78 assert_eq!(hand.result, "win");
79 assert_eq!(hand.winnings, 40);
80}
81
82#[test]
83fn the_dealer_busts_and_the_player_wins() {
84 let mut hand = hand(&["10S", "7H", "8H", "9C", "10H"], 10);
85 assert_eq!(hand.player_total(), 18);
86 assert_eq!(hand.dealer_total(), 16);
87
88 hand.stand();
89
90 assert_eq!(hand.dealer_total(), 26);
91 assert_eq!(hand.result, "win");
92 assert_eq!(hand.winnings, 20);
93}
94
95#[test]
96fn the_dealer_stands_on_soft_17() {
97 let mut hand = hand(&["10S", "AD", "8H", "6C"], 10);
98 assert_eq!(hand.dealer_total(), 17);
99
100 hand.stand();
101
102 assert_eq!(hand.dealer.len(), 2, "dealer must stand on soft 17");
103 assert_eq!(hand.result, "win");
104 assert_eq!(hand.winnings, 20);
105}
106
107#[test]
108fn equal_totals_push() {
109 let mut hand = hand(&["10S", "10D", "8H", "8C"], 10);
110 hand.stand();
111
112 assert_eq!(hand.result, "push");
113 assert_eq!(hand.winnings, 10);
114}
115
116#[test]
117fn dealer_blackjack_wins_unless_player_also_has_it() {
118 let dealer_blackjack = hand(&["10S", "AS", "8H", "KD"], 10);
119 assert_eq!(dealer_blackjack.result, "lose");
120 assert_eq!(dealer_blackjack.winnings, 0);
121
122 let both = hand(&["AS", "AD", "KH", "KC"], 10);
123 assert_eq!(both.result, "push");
124 assert_eq!(both.winnings, 10);
125}
126
127#[test]
128fn the_player_state_hides_the_hole_card() {
129 let hand = hand(&["10S", "9D", "6H", "8C"], 10);
130 let state: BlackjackState = hand.state("session-1", 990);
131
132 assert_eq!(state.phase, "player");
133 assert_eq!(state.dealer, vec!["9D".to_string(), "?".to_string()]);
134 assert_eq!(state.dealer_total, 9);
135 assert_eq!(state.player_total, 16);
136 assert_eq!(state.actions, vec!["hit", "stand", "double"]);
137 assert_eq!(state.bet, 10);
138 assert_eq!(state.balance, 990);
139}