Passed
Push — main ( 06b8a6...5a482c )
by Emil
05:26
created

GameLogic   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 269
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 118
c 1
b 0
f 0
dl 0
loc 269
rs 10
ccs 124
cts 124
cp 1
wmc 29

7 Methods

Rating   Name   Duplication   Size   Complexity  
B calculateWinner() 0 58 7
A playDealer() 0 16 2
A __construct() 0 4 1
A calculateAllWinners() 0 5 2
A stateOfGame() 0 51 4
A checkIfDealersTurn() 0 21 5
B newGame() 0 46 8
1
<?php
2
3
namespace App\Game\BlackJack;
4
5
use App\Game\BlackJack;
6
7
class GameLogic
8
{
9
    private BlackJack $blackjack;
10
    private bool $isDealersTurn;
11
12 20
    public function __construct(BlackJack $blackjack)
13
    {
14 20
        $this->blackjack = $blackjack;
15 20
        $this->isDealersTurn = false;
16
    }
17
18
    /**
19
     * calculateWinner.
20
     */
21 12
    private function calculateWinner(int $index): void
22
    {
23
        // Get variables
24 12
        $player = $this->blackjack->getPlayers()[$index];
25 12
        $credits = $player->getCredits();
26 12
        $bet = $player->getBet();
27 12
        $gameState = $player->getGameState();
28 12
        $dealer = $this->blackjack->getDealer();
29
30
        // The winner is already decided or player broke
31 12
        if (Player::DEALER_WIN === $gameState or true === $player->isBroke()) {
32 3
            return;
33
        }
34
35
        // If player is busted dealer wins
36 10
        if (true === $player->isBust()) {
37 1
            $player->setGameState(Player::DEALER_WIN);
38 1
            $player->resetBet();
39 1
            $this->blackjack->setPlayer($index, $player);
40
41 1
            return;
42
        }
43
44
        // If dealer is bust: player wins
45 9
        if (true === $dealer->isBust()) {
46 1
            $player->setGameState(Player::PLAYER_WIN);
47 1
            $player->setCredits($credits + ($bet * 2));
48 1
            $player->resetBet();
49 1
            $this->blackjack->setPlayer($index, $player);
50
51 1
            return;
52
        }
53
54
        // Both are not busts, compare their hand values
55 8
        $playerHandValue = $player->getHandValue();
56 8
        $dealerHandValue = $dealer->getHandValue();
57
58 8
        if ($playerHandValue > $dealerHandValue) {
59 2
            $player->setGameState(Player::PLAYER_WIN);
60 2
            $player->setCredits($credits + ($bet * 2));
61 2
            $player->resetBet();
62 2
            $this->blackjack->setPlayer($index, $player);
63
64 2
            return;
65
        }
66
67 7
        if ($playerHandValue < $dealerHandValue) {
68 6
            $player->setGameState(Player::DEALER_WIN);
69 6
            $player->resetBet();
70 6
            $this->blackjack->setPlayer($index, $player);
71
72 6
            return;
73
        }
74
75 1
        $player->setGameState(Player::TIE);
76 1
        $player->setCredits($credits + $bet);
77 1
        $player->resetBet();
78 1
        $this->blackjack->setPlayer($index, $player);
79
    }
80
81
    /**
82
     * calculateAllWinners.
83
     */
84 12
    private function calculateAllWinners(): void
85
    {
86 12
        $numOfPlayers = $this->blackjack->getNumOfPlayers();
87 12
        for ($i = 0; $i < $numOfPlayers; ++$i) {
88 12
            $this->calculateWinner($i);
89
        }
90
    }
91
92
    /**
93
     * playDealer.
94
     *
95
     * The logic for the dealer to play
96
     */
97 12
    private function playDealer(): void
98
    {
99
        // Get variables
100 12
        $dealer = $this->blackjack->getDealer();
101 12
        $deck = $this->blackjack->getDeck();
102
103 12
        while (true === $dealer->play()) {
104 4
            $dealer->addCard($deck->drawCard());
105
        }
106
107
        // Set variables
108 12
        $this->blackjack->setDealer($dealer);
109 12
        $this->blackjack->setDeck($deck);
110
111
        // Calculate all winners
112 12
        $this->calculateAllWinners();
113
    }
114
115
    /**
116
     * newGame.
117
     *
118
     * Sets up a new game
119
     *
120
     * @param array<int, int> $bets
121
     */
122 13
    public function newGame(array $bets = []): void
123
    {
124
        // Get variables
125 13
        $players = $this->blackjack->getPlayers();
126 13
        $dealer = $this->blackjack->getDealer();
127 13
        $deck = $this->blackjack->getDeck();
128 13
        $numOfPlayers = $this->blackjack->getNumOfPlayers();
129
130
        // Reset game
131 13
        $this->isDealersTurn = false;
132 13
        $dealer->dropHand();
133 13
        $deck->reshuffleDeck();
134
135
        // Set bets
136 13
        for ($i = 0; $i < $numOfPlayers; ++$i) {
137
            // Reset the player
138 13
            $players[$i]->resetBet();
139 13
            $players[$i]->dropHand();
140 13
            $players[$i]->setGameState(Player::UNDECIDED);
141
142
            // If the player is broke skip
143 13
            if (true === $players[$i]->isBroke()) {
144 1
                continue;
145
            }
146
147
            // If there is a bet and it is lager then minimum
148 13
            (true === array_key_exists($i, $bets) and BlackJack::MINIMUM_BET < $bets[$i]) ? $players[$i]->increaseBet($bets[$i]) : $players[$i]->increaseBet(BlackJack::MINIMUM_BET);
149
        }
150
151
        // For 2 rounds of dealing a card
152 13
        for ($round = 0; $round < 2; ++$round) {
153 13
            for ($i = 0; $i < $numOfPlayers; ++$i) {
154
                // If the player is broke skip
155 13
                if (true === $players[$i]->isBroke()) {
156 1
                    continue;
157
                }
158
159 13
                $players[$i]->addCard($deck->drawCard());
160
            }
161 13
            $dealer->addCard($deck->drawCard());
162
        }
163
164
        // Set variables
165 13
        $this->blackjack->setPlayers($players);
166 13
        $this->blackjack->setDealer($dealer);
167 13
        $this->blackjack->setDeck($deck);
168
    }
169
170
    /**
171
     * stateOfGame.
172
     *
173
     * Returns the current game state.
174
     *
175
     * @return array
176
     *               Descriptive list of array contents:
177
     *               - numOfPlayers (int)
178
     *               - playersNames (array<string>)
179
     *               - playersCards (array<int, array<string>>)
180
     *               - playersHandValue (array<string>)
181
     *               - playersCredits (array<string>)
182
     *               - playersBets (array<string>)
183
     *               - dealerCards (array<string>)
184
     *               - dealerHandValue (string)
185
     *               - gameStates (array<string>)
186
     *
187
     * @phpstan-return array{
188
     *   numOfPlayers: int,
189
     *   playersNames: array<string>,
190
     *   playersCards: array<int, array<string>>,
191
     *   playersHandValue: array<string>,
192
     *   playersCredits: array<string>,
193
     *   playersBets: array<string>,
194
     *   dealerCards: array<string>,
195
     *   dealerHandValue: string,
196
     *   gameStates: array<string>
197
     * }
198
     */
199 11
    public function stateOfGame(): array
200
    {
201
        // Get variables
202 11
        $players = $this->blackjack->getPlayers();
203 11
        $dealer = $this->blackjack->getDealer();
204 11
        $numOfPlayers = $this->blackjack->getNumOfPlayers();
205
206
        // Map Player game states to strings
207 11
        $gameStateMap = [
208 11
            Player::DOUBLE_DOWN => 'Double Down',
209 11
            Player::STAYED => 'Stayed',
210 11
            Player::UNDECIDED => 'Undecided',
211 11
            Player::TIE => 'Tie',
212 11
            Player::PLAYER_WIN => 'Player',
213 11
            Player::DEALER_WIN => 'Dealer',
214 11
        ];
215
216 11
        $data = [
217 11
            'numOfPlayers' => $numOfPlayers,
218 11
            'playersNames' => [],
219 11
            'playersCards' => [],
220 11
            'playersHandValue' => [],
221 11
            'playersCredits' => [],
222 11
            'playersBets' => [],
223 11
            'dealerCards' => $dealer->getString(),
224 11
            'dealerHandValue' => strval($dealer->getHandValue()),
225 11
            'gameStates' => [],
226 11
        ];
227
228 11
        for ($i = 0; $i < $numOfPlayers; ++$i) {
229 11
            $data['playersNames'][$i] = $players[$i]->getName();
230 11
            $data['playersCards'][$i] = $players[$i]->getString();
231 11
            $data['playersHandValue'][$i] = strval($players[$i]->getHandValue());
232 11
            $data['playersCredits'][$i] = strval($players[$i]->getCredits());
233 11
            $data['playersBets'][$i] = strval($players[$i]->getBet());
234
235 11
            $gameState = $players[$i]->getGameState();
236
            // Use the mapping array to get the string
237 11
            $data['gameStates'][$i] = $gameStateMap[$gameState] ?? 'Unknown';
238
        }
239
240
        // If all players are not done
241 11
        if (false === $this->isDealersTurn) {
242 5
            $dealerCards = $dealer->getString();
243 5
            if (0 !== count($dealerCards)) {
244 4
                $data['dealerCards'] = [$dealerCards[0], '🂠'];
245 4
                $data['dealerHandValue'] = '0';
246
            }
247
        }
248
249 11
        return $data;
250
    }
251
252
    /**
253
     * checkIfDealersTurn.
254
     */
255 12
    public function checkIfDealersTurn(): void
256
    {
257
        // Get variables
258 12
        $players = $this->blackjack->getPlayers();
259 12
        $numOfPlayers = $this->blackjack->getNumOfPlayers();
260
261
        // Check if all players are done
262 12
        $allPlayersDone = true;
263
264 12
        for ($i = 0; $i < $numOfPlayers; ++$i) {
265 12
            $roundState = $players[$i]->getGameState();
266
            // If undecided and not broke
267 12
            if (Player::UNDECIDED === $roundState and false === $players[$i]->isBroke()) {
268 2
                $allPlayersDone = false;
269 2
                break;
270
            }
271
        }
272
273 12
        if (true === $allPlayersDone) {
274 12
            $this->isDealersTurn = true;
275 12
            $this->playDealer();
276
        }
277
    }
278
}
279