Passed
Push — main ( 8bc290...60b955 )
by Peter
04:33
created

BlackjackHandHelperProj   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 185
Duplicated Lines 0 %

Test Coverage

Coverage 91.3%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 62
c 1
b 0
f 1
dl 0
loc 185
ccs 63
cts 69
cp 0.913
rs 9.68
wmc 34

8 Methods

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