Rock, paper, scissors

Fixes #1
This commit is contained in:
Oliver Davies 2020-07-10 23:15:10 +01:00
parent ae5f58c8c7
commit 3171da146f
3 changed files with 150 additions and 0 deletions

View file

@ -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

View 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.'
);
}
}

View 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']);