1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace App\Card; |
4
|
|
|
|
5
|
|
|
use App\Card\PayoutBlackJack; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Class BlackJack is game logic handler. |
9
|
|
|
*/ |
10
|
|
|
class BlackJack |
11
|
|
|
{ |
12
|
|
|
/** @var Deck */ |
13
|
|
|
private Deck $deck; |
14
|
|
|
|
15
|
|
|
/** @var CardHand[] */ |
16
|
|
|
private array $playerHands = []; |
17
|
|
|
|
18
|
|
|
/** @var int Index for the active hand */ |
19
|
|
|
private int $currentHandIndex = 0; |
20
|
|
|
|
21
|
|
|
/** @var CardHand */ |
22
|
|
|
private CardHand $bankHand; |
23
|
|
|
|
24
|
|
|
private BlackJackRules $rules; |
25
|
|
|
|
26
|
|
|
private PayoutBlackJack $payout; |
27
|
|
|
|
28
|
|
|
/** @var bool Flag for whether the game is over. */ |
29
|
|
|
private bool $gameOver = false; |
30
|
|
|
|
31
|
|
|
/** @var string[] The result message. */ |
32
|
|
|
private array $results = []; |
33
|
|
|
|
34
|
|
|
private string $playerName = ''; |
35
|
|
|
private int $bet = 0; |
36
|
|
|
private int $balance = 0; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Black Jack constructor. |
40
|
|
|
* |
41
|
|
|
* Init the game by creating a new deck and empty hands for the player and the bank. |
42
|
|
|
*/ |
43
|
13 |
|
public function __construct(Deck $deck, BlackJackRules $rules, PayoutBlackJack $payout) |
44
|
|
|
{ |
45
|
13 |
|
$this->deck = $deck; |
46
|
13 |
|
$this->rules = $rules; |
47
|
13 |
|
$this->payout = $payout; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Draw a card for current player hand. |
52
|
|
|
*/ |
53
|
3 |
|
public function drawForPlayer(): void |
54
|
|
|
{ |
55
|
3 |
|
$hand = $this->getCurrentHand(); |
56
|
|
|
|
57
|
3 |
|
if ($hand === null) { |
58
|
1 |
|
return; |
59
|
|
|
} |
60
|
|
|
|
61
|
2 |
|
$this->dealCardTo($hand); |
62
|
|
|
|
63
|
2 |
|
if ($hand->getTotalBlackJack() > 21) { |
64
|
1 |
|
$this->nextHand(); |
65
|
|
|
} |
66
|
|
|
} |
67
|
|
|
|
68
|
3 |
|
public function getCurrentHand(): ?CardHand |
69
|
|
|
{ |
70
|
3 |
|
return $this->playerHands[$this->currentHandIndex] ?? null; |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Go to next player hand, or bank at the end. |
75
|
|
|
*/ |
76
|
3 |
|
public function nextHand(): void |
77
|
|
|
{ |
78
|
3 |
|
$this->currentHandIndex++; |
79
|
|
|
|
80
|
3 |
|
if ($this->currentHandIndex >= count($this->playerHands)) { |
81
|
2 |
|
$this->drawForBank(); |
82
|
2 |
|
$this->compareResults(); |
83
|
|
|
} |
84
|
|
|
} |
85
|
|
|
|
86
|
3 |
|
public function getCurrentHandIndex(): int |
87
|
|
|
{ |
88
|
3 |
|
return $this->currentHandIndex; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Player chooses to "stay" on this hand → move to the next one. |
93
|
|
|
*/ |
94
|
2 |
|
public function stay(): void |
95
|
|
|
{ |
96
|
2 |
|
$this->nextHand(); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* Public wrapper for drawing bank cards via BlackJackRUles class. |
101
|
|
|
*/ |
102
|
3 |
|
public function drawForBank(): void |
103
|
|
|
{ |
104
|
3 |
|
$this->rules->drawForBank($this->bankHand, $this->deck); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Compare each player hand against the bank |
109
|
|
|
* and determine the game result. |
110
|
|
|
*/ |
111
|
4 |
|
public function compareResults(): void |
112
|
|
|
{ |
113
|
4 |
|
foreach ($this->playerHands as $index => $hand) { |
114
|
4 |
|
$outcome = $this->rules->determineResult($hand, $this->bankHand, $index); |
115
|
|
|
|
116
|
4 |
|
$this->payout->applyPayout($outcome['result'], $this->bet, $this->balance); |
117
|
|
|
|
118
|
4 |
|
$this->results[] = $outcome['message']; |
119
|
|
|
} |
120
|
|
|
|
121
|
4 |
|
$this->gameOver = true; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* Start a new round by creating player hands and dealing cards. |
126
|
|
|
* |
127
|
|
|
* @param int $numHands Number of hands the player wants (1-3) |
128
|
|
|
*/ |
129
|
11 |
|
public function startGame(int $numHands = 1): void |
130
|
|
|
{ |
131
|
11 |
|
if ($numHands < 1 || $numHands > 3) { |
132
|
1 |
|
$numHands = 1; |
133
|
|
|
} |
134
|
|
|
|
135
|
11 |
|
$this->playerHands = []; |
136
|
11 |
|
$this->results = []; |
137
|
11 |
|
$this->currentHandIndex = 0; |
138
|
11 |
|
$this->gameOver = false; |
139
|
|
|
|
140
|
|
|
// Create players hands |
141
|
11 |
|
for ($i = 0; $i < $numHands; $i++) { |
142
|
11 |
|
$hand = new CardHand(); |
143
|
11 |
|
$this->dealCardTo($hand); |
144
|
11 |
|
$this->dealCardTo($hand); |
145
|
11 |
|
$this->playerHands[] = $hand; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
// Crate banks hand |
149
|
11 |
|
$this->bankHand = new CardHand(); |
150
|
11 |
|
$this->dealCardTo($this->bankHand); |
151
|
11 |
|
$this->dealCardTo($this->bankHand); |
152
|
|
|
|
153
|
|
|
// Draw bet from balance |
154
|
11 |
|
$this->balance -= $this->bet * $numHands; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* Deal one card from the deck. |
159
|
|
|
*/ |
160
|
11 |
|
public function dealCardTo(CardHand $hand): void |
161
|
|
|
{ |
162
|
11 |
|
$card = $this->deck->drawCard(); |
163
|
11 |
|
if ($card !== null) { |
164
|
11 |
|
$hand->addCard($card); |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* @return CardHand[] |
170
|
|
|
*/ |
171
|
4 |
|
public function getPlayerHands(): array |
172
|
|
|
{ |
173
|
4 |
|
return $this->playerHands; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* @return string[] |
178
|
|
|
*/ |
179
|
2 |
|
public function getResults(): array |
180
|
|
|
{ |
181
|
2 |
|
return $this->results; |
182
|
|
|
} |
183
|
|
|
|
184
|
3 |
|
public function getBankHand(): CardHand |
185
|
|
|
{ |
186
|
3 |
|
return $this->bankHand; |
187
|
|
|
} |
188
|
|
|
|
189
|
2 |
|
public function isGameOver(): bool |
190
|
|
|
{ |
191
|
2 |
|
return $this->gameOver; |
192
|
|
|
} |
193
|
|
|
|
194
|
3 |
|
public function setPlayerName(string $name): void |
195
|
|
|
{ |
196
|
3 |
|
$this->playerName = $name; |
197
|
|
|
} |
198
|
|
|
|
199
|
11 |
|
public function setBet(int $bet): void |
200
|
|
|
{ |
201
|
11 |
|
$this->bet = $bet; |
202
|
|
|
} |
203
|
|
|
|
204
|
3 |
|
public function getPlayerName(): string |
205
|
|
|
{ |
206
|
3 |
|
return $this->playerName; |
207
|
|
|
} |
208
|
|
|
|
209
|
3 |
|
public function getBet(): int |
210
|
|
|
{ |
211
|
3 |
|
return $this->bet; |
212
|
|
|
} |
213
|
|
|
|
214
|
5 |
|
public function getBalance(): int |
215
|
|
|
{ |
216
|
5 |
|
return $this->balance; |
217
|
|
|
} |
218
|
|
|
|
219
|
11 |
|
public function setBalance(int $amount): void |
220
|
|
|
{ |
221
|
11 |
|
$this->balance = $amount; |
222
|
|
|
} |
223
|
|
|
} |
224
|
|
|
|