Completed
Push — master ( ef6de7...8edde9 )
by Guillermo
14:11
created

PlayersCollection::areDifferentPlayers()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 0
cts 6
cp 0
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
crap 6
1
<?php
2
3
namespace SecretSanta;
4
5
use SecretSanta\Exceptions\PlayersCollectionException;
6
7
/**
8
 * Class PlayersCollection
9
 * @package SecretSanta
10
 */
11
class PlayersCollection implements \Countable
12
{
13
    /** @var Player[] */
14
    private $players = [];
15
    /** @var array  */
16
    private $exclusivePlayers = [];
17
18
    /**
19
     * @param Player $player
20
     * @throws PlayersCollectionException
21
     */
22
    public function addPlayer(Player $player)
23
    {
24
        if (!$this->isDuplicatePlayer($player)) {
25
            $this->players[$player->id()] = $player;
26
        }
27
    }
28
29
    /**
30
     * @param Player $player
31
     * @param Player $couple
32
     * @throws PlayersCollectionException
33
     */
34
    public function addCouple(Player $player, Player $couple)
35
    {
36
        if (!$this->areDifferentPlayers([$player, $couple])) {
37
            throw new PlayersCollectionException('The couple can not be the same player');
38
        }
39
40
        if (!$this->isDuplicatePlayer($player) && !$this->isDuplicatePlayer($couple) ) {
41
            $this->players[$player->id()] = $player;
42
            $this->players[$couple->id()] = $couple;
43
44
            $this->exclusivePlayers([$player, $couple]);
45
        }
46
    }
47
48
    /**
49
     * @param Player[] $players
50
     * @throws PlayersCollectionException
51
     */
52
    public function addExclusivePlayers(array $players)
53
    {
54
        if (!$this->areDifferentPlayers($players)) {
55
            throw new PlayersCollectionException('The players must be different');
56
        }
57
58
        foreach ($players as $player) {
59
            if (!$this->isDuplicatePlayer($player)) {
60
                $this->players[$player->id()] = $player;
61
            }
62
        }
63
64
        $this->exclusivePlayers($players);
65
    }
66
67
    /**
68
     * @return Player[]
69
     */
70
    public function players()
71
    {
72
        return $this->players;
73
    }
74
75
    /**
76
     * @return Player[]
77
     */
78
    public function shufflePlayers()
79
    {
80
        return $this->shuffleAssoc($this->players);
81
    }
82
83
    /**
84
     * @param string $id
85
     * @return Player
86
     * @throws PlayersCollectionException
87
     */
88
    public function player(string $id)
89
    {
90
        if (!isset($this->players[$id])) {
91
            throw new PlayersCollectionException("Player {$id} not found");
92
        }
93
94
        return $this->players[$id];
95
    }
96
97
98
    /**
99
     * @param Player[] $players
100
     */
101
    private function exclusivePlayers($players)
102
    {
103
        foreach ($players as $mainPlayer) {
104
            foreach ($players as $player) {
105
                if ($mainPlayer->id() == $player->id()){
106
                    continue;
107
                }
108
                $this->exclusivePlayers[$mainPlayer->id()][] = $player->id();
109
            }
110
        }
111
    }
112
113
    /**
114
     * @param Player $player
115
     * @param Player $player2
116
     * @return bool
117
     */
118
    public function areExclusive(Player $player, Player $player2)
119
    {
120
        if (array_key_exists($player->id(), $this->exclusivePlayers)
121
            && in_array($player2->id(), $this->exclusivePlayers[$player->id()])
122
        ) {
123
            return true;
124
        }
125
126
        return false;
127
    }
128
129
    /**
130
     * @return int
131
     */
132
    public function count()
133
    {
134
        return count($this->players);
135
    }
136
137
    /**
138
     * @return int
139
     */
140
    public function countExclusivePlayers()
141
    {
142
        return count($this->exclusivePlayers);
143
    }
144
145
146
    /**
147
     * @param Player $player
148
     * @return bool
149
     * @throws PlayersCollectionException
150
     */
151
    private function isDuplicatePlayer(Player $player)
152
    {
153
        if (array_key_exists($player->id(), $this->players)) {
154
            throw  new PlayersCollectionException('Duplicate player: '.$player->email());
155
        }
156
157
        return false;
158
    }
159
160
    /**
161
     * @param Player[] $players
162
     * @return bool
163
     */
164
    private function areDifferentPlayers(array $players)
165
    {
166
        $uniqueIds = [];
167
        foreach ($players as $player) {
168
            $uniqueIds[] = $player->id();
169
        }
170
171
        return count($players) == count(array_unique($uniqueIds));
172
    }
173
174
    /**
175
     * @param array $list
176
     * @return array
177
     */
178
    private function shuffleAssoc(array $list)
179
    {
180
        if (!is_array($list)) return $list;
181
182
        $keys = $this->forceShuffle(array_keys($list));
183
        $random = [];
184
        foreach ($keys as $key) {
185
            $random[$key] = $list[$key];
186
        }
187
188
        return $random;
189
    }
190
191
    /**
192
     * @param array $list
193
     * @return array
194
     */
195
    private function forceShuffle(array $list)
196
    {
197
        if (!is_array($list) || count($list) < 2) return $list;
198
199
        $shuffleList = $list;
200
        while ($shuffleList == $list) {
201
            shuffle($shuffleList);
202
        }
203
204
        return $shuffleList;
205
    }
206
}