BlackjackHandHelperProj   A
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 191
Duplicated Lines 0 %

Test Coverage

Coverage 89.04%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 66
c 1
b 0
f 1
dl 0
loc 191
ccs 65
cts 73
cp 0.8904
rs 9.52
wmc 36

8 Methods

Rating   Name   Duplication   Size   Complexity  
A hasBlackjack() 0 3 2
A settleBets() 0 11 2
A shouldComputerHit() 0 13 5
B settleSingleHandBet() 0 21 7
A getHandValue() 0 19 5
A handHasAce() 0 8 3
B getBustProbability() 0 34 9
A getLowHandValue() 0 12 3
1
<?php
2
3
namespace App\GameProj;
4
5
use App\Card\DeckProj;
6
use App\Card\Card;
7
8
/**
9
 * Helper class for more advanced Blackjack hand operations.
10
 */
11
class BlackjackHandHelperProj
12
{
13
    /**
14
     * Calculate the total value of a hand.
15
     *
16
     * @param Card[] $hand The hand to calculate
17
     * @return int The value of the hand
18
     */
19 8
    public function getHandValue(array $hand): int
20
    {
21 8
        $value = 0;
22 8
        $aceCount = 0;
23
24 8
        foreach ($hand as $card) {
25 8
            $cardValue = $card->getBlackjackValue();
26 8
            if ($cardValue === 11) {
27 3
                $aceCount++;
28
            }
29 8
            $value += $cardValue;
30
        }
31
32 8
        while ($value > 21 && $aceCount > 0) {
33 1
            $value -= 10;
34 1
            $aceCount--;
35
        }
36
37 8
        return $value;
38
    }
39
40
    /**
41
     * Get the probability of busting for a specific hand.
42
     *
43
     * @param array $hand The hand to check
44
     * @param DeckProj $deck The deck to calculate probabilities from
45
     * @return float The probability of busting
46
     */
47 2
    public function getBustProbability(array $hand, DeckProj $deck): float
48
    {
49 2
        $handValue = $this->getHandValue($hand);
50
51 2
        $hasAce = $this->handHasAce($hand);
52 2
        $lowHandValue = $this->getLowHandValue($hand);
53
54 2
        if ($hasAce && $handValue != $lowHandValue) {
55 1
            $handValue = $lowHandValue;
56
        }
57
58 2
        $safeValue = 21 - $handValue;
59
60 2
        if ($safeValue <= 0) {
61
            return 1.0;
62
        }
63
64 2
        if ($hasAce && $handValue <= 11) {
65 1
            return 0.0;
66
        }
67
68 1
        $totalCards = $deck->remainingCardsCount();
69 1
        $safeCards = 0;
70
71 1
        foreach ($deck->getCards() as $card) {
72 1
            $cardValue = $card->getBlackjackValue();
73 1
            $isAce = $card->getValue() === 'Ace';
74
75 1
            if ($cardValue <= $safeValue || $isAce) {
76 1
                $safeCards++;
77
            }
78
        }
79
80 1
        return 1 - ($safeCards / $totalCards);
81
    }
82
83
    /**
84
     * Check if a hand has blackjack.
85
     *
86
     * @param array $hand The hand to check
87
     * @return bool True if the hand has blackjack
88
     */
89 2
    public function hasBlackjack(array $hand): bool
90
    {
91 2
        return count($hand) == 2 && $this->getHandValue($hand) == 21;
92
    }
93
94
    /**
95
     * Check if a hand contains an Ace.
96
     *
97
     * @param Card[] $hand The hand to check
98
     * @return bool True if the hand contains an Ace
99
     */
100 3
    private function handHasAce(array $hand): bool
101
    {
102 3
        foreach ($hand as $card) {
103 3
            if ($card->getValue() === 'Ace') {
104 2
                return true;
105
            }
106
        }
107 1
        return false;
108
    }
109
110
    /**
111
     * Calculate the low value of a hand (counting Aces as 1).
112
     *
113
     * @param Card[] $hand The hand to calculate
114
     * @return int The low value of the hand
115
     */
116 2
    private function getLowHandValue(array $hand): int
117
    {
118 2
        $lowValue = 0;
119 2
        foreach ($hand as $card) {
120 2
            if ($card->getValue() === 'Ace') {
121 1
                $lowValue += 1;
122 1
                continue;
123
            }
124
125 2
            $lowValue += $card->getBlackjackValue();
126
        }
127 2
        return $lowValue;
128
    }
129
130
    /**
131
     * Determine if the computer should hit based on its strategy.
132
     *
133
     * @param string $computerStrategy The strategy used by the computer player
134
     * @param int $handValue The current value of the hand
135
     * @param array $hand The current hand
136
     * @return bool True if the computer should hit
137
     */
138 1
    public function shouldComputerHit(string $computerStrategy, int $handValue, array $hand): bool
139
    {
140 1
        if ($computerStrategy === 'smart') {
141 1
            if ($handValue < 17) {
142 1
                return true;
143
            }
144 1
            if ($handValue < 18 && $this->handHasAce($hand)) {
145 1
                return true;
146
            }
147
            return false;
148
        }
149
150
        return $handValue < 17;
151
    }
152
153
    /**
154
     * Settle all bets.
155
     *
156
     * @param array $hands All player hands
157
     * @param array $dealerHand The dealer hand
158
     * @return float The total adjustment to the player bank
159
     */
160 1
    public function settleBets(array $hands, array $dealerHand): float
161
    {
162 1
        $dealerBlackjack = $this->hasBlackjack($dealerHand);
163 1
        $dealerValue = $this->getHandValue($dealerHand);
164 1
        $bankAdjustment = 0;
165
166 1
        foreach ($hands as $hand) {
167 1
            $bankAdjustment += $this->settleSingleHandBet($hand, $dealerBlackjack, $dealerValue);
168
        }
169
170 1
        return $bankAdjustment;
171
    }
172
173
    /**
174
     * Settle the bet for a single hand.
175
     *
176
     * @param array $hand The hand to settle
177
     * @param bool $dealerBlackjack Whether the dealer has blackjack
178
     * @param int $dealerValue The value of the dealer hand
179
     * @return float The adjustment to the player bank for this hand
180
     */
181 1
    private function settleSingleHandBet(array $hand, bool $dealerBlackjack, int $dealerValue): float
182
    {
183 1
        $handValue = $this->getHandValue($hand['hand']);
184 1
        $playerBlackjack = $hand['status'] === 'blackjack';
185
186 1
        if ($playerBlackjack) {
187
            if ($dealerBlackjack) {
188
                return $hand['bet'];
189
            }
190
            return $hand['bet'] * 2.5;
191
        }
192
193 1
        if ($handValue == $dealerValue) {
194
            return $hand['bet'];
195
        }
196
197 1
        if ($handValue <= 21 && ($handValue > $dealerValue || $dealerValue > 21)) {
198
            return $hand['bet'] * 2;
199
        }
200
201 1
        return 0;
202
    }
203
}
204