Completed
Push — master ( 92fb9d...3bde59 )
by Dan
02:13
created

CashGame::players()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 1
cts 1
cp 1
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Cysha\Casino\Holdem\Game;
4
5
use Cysha\Casino\Cards\Deck;
6
use Cysha\Casino\Exceptions\GameException;
7
use Cysha\Casino\Game\Chips;
8
use Cysha\Casino\Game\Client;
9
use Cysha\Casino\Game\Contracts\Game;
10
use Cysha\Casino\Game\Contracts\GameParameters;
11
use Cysha\Casino\Game\PlayerCollection;
12
use Cysha\Casino\Game\TableCollection;
13
use Cysha\Casino\Holdem\Cards\Evaluators\SevenCard;
14
use Ramsey\Uuid\UuidInterface;
15
16
final class CashGame implements Game
17
{
18
    /**
19
     * @var UuidInterface
20
     */
21
    private $id;
22
23
    /**
24
     * @var string
25
     */
26
    private $name;
27
28
    /**
29
     * @var DefaultParameters
30
     */
31
    private $rules;
32
33
    /**
34
     * @var PlayerCollection
35
     */
36
    private $players;
37
38
    /**
39
     * @var TableCollection
40
     */
41
    protected $tables;
42
43
    /**
44
     * CashGame constructor.
45
     *
46
     * @param UuidInterface  $id
47
     * @param string         $name
48
     * @param GameParameters $rules
49 66
     */
50
    public function __construct(UuidInterface $id, string $name, GameParameters $rules)
51 66
    {
52 66
        $this->id = $id;
53 66
        $this->name = $name;
54 66
        $this->players = PlayerCollection::make();
55 66
        $this->tables = TableCollection::make();
56 66
        $this->rules = $rules;
0 ignored issues
show
Documentation Bug introduced by
It seems like $rules of type object<Cysha\Casino\Game...ntracts\GameParameters> is incompatible with the declared type object<Cysha\Casino\Hold...Game\DefaultParameters> of property $rules.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
57
    }
58
59
    /**
60
     * @param UuidInterface  $id
61
     * @param string         $name
62
     * @param GameParameters $rules
63
     *
64
     * @return CashGame
65 66
     */
66
    public static function setUp(UuidInterface $id, string $name, GameParameters $rules)
67 66
    {
68
        return new self($id, $name, $rules);
69
    }
70
71
    /**
72
     * @return UuidInterface
73 1
     */
74
    public function id(): UuidInterface
75 1
    {
76
        return $this->id;
77
    }
78
79
    /**
80
     * @return string
81 1
     */
82
    public function name(): string
83 1
    {
84
        return $this->name;
85
    }
86
87
    /**
88
     * @return GameParameters
89 4
     */
90
    public function rules(): GameParameters
91 4
    {
92
        return $this->rules;
93
    }
94
95
    /**
96
     * @return PlayerCollection
97 63
     */
98
    public function players(): PlayerCollection
99 63
    {
100
        return $this->players;
101
    }
102
103
    /**
104
     * @return string
105
     */
106
    public function __toString(): string
107
    {
108 62
        return $this->name;
109
    }
110 62
111
    /**
112 62
     * @return TableCollection
113
     */
114 59
    public function tables(): TableCollection
115 62
    {
116
        return $this->tables;
117 62
    }
118 1
119
    /**
120
     * @param Client $client
121 62
     * @param Chips  $buyinAmount
122 1
     *
123
     * @throws GameException
124
     */
125 61
    public function registerPlayer(Client $client, Chips $buyinAmount = null)
126
    {
127 61
        $buyinAmount = $buyinAmount ?? $this->rules()->minimumBuyIn();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\GameParameters as the method minimumBuyIn() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game...ters\CashGameParameters.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
128 61
129 61
        $playerRegistered = $this->players()
130
            ->filter(function (Client $player) use ($client) {
131
                return $client->name() === $player->name();
132
            });
133
134 2
        if ($playerRegistered->count() !== 0) {
135
            throw GameException::alreadyRegistered($client, $this);
136 2
        }
137
138
        if ($buyinAmount->amount() > $client->wallet()->amount()) {
139
            throw GameException::insufficientFunds($client, $this);
140
        }
141
142 57
        $client->wallet()->subtract($buyinAmount);
143
144
        $addPlayer = Player::fromClient($client, $buyinAmount);
145 57
        $this->players()->push($addPlayer);
146
    }
147 57
148 57
    public function removePlayer(Client $client)
149
    {
150 57
        $player = $this->players()
151 57
            ->filter(function (Player $player) use ($client) {
152 57
                return $player->name() === $client->name();
153
            })
154
            ->first()
155
        ;
156
157 54
        $client->wallet()->add($player->chipstack());
158
159 54
        $this->players = $this->players()
160
            ->reject(function (Player $player) use ($client) {
161
                return $player->name() === $client->name();
162
            })
163
            ->values();
164
    }
165
166
    public function assignPlayersToTables()
167
    {
168
        $groupedPlayers = $this->players()
169
        //->shuffle()
170
            ->chunk($this->rules()->tableSize())
171
            ->map(function (PlayerCollection $players) {
172
                $dealer = Dealer::startWork(new Deck(), new SevenCard());
173
174
                return Table::setUp($dealer, $players);
175
            })
176
            ->toArray();
177
178
        $this->tables = TableCollection::make($groupedPlayers);
179
    }
180
}
181