php-katas-with-pest/src/BowlingGame.php
2020-07-05 15:50:12 +01:00

89 lines
2 KiB
PHP

<?php
declare(strict_types=1);
namespace App;
use Assert\Assert;
use Tightenco\Collect\Support\Collection;
final class BowlingGame
{
private const MAX_PINS_PER_FRAME = 10;
private const NUMBER_OF_FRAMES = 10;
private Collection $rolls;
public function __construct()
{
$this->rolls = new Collection();
}
public function roll(int $pins): void
{
Assert::that($pins)
->greaterOrEqualThan(0,
'You cannot knock down a negative number of pins. Knocked down %d.')
->lessOrEqualThan(self::MAX_PINS_PER_FRAME,
'You can only knock down a maximum of 10 pins in a roll. Knocked down 12.');
$this->rolls->push($pins);
}
public function getScore(): int
{
$score = 0;
$roll = 0;
foreach (range(1, self::NUMBER_OF_FRAMES) as $frame) {
if ($this->isStrike($roll)) {
$score += $this->rolls[$roll];
$score += $this->bonusForStrike($roll);
$roll += 1;
continue;
}
if ($this->isSpare($roll)) {
$score += $this->defaultFrameScore($roll);
$score += $this->bonusForSpare($roll);
$roll += 2;
continue;
}
$score += $this->defaultFrameScore($roll);
$roll += 2;
}
return $score;
}
private function bonusForSpare(int $roll): int
{
return $this->rolls->get($roll + 2);
}
private function bonusForStrike(int $roll): int
{
return $this->rolls[$roll + 1] + $this->rolls[$roll + 2];
}
private function defaultFrameScore(int $roll): int
{
return $this->rolls[$roll] + $this->rolls[$roll + 1];
}
private function isSpare(int $roll): bool
{
return $this->defaultFrameScore($roll)
== self::MAX_PINS_PER_FRAME;
}
private function isStrike(int $roll): bool
{
return $this->rolls[$roll] == self::MAX_PINS_PER_FRAME;
}
}