Passed
Push — main ( b1744e...69bb1b )
by Alex
03:36
created

GameManager::checkPlayerWon()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 0
dl 0
loc 8
ccs 6
cts 6
cp 1
crap 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace App\Game;
4
5
use App\Card\DeckOfCards;
6
use App\Card\Card;
7
8
class GameManager
9
{
10
    /** @var DeckOfCards $deck */
11
    private $deck;
12
13
    /** @var ReceiverInterface $player */
14
    private $player;
15
16
    /** @var BankerInterface $banker */
17
    private $banker;
18
19
    /** @var bool $assistanceMode As true if assistance mode is turned on, otherwise false. */
20
    private bool $assistanceMode = false;
21
22
    /** @var Card[] $removedCards All cards drawn in previous turns. */
23
    private array $removedCards = [];
24
25
    /** @var int $hasWon As 0 if no one has won, 1 if player has won or -1 if banker has won. */
26
    private int $hasWon = 0;
27
28
    /** @return int As 0 if no one has won, 1 if player has one or -1 if banker has won. */
29 6
    public function getHasWon(): int
30
    {
31 6
        return $this->hasWon;
32
    }
33
34
    /** @return bool As true if assistance mode is turned on, otherwise false. */
35 1
    public function hasAssistanceMode(): bool
36
    {
37 1
        return $this->assistanceMode;
38
    }
39
40
    /**
41
     * Move drawn cards to array of removed cards before also resetting player and banker.
42
     */
43
    public function reset(): void
44
    {
45
        /** @var Card[] $cardsToRemove Cards drawn by the player and banker this turn */
46
        $cardsToRemove = array_merge($this->player->getCards(), $this->banker->getCards());
47
48
        $this->removedCards = array_merge($this->removedCards, $cardsToRemove);
49
50
        // Reset player and banker points and cards
51
        $this->player->reset();
52
        $this->banker->reset();
53
54
        $this->hasWon = 0;
55
    }
56
57
    /** @param bool $value As true if mode should be turned on, otherwise false. */
58 1
    public function setAssistanceMode(bool $value): void
59
    {
60 1
        $this->assistanceMode = $value;
61
    }
62
63
    /** @param DeckOfCards $deck */
64 8
    public function setDeck(DeckOfCards $deck): void
65
    {
66 8
        $this->deck = $deck;
67
    }
68
69
    /** @param ReceiverInterface $player */
70 14
    public function setPlayer(ReceiverInterface $player): void
71
    {
72 14
        $this->player = $player;
73
    }
74
75
    /** @param BankerInterface $banker */
76 15
    public function setBanker(BankerInterface $banker): void
77
    {
78 15
        $this->banker = $banker;
79
    }
80
81
    /**
82
     * Get the risk of the player scoring over 21 (bursting).
83
     *
84
     * @return float As the risk of bursting on drawing another card.
85
     */
86 4
    public function getBurstRisk(): float
87
    {
88
        /** @var int $margin Number of points the player can score before bursting. */
89 4
        $margin = 21 - $this->player->getPoints();
90
91 4
        if ($margin > 13) {
92 1
            return 0;         // No card will put he player over 21, return early
93
        }
94
95
        /** @var int[] $burstCards Values of all cards that will make the player burst. */
96 3
        $burstCards = array_filter($this->deck->getValues(), function ($value) use ($margin) {
97 3
            return $value > $margin;
98 3
        });
99
100
        /** @var float $burstRisk Risk of drawing over 21. */
101 3
        $burstRisk = round(count($burstCards) / $this->deck->getCount(), 2);
102
103 3
        return $burstRisk;
104
    }
105
106
    /**
107
     * Deal player a card.
108
     */
109 3
    public function dealPlayer(): void
110
    {
111 3
        $this->player->receive($this->deck->draw(1)[0]);
112 3
        $this->refillEmptyDeck();
113
    }
114
115
    /**
116
     * Deal banker cards until they decide to stop hitting.
117
     */
118 1
    public function dealBanker(): void
119
    {
120 1
        $this->informBanker();
121
122 1
        $keepHitting = true;
123 1
        while ($keepHitting === true) {
124 1
            $this->banker->receive($this->deck->draw(1)[0]);
125
126 1
            $keepHitting = $this->banker->keepHitting();
127
128 1
            $this->refillEmptyDeck();
129
        }
130
    }
131
132
    /**
133
     * Method of informing banker about current game state.
134
     */
135 1
    private function informBanker(): void
136
    {
137 1
        $this->banker->passInfo($this->removedCards, $this->player->getPoints());
138
    }
139
140
    /** @return mixed[] As the current game state. */
141 4
    public function getState(): array
142
    {
143 4
        $state = [
144 4
            'playerPoints' => $this->player->getPoints(),
145 4
            'playerCards'  => $this->player->getCards(),
146 4
            'bankerPoints' => $this->banker->getPoints(),
147 4
            'bankerCards'  => $this->banker->getCards(),
148 4
            'cardCount'    => $this->deck->getCount(),
149 4
            'assistance'   => $this->assistanceMode ? $this->getBurstRisk() * 100 : null,
150 4
            'hasWon'       => $this->hasWon,
151 4
        ];
152
153 4
        return $state;
154
    }
155
156
    /**
157
     * Check if player won.
158
     *
159
     * @return int As who (if anyone) has won.
160
     */
161 2
    public function checkPlayerWon(): int
162
    {
163 2
        if ($this->player->getPoints() === 21) {
164 1
            $this->hasWon = 1;
165 1
        } elseif ($this->player->getPoints() > 21) {
166 1
            $this->hasWon = -1;
167
        }
168 2
        return $this->hasWon;
169
    }
170
171
    /**
172
     * Check if banker won.
173
     *
174
     * @return int As who (if anyone) has won.
175
     */
176 4
    public function checkBankerWon(): int
177
    {
178 4
        if ($this->banker->getPoints() > 21 || $this->player->getPoints() > $this->banker->getPoints()) {
179 2
            $this->hasWon = 1;
180 2
        } elseif ($this->banker->getPoints() >= $this->player->getPoints()) {
181 2
            $this->hasWon = -1;
182
        }
183 4
        return $this->hasWon;
184
    }
185
186
    /**
187
     * Fill deck with removed cards if empty.
188
     */
189 4
    private function refillEmptyDeck(): void
190
    {
191 4
        if ($this->deck->getCount() > 0) {
192 4
            return;     // Deck is not empty, do nothing and return early
193
        }
194
195
        // Add removed cards back in the deck
196
        foreach ($this->removedCards as $card) {
197
            $this->deck->addCard($card);
198
        }
199
200
        // Shuffle deck
201
        $this->deck->shuffleCards();
202
203
        // The removed cards are back in the deck, inform banker about it
204
        $this->removedCards = [];
205
        $this->informBanker();
206
    }
207
}
208