parent
ae5f58c8c7
commit
3171da146f
|
@ -8,6 +8,7 @@ Includes:
|
||||||
- **Bob**: returns different responses based on input.
|
- **Bob**: returns different responses based on input.
|
||||||
- **Bowling**: calculate the score for a game of bowling.
|
- **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.
|
- **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.
|
- **Roman numerals**: convert a number into its roman numeral value.
|
||||||
|
|
||||||
[exercism.io]: https://exercism.io
|
[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