PlayersCollection::addCouple()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

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