parent
ae5f58c8c7
commit
3171da146f
|
@ -8,6 +8,7 @@ Includes:
|
|||
- **Bob**: returns different responses based on input.
|
||||
- **Bowling**: calculate the score for a game of bowling.
|
||||
- **Grade School**: given students' names along with the grade that they are in, create a roster for the school.
|
||||
- **Rock, paper, scissors**
|
||||
- **Roman numerals**: convert a number into its roman numeral value.
|
||||
|
||||
[exercism.io]: https://exercism.io
|
||||
|
|
77
src/RockPaperScissorsGame.php
Normal file
77
src/RockPaperScissorsGame.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Assert\Assert;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
|
||||
class RockPaperScissorsGame
|
||||
{
|
||||
private const MOVE_ROCK = 'rock';
|
||||
private const MOVE_PAPER = 'paper';
|
||||
private const MOVE_SCISSORS = 'scissors';
|
||||
|
||||
private static array $possibleMoves = [
|
||||
[
|
||||
'moves' => [self::MOVE_ROCK, self::MOVE_PAPER],
|
||||
'winner' => self::MOVE_PAPER,
|
||||
],
|
||||
[
|
||||
'moves' => [self::MOVE_ROCK, self::MOVE_SCISSORS],
|
||||
'winner' => self::MOVE_SCISSORS,
|
||||
],
|
||||
[
|
||||
'moves' => [self::MOVE_PAPER, self::MOVE_SCISSORS],
|
||||
'winner' => self::MOVE_SCISSORS,
|
||||
],
|
||||
];
|
||||
|
||||
private Collection $moves;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->moves = new Collection();
|
||||
}
|
||||
|
||||
public function firstMove(string $move): self
|
||||
{
|
||||
$this->validateMoveIsValid($move);
|
||||
$this->moves[0] = $move;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function secondMove(string $move): self
|
||||
{
|
||||
$this->validateMoveIsValid($move);
|
||||
$this->moves[1] = $move;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWinner(): ?string
|
||||
{
|
||||
if ($this->moves[0] == $this->moves[1]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$move = (new Collection(self::$possibleMoves))
|
||||
->first(function (array $move): bool {
|
||||
// Determine if the played moves match this combination of
|
||||
// possible moves.
|
||||
return $this->moves->diff($move['moves'])->isEmpty();
|
||||
});
|
||||
|
||||
return $move['winner'];
|
||||
}
|
||||
|
||||
private function validateMoveIsValid(string $move): void
|
||||
{
|
||||
Assert::that($move)
|
||||
->notEmpty('You must specify a move.')
|
||||
->inArray(
|
||||
[self::MOVE_ROCK, self::MOVE_PAPER, self::MOVE_SCISSORS],
|
||||
'You must enter a valid move. %s given.'
|
||||
);
|
||||
}
|
||||
}
|
72
tests/RockPaperScissorsTest.php
Normal file
72
tests/RockPaperScissorsTest.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
use Assert\AssertionFailedException;
|
||||
|
||||
beforeEach(function () {
|
||||
$this->game = new App\RockPaperScissorsGame();
|
||||
});
|
||||
|
||||
it('throws an exception for an empty first move', function () {
|
||||
$this->game->firstMove('');
|
||||
})->throws(AssertionFailedException::class, 'You must specify a move.');
|
||||
|
||||
it('throws an exception for an empty second move', function () {
|
||||
$this->game->secondMove('');
|
||||
})->throws(AssertionFailedException::class, 'You must specify a move.');
|
||||
|
||||
it('throws an exception if an invalid first move is entered', function () {
|
||||
$this->game->firstMove('banana');
|
||||
})->throws(AssertionFailedException::class, 'You must enter a valid move. banana given.');
|
||||
|
||||
it('throws an exception if an invalid second move is entered', function () {
|
||||
$this->game->secondMove('apple');
|
||||
})->throws(AssertionFailedException::class, 'You must enter a valid move. apple given.');
|
||||
|
||||
it('returns the result of two different valid moves', function (
|
||||
string $firstMove,
|
||||
string $secondMove,
|
||||
string $winner
|
||||
) {
|
||||
$this->game
|
||||
->firstMove($firstMove)
|
||||
->secondMove($secondMove);
|
||||
|
||||
assertSame($winner, $this->game->getWinner());
|
||||
})->with([
|
||||
[
|
||||
'firstMove' => 'rock',
|
||||
'secondMove' => 'paper',
|
||||
'winner' => 'paper',
|
||||
],
|
||||
[
|
||||
'firstMove' => 'paper',
|
||||
'secondMove' => 'rock',
|
||||
'winner' => 'paper',
|
||||
],
|
||||
[
|
||||
'firstMove' => 'rock',
|
||||
'secondMove' => 'scissors',
|
||||
'winner' => 'scissors',
|
||||
],
|
||||
[
|
||||
'firstMove' => 'scissors',
|
||||
'secondMove' => 'rock',
|
||||
'winner' => 'scissors',
|
||||
],
|
||||
[
|
||||
'firstMove' => 'scissors',
|
||||
'secondMove' => 'paper',
|
||||
'winner' => 'scissors',
|
||||
],
|
||||
[
|
||||
'firstMove' => 'paper',
|
||||
'secondMove' => 'scissors',
|
||||
'winner' => 'scissors',
|
||||
],
|
||||
]);
|
||||
|
||||
test('it returns null if there is a tie', function (string $move) {
|
||||
$this->game->firstMove($move)->secondMove($move);
|
||||
|
||||
assertNull($this->game->getWinner());
|
||||
})->with(['rock', 'paper', 'scissors']);
|
Loading…
Reference in a new issue