Passed
Push — main ( c11a0d...b1744e )
by Alex
03:33
created

GameManager   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 187
Duplicated Lines 0 %

Test Coverage

Coverage 83.33%

Importance

Changes 12
Bugs 0 Features 1
Metric Value
eloc 57
c 12
b 0
f 1
dl 0
loc 187
ccs 55
cts 66
cp 0.8333
rs 10
wmc 25

14 Methods

Rating   Name   Duplication   Size   Complexity  
A setAssistanceMode() 0 3 1
A dealPlayer() 0 4 1
A informBanker() 0 3 1
A getBurstRisk() 0 18 2
A getState() 0 13 2
A setPlayer() 0 3 1
A dealBanker() 0 11 2
A setDeck() 0 3 1
A reset() 0 12 1
A setBanker() 0 3 1
A hasAssistanceMode() 0 3 1
A getHasWon() 0 3 1
A refillEmptyDeck() 0 17 3
B updateHasWonStatus() 0 12 7
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 7
    public function getHasWon(): int
30
    {
31 7
        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 15
    public function setPlayer(ReceiverInterface $player): void
71
    {
72 15
        $this->player = $player;
73
    }
74
75
    /** @param BankerInterface $banker */
76 16
    public function setBanker(BankerInterface $banker): void
77
    {
78 16
        $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
     * Update who (if anyone) has won by checking their respective win conditions.
158
     *
159
     * @return int As who (if anyone) has won.
160
     */
161 7
    public function updateHasWonStatus(): int
162
    {
163 7
        $playerPoints = $this->player->getPoints();
164 7
        $bankerPoints = $this->banker->getPoints();
165
166 7
        if ($playerPoints === 21 || $bankerPoints > 21 || ($bankerPoints > 0 && $playerPoints > $bankerPoints)) {
167 3
            $this->hasWon = 1;
168 4
        } elseif ($playerPoints > 21 || $bankerPoints >= $playerPoints) {
169 3
            $this->hasWon = -1;
170
        }
171
172 7
        return $this->hasWon;
173
    }
174
175
    /**
176
     * Fill deck with removed cards if empty.
177
     */
178 4
    private function refillEmptyDeck(): void
179
    {
180 4
        if ($this->deck->getCount() > 0) {
181 4
            return;     // Deck is not empty, do nothing and return early
182
        }
183
184
        // Add removed cards back in the deck
185
        foreach ($this->removedCards as $card) {
186
            $this->deck->addCard($card);
187
        }
188
189
        // Shuffle deck
190
        $this->deck->shuffleCards();
191
192
        // The removed cards are back in the deck, inform banker about it
193
        $this->removedCards = [];
194
        $this->informBanker();
195
    }
196
}
197