diff --git a/README.md b/README.md index ea0b7e1..de965dd 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,14 @@ [![Build Status](https://travis-ci.org/GuilleGF/SecretSantaPHP.svg?branch=master)](https://travis-ci.org/GuilleGF/SecretSantaPHP) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/GuilleGF/SecretSantaPHP/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/GuilleGF/SecretSantaPHP/?branch=master) +[![Code Coverage](https://scrutinizer-ci.com/g/GuilleGF/SecretSantaPHP/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/GuilleGF/SecretSantaPHP/?branch=master) +[![Dependency Status](https://www.versioneye.com/user/projects/5821ae0d89f0a91d55eb9600/badge.svg)](https://www.versioneye.com/user/projects/5821ae0d89f0a91d55eb9600) [![Latest Stable Version](https://poser.pugx.org/guillegf/secret-santa/v/stable)](https://packagist.org/packages/guillegf/secret-santa) [![Total Downloads](https://poser.pugx.org/guillegf/secret-santa/downloads)](https://packagist.org/packages/guillegf/secret-santa) [![License](https://poser.pugx.org/guillegf/secret-santa/license)](https://packagist.org/packages/guillegf/secret-santa) * Repository: https://github.com/GuilleGF/SecretSantaPHP -* Version: 1.0.3 +* Version: 1.1.0 * License: MIT, see [LICENSE](LICENSE) ## Description @@ -29,13 +31,13 @@ documentation. To add this dependency using the command, run the following from within your project directory: ``` -composer require guillegf/secret-santa "~1.0" +composer require guillegf/secret-santa "~1.1" ``` Alternatively, add the dependency directly to your `composer.json` file: ```json "require": { - "guillegf/secret-santa": "~1.0" + "guillegf/secret-santa": "~1.1" } ``` ## Usage @@ -43,14 +45,13 @@ Alternatively, add the dependency directly to your `composer.json` file: ```php addPlayer('Player', 'player@email.com') - ->addCouple('Player2', 'player2@email.com', 'Couple2', 'couple2@email.com') +$secretSanta->addPlayer('Player', 'player@email.com') + ->addPlayer('Player2', 'player2@email.com') ->addCouple('Player3', 'player3@email.com', 'Couple3', 'couple3@email.com') - ->play(); + ->addCouple('Player4', 'player4@email.com', 'Couple4', 'couple4@email.com'); -foreach ($secretSantaPlayers as $player) { - echo ("{$player['name']} {$player['email']}: {$player['secretSanta']}\n"); +foreach ($secretSanta->play() as $player) { + echo ("{$player->name()} ({$player->email()}): {$player->secretSanta()->name()}\n"); } ``` diff --git a/src/PlayersCollection.php b/src/PlayersCollection.php index 635d9d1..c450328 100644 --- a/src/PlayersCollection.php +++ b/src/PlayersCollection.php @@ -48,6 +48,14 @@ public function players() return $this->players; } + /** + * @return Player[] + */ + public function shufflePlayers() + { + return $this->shuffleAssoc($this->players); + } + /** * @param string $id * @return Player @@ -117,6 +125,39 @@ private function isDuplicatePlayer(Player $player) return false; } + /** + * @param array $list + * @return array + */ + private function shuffleAssoc($list) + { + if (!is_array($list)) return $list; + + $keys = $this->forceShuffle(array_keys($list)); + $random = []; + foreach ($keys as $key) { + $random[$key] = $list[$key]; + } + + return $random; + } + + /** + * @param array $list + * @return array + */ + private function forceShuffle($list) + { + if (!is_array($list) || count($list) < 2) return $list; + + $shuffleList = $list; + while ($shuffleList == $list) { + shuffle($shuffleList); + } + + return $shuffleList; + } + /** * @return Player */ diff --git a/src/SecretSanta.php b/src/SecretSanta.php index 100ac7f..6864161 100644 --- a/src/SecretSanta.php +++ b/src/SecretSanta.php @@ -53,25 +53,24 @@ public function addCouple($name, $email, $coupleName, $coupleEmail) } /** - * @return array + * @return PlayersCollection + * @throws SecretSantaException */ public function play() { - $this->combinePlayers(); + try { + $this->combinePlayers(); - $result = []; - if ($this->isValidCombination()) { - foreach ($this->combination as $playerId => $secretPlayerId) { - $player = $this->players->player($playerId); - $result[] = [ - 'name' => $player->name(), - 'email' => $player->email(), - 'secretSanta' => $this->players->player($secretPlayerId)->name() - ]; - } + return $this->players; + } catch (SecretSantaException $exception) { + throw $exception; + } catch (\Exception $exception) { + throw new SecretSantaException( + 'Error during play, impossible to find secret santa, try again', + 0, + $exception + ); } - - return $result; } /** @@ -79,29 +78,31 @@ public function play() */ private function combinePlayers() { - $retry = 0; - $this->combination = []; + if (count($this->players) < 4) { + throw new SecretSantaException("Not enough players to play, at least 4 players are required"); + } + + $retry = count($this->players) + $this->players->countExcludePlayers(); - while (!$this->isValidCombination() && $retry < (count($this->players)*2)) { - $retry++; - $players = $this->players->players(); - $secretPlayers = $this->players->players(); - shuffle($players); - shuffle($secretPlayers); - foreach ($players as $player) { - foreach ($secretPlayers as $key => $secretPlayer) { + while (!$this->isValidCombination() && $retry > 0 ) { + $this->combination = []; + $secretPlayers = $this->players->shufflePlayers(); + foreach ($this->players as $playerId => $player) { + foreach ($secretPlayers as $secretPlayer) { if ($player->id() != $secretPlayer->id() && !$this->players->areExclude($player, $secretPlayer)) { if (!in_array($secretPlayer->id(), $this->combination)) { + $player->setSecretSanta($secretPlayer); $this->combination[$player->id()] = $secretPlayer->id(); - unset ($secretPlayers[$key]); + unset ($secretPlayers[$secretPlayer->id()]); break; } } } } + $retry--; } - if (!$this->isValidCombination()) { + if (!$this->isValidCombination() && $retry <= 0) { throw new SecretSantaException("Not enough players to play"); } } diff --git a/tests/PlayerTest.php b/tests/PlayerTest.php index b9f2b88..ed38474 100644 --- a/tests/PlayerTest.php +++ b/tests/PlayerTest.php @@ -15,6 +15,14 @@ public function testSortName() Player::create('ab', 'email@email.com'); } + /** + * @expectedException \SecretSanta\Exceptions\PlayerException + */ + public function testInvalidName() + { + Player::create([], 'email@email.com'); + } + /** * @expectedException \SecretSanta\Exceptions\PlayerException */ @@ -31,4 +39,24 @@ public function testPlayer() $this->assertSame('name', $player->name()); $this->assertSame('email@email.com', $player->email()); } + + public function testAddSecretSantaToPlayer() + { + $player = Player::create('name', 'email@email.com'); + $secretSanta = Player::create('name', 'email@email.com'); + + $player->setSecretSanta($secretSanta); + + $this->assertSame($secretSanta, $player->secretSanta()); + } + + /** + * @expectedException \SecretSanta\Exceptions\PlayerException + */ + public function testGetSecretSantaBeforeAddToPlayer() + { + $player = Player::create('name', 'email@email.com'); + + $player->secretSanta(); + } } diff --git a/tests/PlayersCollectionTest.php b/tests/PlayersCollectionTest.php index 1a66563..00d3503 100644 --- a/tests/PlayersCollectionTest.php +++ b/tests/PlayersCollectionTest.php @@ -20,6 +20,18 @@ public function testAddPlayer() $this->assertSame($expectedPlayer, $player); } + /** + * @expectedException \SecretSanta\Exceptions\PlayersCollectionException + */ + public function testGetUnKnowPlayer() + { + $expectedPlayer = Player::create('name', 'email@email.com'); + $playersCollection = new PlayersCollection(); + $playersCollection->addPlayer($expectedPlayer); + + $playersCollection->player('error-id'); + } + /** * @expectedException \SecretSanta\Exceptions\PlayersCollectionException */ @@ -46,4 +58,31 @@ public function testAddCouple() $this->assertSame($expectedPlayer, $player); $this->assertSame($expectedCouple, $couple); } + + public function testShufflePlayers() + { + $expectedPlayer = Player::create('name', 'email@email.com'); + $expectedCouple = Player::create('nameCouple', 'emailCouple@email.com'); + + $playersCollection = new PlayersCollection(); + $playersCollection->addCouple($expectedPlayer, $expectedCouple); + + $shufflePlayers = $playersCollection->shufflePlayers(); + + $this->assertNotEquals(array_keys($playersCollection->players()), array_keys($shufflePlayers)); + } + + public function testExcludePlayers() + { + $expectedSinglePlayer = Player::create('nameSingle', 'emailSingle@email.com'); + $expectedPlayer = Player::create('name', 'email@email.com'); + $expectedCouple = Player::create('nameCouple', 'emailCouple@email.com'); + + $playersCollection = new PlayersCollection(); + $playersCollection->addCouple($expectedPlayer, $expectedCouple); + + $this->assertTrue($playersCollection->areExclude($expectedPlayer, $expectedCouple)); + $this->assertFalse($playersCollection->areExclude($expectedSinglePlayer, $expectedPlayer)); + $this->assertSame(2, $playersCollection->countExcludePlayers()); + } } \ No newline at end of file diff --git a/tests/SecretSantaTest.php b/tests/SecretSantaTest.php index c35f0a9..5f720a1 100644 --- a/tests/SecretSantaTest.php +++ b/tests/SecretSantaTest.php @@ -59,4 +59,34 @@ public function testFourCouplesAndTwoPlayers() $this->assertSame(10 , count($combination)); } + + public function testTenCouplesAndTenPlayers() + { + $secretSanta = new SecretSanta(); + + $secretSanta->addPlayer('Player', 'player@email.com'); + $secretSanta->addPlayer('Player2', 'player2@email.com'); + $secretSanta->addCouple('Player3', 'player3@email.com', 'Couple3', 'couple3@email.com'); + $secretSanta->addCouple('Player4', 'player4@email.com', 'Couple4', 'couple4@email.com'); + $secretSanta->addCouple('Player5', 'player5@email.com', 'Couple5', 'couple5@email.com'); + $secretSanta->addCouple('Player6', 'player6@email.com', 'Couple6', 'couple6@email.com'); + $secretSanta->addPlayer('Player7', 'player7@email.com'); + $secretSanta->addPlayer('Player8', 'player8@email.com'); + $secretSanta->addPlayer('Player9', 'player9@email.com'); + $secretSanta->addPlayer('Player10', 'player10@email.com'); + $secretSanta->addPlayer('Player11', 'player11@email.com'); + $secretSanta->addPlayer('Player12', 'player12@email.com'); + $secretSanta->addCouple('Player13', 'player13@email.com', 'Couple13', 'couple13@email.com'); + $secretSanta->addCouple('Player14', 'player14@email.com', 'Couple14', 'couple14@email.com'); + $secretSanta->addCouple('Player15', 'player15@email.com', 'Couple15', 'couple15@email.com'); + $secretSanta->addCouple('Player16', 'player16@email.com', 'Couple16', 'couple16@email.com'); + $secretSanta->addPlayer('Player17', 'player17@email.com'); + $secretSanta->addPlayer('Player18', 'player18@email.com'); + $secretSanta->addCouple('Player19', 'player19@email.com', 'Couple19', 'couple19@email.com'); + $secretSanta->addCouple('Player20', 'player20@email.com', 'Couple20', 'couple20@email.com'); + + $combination = $secretSanta->play(); + + $this->assertSame(30 , count($combination)); + } }