summaryrefslogtreecommitdiffstats
path: root/tests/blackjack.rs
blob: 36ed7cf159270da3bd033751d01f5f6efe37bf42 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use zagan_bet::blackjack::{
    card_label, card_value, fresh_shoe, hand_total, is_blackjack, BlackjackState,
};
use zagan_bet::server::games::blackjack::BlackjackGame;

fn hand(deck: &[&str], bet: u64) -> zagan_bet::server::games::blackjack::BlackjackHand {
    let deck = deck.iter().map(|card| card.to_string()).collect();
    BlackjackGame::with_deck(deck).deal(bet)
}

#[test]
fn card_values_and_soft_totals_are_correct() {
    assert_eq!(card_value("AS"), 11);
    assert_eq!(card_value("10H"), 10);
    assert_eq!(card_value("KD"), 10);
    assert_eq!(card_label("AS"), "A♠");
    assert_eq!(card_label("10H"), "10♥");

    let cards = |values: &[&str]| {
        values
            .iter()
            .map(|card| card.to_string())
            .collect::<Vec<_>>()
    };
    assert_eq!(hand_total(&cards(&["AS", "10H"])), 21);
    assert_eq!(hand_total(&cards(&["AS", "9H"])), 20);
    assert_eq!(hand_total(&cards(&["AS", "AS", "9H"])), 21);
    assert!(is_blackjack(&cards(&["AS", "KH"])));
    assert!(!is_blackjack(&cards(&["AS", "9H"])));
}

#[test]
fn a_six_deck_shoe_has_312_cards() {
    let shoe = fresh_shoe();
    assert_eq!(shoe.len(), 312);
    assert_eq!(shoe.iter().filter(|card| card.as_str() == "AS").count(), 6);
}

#[test]
fn a_natural_blackjack_settles_immediately() {
    let hand = hand(&["AS", "9D", "KH", "8C"], 10);

    assert!(hand.is_done());
    assert_eq!(hand.result, "blackjack");
    assert_eq!(hand.winnings, 25); // 10 + 15
    assert_eq!(hand.player_total(), 21);
}

#[test]
fn a_player_hand_can_hit_to_21() {
    let mut hand = hand(&["10S", "9D", "6H", "8C", "5D"], 10);
    assert_eq!(hand.player_total(), 16);
    assert_eq!(hand.dealer_total(), 17);

    hand.hit().unwrap();

    assert!(hand.is_done());
    assert_eq!(hand.player_total(), 21);
    assert_eq!(hand.result, "win");
    assert_eq!(hand.winnings, 20);
}

#[test]
fn hitting_over_21_busts() {
    let mut hand = hand(&["10S", "9D", "6H", "8C", "KD"], 10);
    hand.hit().unwrap();

    assert!(hand.is_done());
    assert_eq!(hand.result, "bust");
    assert_eq!(hand.winnings, 0);
}

#[test]
fn doubling_adds_the_base_bet_and_draws_one_card() {
    let mut hand = hand(&["5S", "9D", "5H", "8C", "10D"], 10);
    assert_eq!(hand.player_total(), 10);

    hand.double().unwrap();

    assert_eq!(hand.player.len(), 3);
    assert_eq!(hand.bet, 20);
    assert_eq!(hand.player_total(), 20);
    assert_eq!(hand.result, "win");
    assert_eq!(hand.winnings, 40);
}

#[test]
fn forfeiting_loses_the_bet() {
    let mut hand = hand(&["10S", "9D", "6H", "8C"], 10);
    hand.forfeit();

    assert!(hand.is_done());
    assert_eq!(hand.result, "forfeit");
    assert_eq!(hand.winnings, 0);
    assert_eq!(hand.bet, 10);
}

#[test]
fn the_dealer_busts_and_the_player_wins() {
    let mut hand = hand(&["10S", "7H", "8H", "9C", "10H"], 10);
    assert_eq!(hand.player_total(), 18);
    assert_eq!(hand.dealer_total(), 16);

    hand.stand();

    assert_eq!(hand.dealer_total(), 26);
    assert_eq!(hand.result, "win");
    assert_eq!(hand.winnings, 20);
}

#[test]
fn the_dealer_stands_on_soft_17() {
    let mut hand = hand(&["10S", "AD", "8H", "6C"], 10);
    assert_eq!(hand.dealer_total(), 17);

    hand.stand();

    assert_eq!(hand.dealer.len(), 2, "dealer must stand on soft 17");
    assert_eq!(hand.result, "win");
    assert_eq!(hand.winnings, 20);
}

#[test]
fn equal_totals_push() {
    let mut hand = hand(&["10S", "10D", "8H", "8C"], 10);
    hand.stand();

    assert_eq!(hand.result, "push");
    assert_eq!(hand.winnings, 10);
}

#[test]
fn dealer_blackjack_wins_unless_player_also_has_it() {
    let dealer_blackjack = hand(&["10S", "AS", "8H", "KD"], 10);
    assert_eq!(dealer_blackjack.result, "lose");
    assert_eq!(dealer_blackjack.winnings, 0);

    let both = hand(&["AS", "AD", "KH", "KC"], 10);
    assert_eq!(both.result, "push");
    assert_eq!(both.winnings, 10);
}

#[test]
fn the_player_state_hides_the_hole_card() {
    let hand = hand(&["10S", "9D", "6H", "8C"], 10);
    let state: BlackjackState = hand.state("session-1", 990);

    assert_eq!(state.phase, "player");
    assert_eq!(state.dealer, vec!["9D".to_string(), "?".to_string()]);
    assert_eq!(state.dealer_total, 9);
    assert_eq!(state.player_total, 16);
    assert_eq!(state.actions, vec!["hit", "stand", "double"]);
    assert_eq!(state.bet, 10);
    assert_eq!(state.balance, 990);
}