1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | /* (c) Anton Medvedev <[email protected]> |
||
6 | * |
||
7 | * For the full copyright and license information, please view the LICENSE |
||
8 | * file that was distributed with this source code. |
||
9 | */ |
||
10 | |||
11 | namespace Deployer\Command; |
||
12 | |||
13 | use Symfony\Component\Console\Command\Command; |
||
14 | use Symfony\Component\Console\Input\InputInterface as Input; |
||
15 | use Symfony\Component\Console\Output\OutputInterface as Output; |
||
16 | use Symfony\Component\Console\Question\ChoiceQuestion; |
||
17 | use Symfony\Component\Console\Style\SymfonyStyle; |
||
18 | |||
19 | use function Deployer\Support\array_flatten; |
||
20 | |||
21 | class BlackjackCommand extends Command |
||
22 | { |
||
23 | use CommandCommon; |
||
24 | |||
25 | /** |
||
26 | * @var Input |
||
27 | */ |
||
28 | private $input; |
||
29 | |||
30 | /** |
||
31 | * @var Output |
||
32 | */ |
||
33 | private $output; |
||
34 | |||
35 | public function __construct() |
||
36 | { |
||
37 | parent::__construct('blackjack'); |
||
38 | $this->setDescription('Play blackjack'); |
||
39 | } |
||
40 | |||
41 | protected function execute(Input $input, Output $output): int |
||
42 | { |
||
43 | $this->input = $input; |
||
44 | $this->output = $output; |
||
45 | $this->telemetry(); |
||
46 | $io = new SymfonyStyle($this->input, $this->output); |
||
47 | |||
48 | if (getenv('COLORTERM') === 'truecolor') { |
||
49 | $this->print("\x1b[38;2;255;95;109m╭\x1b[39m\x1b[38;2;255;95;107m─\x1b[39m\x1b[38;2;255;96;106m─\x1b[39m\x1b[38;2;255;96;104m─\x1b[39m\x1b[38;2;255;96;103m─\x1b[39m\x1b[38;2;255;97;101m─\x1b[39m\x1b[38;2;255;97;100m─\x1b[39m\x1b[38;2;255;97;99m─\x1b[39m\x1b[38;2;255;98;97m─\x1b[39m\x1b[38;2;255;100;98m─\x1b[39m\x1b[38;2;255;102;98m─\x1b[39m\x1b[38;2;255;104;98m─\x1b[39m\x1b[38;2;255;106;99m─\x1b[39m\x1b[38;2;255;108;99m─\x1b[39m\x1b[38;2;255;110;99m─\x1b[39m\x1b[38;2;255;112;100m─\x1b[39m\x1b[38;2;255;114;100m─\x1b[39m\x1b[38;2;255;116;100m─\x1b[39m\x1b[38;2;255;118;100m─\x1b[39m\x1b[38;2;255;120;101m─\x1b[39m\x1b[38;2;255;122;101m─\x1b[39m\x1b[38;2;255;124;101m─\x1b[39m\x1b[38;2;255;126;102m╮\x1b[39m"); |
||
50 | $this->print("\x1b[38;2;255;128;102m│\x1b[39m \x1b[38;2;255;130;102m│\x1b[39m"); |
||
51 | $this->print("\x1b[38;2;255;132;103m│\x1b[39m \x1b[38;2;255;134;103mW\x1b[39m\x1b[38;2;255;136;103me\x1b[39m\x1b[38;2;255;138;104ml\x1b[39m\x1b[38;2;255;140;104mc\x1b[39m\x1b[38;2;255;142;104mo\x1b[39m\x1b[38;2;255;144;104mm\x1b[39m\x1b[38;2;255;146;105me\x1b[39m\x1b[38;2;255;148;105m!\x1b[39m \x1b[38;2;255;150;105m│\x1b[39m"); |
||
52 | $this->print("\x1b[38;2;255;152;106m│\x1b[39m \x1b[38;2;255;153;106m│\x1b[39m"); |
||
53 | $this->print("\x1b[38;2;255;155;106m╰\x1b[39m\x1b[38;2;255;157;107m─\x1b[39m\x1b[38;2;255;159;107m─\x1b[39m\x1b[38;2;255;161;107m─\x1b[39m\x1b[38;2;255;163;108m─\x1b[39m\x1b[38;2;255;165;108m─\x1b[39m\x1b[38;2;255;166;108m─\x1b[39m\x1b[38;2;255;168;108m─\x1b[39m\x1b[38;2;255;170;109m─\x1b[39m\x1b[38;2;255;172;109m─\x1b[39m\x1b[38;2;255;174;109m─\x1b[39m\x1b[38;2;255;176;110m─\x1b[39m\x1b[38;2;255;177;110m─\x1b[39m\x1b[38;2;255;179;110m─\x1b[39m\x1b[38;2;255;181;111m─\x1b[39m\x1b[38;2;255;183;111m─\x1b[39m\x1b[38;2;255;185;111m─\x1b[39m\x1b[38;2;255;186;111m─\x1b[39m\x1b[38;2;255;188;112m─\x1b[39m\x1b[38;2;255;190;112m─\x1b[39m\x1b[38;2;255;192;112m─\x1b[39m\x1b[38;2;255;193;113m─\x1b[39m\x1b[38;2;255;195;113m╯\x1b[0m"); |
||
54 | } else { |
||
55 | $this->print("╭─────────────────────╮"); |
||
56 | $this->print("│ │"); |
||
57 | $this->print("│ Welcome! │"); |
||
58 | $this->print("│ │"); |
||
59 | $this->print("╰─────────────────────╯"); |
||
60 | } |
||
61 | |||
62 | $money = 100; |
||
63 | |||
64 | if (md5(strval(getenv('MONEY'))) === '5a7c2f336d0cc43b68951e75cdffe333') { |
||
65 | $money += 25; |
||
66 | $this->print('<fg=cyan>You got an extra $25.</>'); |
||
67 | } elseif (md5(strval(getenv('MONEY'))) === '530029252abcbda4a2a2069036ccc7fc') { |
||
68 | $money += 100; |
||
69 | $this->print('<fg=cyan>You got an extra $100.</>'); |
||
70 | } elseif (md5(strval(getenv('MONEY'))) === '1aa827a06ecbfa5d6fa7c62ad245f3a3') { |
||
71 | $money = 100000; |
||
72 | } |
||
73 | |||
74 | $hasWatch = true; |
||
75 | $orderWhiskey = false; |
||
76 | $whiskeyLevel = 0; |
||
77 | |||
78 | $deck = $this->newDeck(); |
||
79 | $graveyard = []; |
||
80 | $dealersHand = []; |
||
81 | $playersHand = []; |
||
82 | shuffle($deck); |
||
83 | $deal = function () use (&$deck, &$graveyard) { |
||
84 | if (count($deck) == 0) { |
||
85 | shuffle($graveyard); |
||
86 | $deck = $graveyard; |
||
87 | $graveyard = []; |
||
88 | } |
||
89 | return array_pop($deck); |
||
90 | }; |
||
91 | |||
92 | start: |
||
93 | $this->print("You have <info>$</info><info>$money</info>."); |
||
94 | if ($money > 0) { |
||
95 | $bet = (int) $io->ask('Your bet', '5'); |
||
96 | if ($bet <= 0) { |
||
97 | goto start; |
||
98 | } |
||
99 | if ($bet > $money) { |
||
100 | goto start; |
||
101 | } |
||
102 | } elseif ($hasWatch) { // @phpstan-ignore-line |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
103 | $answer = $io->askQuestion(new ChoiceQuestion('?', ['leave', '- Here, take my watch! [$25]'], 0)); |
||
104 | if ($answer == 'leave') { |
||
105 | goto leave; |
||
106 | } else { |
||
107 | $hasWatch = false; |
||
108 | $money = 25; |
||
109 | $bet = 25; |
||
110 | } |
||
111 | } else { |
||
112 | goto leave; |
||
113 | } |
||
114 | |||
115 | $graveyard = array_merge($graveyard, $dealersHand); |
||
116 | $dealersHand = []; |
||
117 | $dealersHand[] = $deal(); |
||
118 | $this->print("Dealers hand:"); |
||
119 | $this->printHand($dealersHand); |
||
120 | |||
121 | $graveyard = array_merge($graveyard, $playersHand); |
||
122 | $playersHand = []; |
||
123 | $playersHand[] = $deal(); |
||
124 | $playersHand[] = $deal(); |
||
125 | $this->print("Your hand:"); |
||
126 | $this->printHand($playersHand, 2); |
||
127 | |||
128 | while (true) { |
||
129 | $question = new ChoiceQuestion('Your turn', ['hit', 'stand'], 0); |
||
130 | $answer = $io->askQuestion($question); |
||
131 | |||
132 | if ($answer === 'hit') { |
||
133 | $playersHand[] = $deal(); |
||
134 | usleep(200000); |
||
135 | } |
||
136 | |||
137 | if ($answer === 'stand') { |
||
138 | break; |
||
139 | } |
||
140 | |||
141 | $this->printHand($playersHand); |
||
142 | $handValue = self::handValue($playersHand); |
||
143 | |||
144 | if ($handValue > 21) { |
||
145 | $this->print("You got <comment>$handValue</comment>."); |
||
146 | $this->print("<fg=cyan>Bust!</>"); |
||
147 | $this->print("-<info>$</info><info>$bet</info>"); |
||
148 | $money -= $bet; |
||
149 | goto nextRound; |
||
150 | } |
||
151 | } |
||
152 | |||
153 | $this->printHand($dealersHand); |
||
154 | $this->print("Dealer: " . self::handValue($dealersHand)); |
||
155 | sleep(1); |
||
156 | |||
157 | while (self::handValue($dealersHand) <= 17) { |
||
158 | $dealersHand[] = $deal(); |
||
159 | $this->printHand($dealersHand); |
||
160 | $this->print("Dealer: " . self::handValue($dealersHand)); |
||
161 | sleep(1); |
||
162 | } |
||
163 | |||
164 | $d = self::handValue($dealersHand); |
||
165 | $p = self::handValue($playersHand); |
||
166 | $this->print("You got <comment>$p</comment> and dealer <comment>$d</comment>."); |
||
167 | |||
168 | if ($d > 21 || $p > $d) { |
||
169 | $this->print("<fg=cyan>You won!</>"); |
||
170 | $this->print("+<info>$</info><info>$bet</info>"); |
||
171 | $money += $bet; |
||
172 | } elseif ($p < $d) { |
||
173 | $this->print("<fg=cyan>You lose!</>"); |
||
174 | $this->print("-<info>$</info><info>$bet</info>"); |
||
175 | $money -= $bet; |
||
176 | } else { |
||
177 | $this->print("<fg=cyan>Push!</>"); |
||
178 | } |
||
179 | |||
180 | nextRound: |
||
181 | $choices = ['continue', 'leave']; |
||
182 | if ($orderWhiskey) { |
||
0 ignored issues
–
show
|
|||
183 | $orderWhiskey = false; |
||
184 | $whiskeyLevel = 4; |
||
185 | $this->print(); |
||
186 | $this->print('The waitress brought whiskey and says:'); |
||
187 | $this->print(' - Your whiskey, sir.'); |
||
188 | if ($money >= 5) { |
||
189 | array_push($choices, 'tip the waitress [$5]'); |
||
190 | } |
||
191 | } elseif ($money >= 5) { |
||
192 | array_push($choices, 'order whiskey [$5]'); |
||
193 | } |
||
194 | |||
195 | if ($whiskeyLevel > 0) { |
||
196 | $this->printWhiskey($whiskeyLevel); |
||
197 | $whiskeyLevel--; |
||
198 | } |
||
199 | $answer = $io->askQuestion(new ChoiceQuestion('?', $choices, 0)); |
||
200 | |||
201 | if ($answer == 'leave') { |
||
202 | goto leave; |
||
203 | } elseif ($money >= 5 && $answer == 'order whiskey [$5]') { |
||
204 | $orderWhiskey = true; |
||
205 | $this->print('You say:'); |
||
206 | $this->print(' - Whiskey, please.'); |
||
207 | $money -= 5; |
||
208 | } elseif ($money >= 5 && $answer == 'tip the waitress [$5]') { |
||
209 | $this->print('The waitress says:'); |
||
210 | $this->print(' - Thank you, sir!'); |
||
211 | $money -= 5; |
||
212 | } |
||
213 | $this->print(); |
||
214 | $this->print("=====> Next round <====="); |
||
215 | goto start; |
||
216 | |||
217 | leave: |
||
218 | if ($money >= 5) { |
||
219 | $answer = $io->ask('Leave a $5 tip to the dealer?', 'yes'); |
||
220 | if ($answer === 'yes') { |
||
221 | $this->print("You can leave a tip here:"); |
||
222 | $this->print(); |
||
223 | $this->print("- https://github.com/sponsors/antonmedv"); |
||
224 | $this->print("- https://paypal.me/antonmedv"); |
||
225 | $this->print(); |
||
226 | } |
||
227 | } |
||
228 | $this->print('Thanks for playing, Come again!'); |
||
229 | return 0; |
||
230 | } |
||
231 | |||
232 | private function newDeck(): array |
||
233 | { |
||
234 | $deck = []; |
||
235 | foreach (['♠', '♣', '♥', '♦'] as $suit) { |
||
236 | for ($i = 2; $i <= 10; $i++) { |
||
237 | $deck[] = [strval($i), $suit]; |
||
238 | } |
||
239 | $deck[] = ['J', $suit]; |
||
240 | $deck[] = ['Q', $suit]; |
||
241 | $deck[] = ['K', $suit]; |
||
242 | $deck[] = ['A', $suit]; |
||
243 | } |
||
244 | return $deck; |
||
245 | } |
||
246 | |||
247 | public static function handValue(array $hand): int |
||
248 | { |
||
249 | $aces = 0; |
||
250 | $value = 0; |
||
251 | foreach ($hand as [$rank]) { |
||
252 | switch ($rank) { |
||
253 | case '2': |
||
254 | $value += 2; |
||
255 | break; |
||
256 | case '3': |
||
257 | $value += 3; |
||
258 | break; |
||
259 | case '4': |
||
260 | $value += 4; |
||
261 | break; |
||
262 | case '5': |
||
263 | $value += 5; |
||
264 | break; |
||
265 | case '6': |
||
266 | $value += 6; |
||
267 | break; |
||
268 | case '7': |
||
269 | $value += 7; |
||
270 | break; |
||
271 | case '8': |
||
272 | $value += 8; |
||
273 | break; |
||
274 | case '9': |
||
275 | $value += 9; |
||
276 | break; |
||
277 | case '10': |
||
278 | case 'J': |
||
279 | case 'Q': |
||
280 | case 'K': |
||
281 | $value += 10; |
||
282 | break; |
||
283 | case 'A': |
||
284 | $aces++; |
||
285 | break; |
||
286 | } |
||
287 | } |
||
288 | $variants = [$value]; |
||
289 | while ($aces-- > 0) { |
||
290 | $variants = array_flatten(array_map(function ($v) { |
||
291 | return [$v + 1, $v + 11]; |
||
292 | }, $variants)); |
||
293 | } |
||
294 | $sum = $variants[0]; |
||
295 | for ($i = 1; $i < count($variants); $i++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
296 | if ($variants[$i] <= 21) { |
||
297 | $sum = $variants[$i]; |
||
298 | } else { |
||
299 | break; |
||
300 | } |
||
301 | } |
||
302 | return $sum; |
||
303 | } |
||
304 | |||
305 | private function print(string $text = "") |
||
306 | { |
||
307 | $this->output->writeln(" $text"); |
||
308 | } |
||
309 | |||
310 | private function printHand(array $hand, int $offset = 1) |
||
311 | { |
||
312 | $cards = []; |
||
313 | for ($i = 0; $i < count($hand) - $offset; $i++) { |
||
314 | [$rank] = $hand[$i]; |
||
315 | $cards[] = [ |
||
316 | "┌───", |
||
317 | "│" . str_pad($rank, 3), |
||
318 | "│ ", |
||
319 | "│ ", |
||
320 | "│ ", |
||
321 | "│ ", |
||
322 | "└───", |
||
323 | ]; |
||
324 | } |
||
325 | |||
326 | for (; $i < count($hand); $i++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
327 | [$rank, $suit] = $hand[$i]; |
||
328 | $cards[] = [ |
||
329 | "┌───────┐", |
||
330 | "│" . str_pad($rank, 7) . "│", |
||
331 | "│ │", |
||
332 | "│ " . $suit . " │", |
||
333 | "│ │", |
||
334 | "│" . str_pad($rank, 7, " ", STR_PAD_LEFT) . "│", |
||
335 | "└───────┘", |
||
336 | ]; |
||
337 | } |
||
338 | |||
339 | for ($i = 0; $i < 7; $i++) { |
||
340 | $this->output->write(" "); |
||
341 | foreach ($cards as $lines) { |
||
342 | $this->output->write($lines[$i]); |
||
343 | } |
||
344 | $this->output->write("\n"); |
||
345 | } |
||
346 | } |
||
347 | |||
348 | private function printWhiskey(int $whiskeyLevel) |
||
349 | { |
||
350 | if ($whiskeyLevel == 4) { |
||
351 | echo <<<ASCII |
||
352 | |||
353 | | | |
||
354 | |__________| |
||
355 | | | |
||
356 | | /\ / /\ /| |
||
357 | |/_/__/__\_| |
||
358 | |||
359 | |||
360 | ASCII; |
||
361 | } |
||
362 | if ($whiskeyLevel == 3) { |
||
363 | echo <<<ASCII |
||
364 | |||
365 | | | |
||
366 | | | |
||
367 | |__________| |
||
368 | | /\ / /\ /| |
||
369 | |/_/__/__\_| |
||
370 | |||
371 | |||
372 | ASCII; |
||
373 | } |
||
374 | if ($whiskeyLevel == 2) { |
||
375 | echo <<<ASCII |
||
376 | |||
377 | | | |
||
378 | | | |
||
379 | | | |
||
380 | |_/\_/_/\_/| |
||
381 | |/_/__/__\_| |
||
382 | |||
383 | |||
384 | ASCII; |
||
385 | } |
||
386 | if ($whiskeyLevel == 1) { |
||
387 | echo <<<ASCII |
||
388 | |||
389 | | | |
||
390 | | | |
||
391 | | | |
||
392 | | /\ / /\ /| |
||
393 | |/_/__/__\_| |
||
394 | |||
395 | |||
396 | ASCII; |
||
397 | } |
||
398 | } |
||
399 | } |
||
400 |