Completed
Push — master ( 0c443a...572f35 )
by Guillermo
01:33
created

PlayersCollection::forceShuffle()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 7
cts 7
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 6
nc 3
nop 1
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 4
    public function addPlayer(Player $player)
23
    {
24 4
        if (!$this->isDuplicatePlayer($player)) {
25 4
            $this->players[$player->id()] = $player;
26 4
        }
27 4
    }
28
29
    /**
30
     * @param Player $player
31
     * @param Player $couple
32
     * @throws PlayersCollectionException
33
     */
34 5
    public function addCouple(Player $player, Player $couple)
35
    {
36 5
        if (!$this->areDifferentPlayers([$player, $couple])) {
37 1
            throw new PlayersCollectionException('The couple can not be the same player');
38
        }
39
40 4
        if (!$this->isDuplicatePlayer($player) && !$this->isDuplicatePlayer($couple) ) {
41 3
            $this->players[$player->id()] = $player;
42 3
            $this->players[$couple->id()] = $couple;
43
44 3
            $this->exclusivePlayers([$player, $couple]);
45 3
        }
46 3
    }
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 1
    public function players()
71
    {
72 1
        return $this->players;
73
    }
74
75
    /**
76
     * @return Player[]
77
     */
78 1
    public function shufflePlayers()
79
    {
80 1
        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 6
    private function exclusivePlayers($players)
102
    {
103 6
        foreach ($players as $mainPlayer) {
104 6
            foreach ($players as $player) {
105 6
                if ($mainPlayer->id() == $player->id()){
106 6
                    continue;
107
                }
108 6
                $this->exclusivePlayers[$mainPlayer->id()][] = $player->id();
109 6
            }
110 6
        }
111 6
    }
112
113
    /**
114
     * @param Player $player
115
     * @param Player $player2
116
     * @return bool
117
     */
118 1
    public function areExclusive(Player $player, Player $player2)
119
    {
120 1
        if (array_key_exists($player->id(), $this->exclusivePlayers)
121 1
            && in_array($player2->id(), $this->exclusivePlayers[$player->id()])
122 1
        ) {
123 1
            return true;
124
        }
125
126 1
        return false;
127
    }
128
129
    /**
130
     * @return int
131
     */
132 1
    public function count()
133
    {
134 1
        return count($this->players);
135
    }
136
137
    /**
138
     * @return int
139
     */
140 1
    public function countExclusivePlayers()
141
    {
142 1
        return count($this->exclusivePlayers);
143
    }
144
145
146
    /**
147
     * @param Player $player
148
     * @return bool
149
     * @throws PlayersCollectionException
150
     */
151 10
    private function isDuplicatePlayer(Player $player)
152
    {
153 10
        if (array_key_exists($player->id(), $this->players)) {
154 2
            throw  new PlayersCollectionException('Duplicate player: '.$player->email());
155
        }
156
157 10
        return false;
158
    }
159
160
    /**
161
     * @param Player[] $players
162
     * @return bool
163
     */
164 9
    private function areDifferentPlayers(array $players)
165
    {
166 9
        $uniqueIds = [];
167 9
        foreach ($players as $player) {
168 9
            $uniqueIds[] = $player->id();
169 9
        }
170
171 9
        return count($players) == count(array_unique($uniqueIds));
172
    }
173
174
    /**
175
     * @param array $list
176
     * @return array
177
     */
178 1
    private function shuffleAssoc(array $list)
179
    {
180 1
        if (!is_array($list)) return $list;
181
182 1
        $keys = $this->forceShuffle(array_keys($list));
183 1
        $random = [];
184 1
        foreach ($keys as $key) {
185 1
            $random[$key] = $list[$key];
186 1
        }
187
188 1
        return $random;
189
    }
190
191
    /**
192
     * @param array $list
193
     * @return array
194
     */
195 1
    private function forceShuffle(array $list)
196
    {
197 1
        if (!is_array($list) || count($list) < 2) return $list;
198
199 1
        $shuffleList = $list;
200 1
        while ($shuffleList == $list) {
201 1
            shuffle($shuffleList);
202 1
        }
203
204 1
        return $shuffleList;
205
    }
206
}