Skip to content

Instantly share code, notes, and snippets.

@laracasts
Last active December 30, 2023 08:10
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laracasts/6ddc75cdf6e2749da6a1eccc554e9dc3 to your computer and use it in GitHub Desktop.
Save laracasts/6ddc75cdf6e2749da6a1eccc554e9dc3 to your computer and use it in GitHub Desktop.
<?php
namespace App;
class Player
{
/**
* @var string
*/
public string $name;
/**
* @var int
*/
public int $points = 0;
/**
* Create a new player.
*
* @param string $name
*/
public function __construct(string $name)
{
$this->name = $name;
}
/**
* Add a point for the player.
*/
public function score()
{
$this->points++;
}
/**
* Convert the player's score to the Tennis term.
*
* @return string
*/
public function toTerm(): string
{
switch ($this->points) {
case 0:
return 'love';
case 1:
return 'fifteen';
case 2:
return 'thirty';
case 3:
return 'forty';
}
}
}
<?php
namespace App;
class TennisMatch
{
/**
* @var Player
*/
protected Player $playerOne;
/**
* @var Player
*/
protected Player $playerTwo;
/**
* Create a new TennisMatch.
*
* @param Player $playerOne
* @param Player $playerTwo
*/
public function __construct(Player $playerOne, Player $playerTwo)
{
$this->playerOne = $playerOne;
$this->playerTwo = $playerTwo;
}
/**
* Score the match.
*
* @return string
*/
public function score(): string
{
if ($this->hasWinner()) {
return 'Winner: '.$this->leader()->name;
}
if ($this->hasAdvantage()) {
return 'Advantage: '.$this->leader()->name;
}
if ($this->isDeuce()) {
return 'deuce';
}
return sprintf(
"%s-%s",
$this->playerOne->toTerm(),
$this->playerTwo->toTerm(),
);
}
/**
* Get the current leader of the set.
*
* @return Player
*/
protected function leader(): Player
{
return $this->playerOne->points > $this->playerTwo->points
? $this->playerOne
: $this->playerTwo;
}
/**
* Determine if the players are in deuce.
*
* @return bool
*/
protected function isDeuce(): bool
{
if (! $this->hasReachedDeuceThreshold()) {
return false;
}
return $this->playerOne->points === $this->playerTwo->points;
}
/**
* Determine if both players have scored at least 3 points.
*
* @return bool
*/
protected function hasReachedDeuceThreshold(): bool
{
return $this->playerOne->points >= 3 && $this->playerTwo->points >= 3;
}
/**
* Determine if one player has the advantage.
*
* @return bool
*/
protected function hasAdvantage(): bool
{
if (! $this->hasReachedDeuceThreshold()) {
return false;
}
return ! $this->isDeuce();
}
/**
* Determine if there is a winner.
*
* @return bool
*/
protected function hasWinner(): bool
{
if ($this->playerOne->points < 4 && $this->playerTwo->points < 4) {
return false;
}
return abs($this->playerOne->points - $this->playerTwo->points) >= 2;
}
}
<?php
use App\Player;
use App\TennisMatch;
use PHPUnit\Framework\TestCase;
class TennisMatchTest extends TestCase
{
/**
* @test
* @dataProvider scores
*/
function it_scores_a_tennis_match($playerOnePoints, $playerTwoPoints, $score)
{
$match = new TennisMatch(
$john = new Player('John'),
$jane = new Player('Jane'),
);
for ($i = 0; $i < $playerOnePoints; $i++) {
$john->score();
}
for ($i = 0; $i < $playerTwoPoints; $i++) {
$jane->score();
}
$this->assertEquals($score, $match->score());
}
public function scores()
{
return [
[0, 0, 'love-love'],
[1, 0, 'fifteen-love'],
[1, 1, 'fifteen-fifteen'],
[2, 0, 'thirty-love'],
[3, 0, 'forty-love'],
[2, 2, 'thirty-thirty'],
[3, 3, 'deuce'],
[4, 4, 'deuce'],
[5, 5, 'deuce'],
[4, 3, 'Advantage: John'],
[3, 4, 'Advantage: Jane'],
[4, 0, 'Winner: John'],
[0, 4, 'Winner: Jane'],
];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment