diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-29 18:22:40 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-29 18:22:40 +0100 |
| commit | b5a52fc0312afdf5d5fbe53275dc88d6d881c2ff (patch) | |
| tree | d12e3c7f6c23ae1698199d16ee763551edfd8c12 /tests/blackjack.rs | |
| parent | v2.1.2: ignore ANSI when measuring board height (diff) | |
| download | zagan-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.rs | 139 |
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 @@ | |||
| 1 | use zagan_bet::blackjack::{ | ||
| 2 | card_label, card_value, fresh_shoe, hand_total, is_blackjack, BlackjackState, | ||
| 3 | }; | ||
| 4 | use zagan_bet::server::games::blackjack::BlackjackGame; | ||
| 5 | |||
| 6 | fn 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] | ||
| 12 | fn 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] | ||
| 28 | fn 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] | ||
| 35 | fn 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] | ||
| 45 | fn 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] | ||
| 59 | fn 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] | ||
| 69 | fn 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] | ||
| 83 | fn 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] | ||
| 96 | fn 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] | ||
| 108 | fn 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] | ||
| 117 | fn 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] | ||
| 128 | fn 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 | } | ||
