Completed
Branch Bowlingkata/Albert (8d392f)
by Albert
06:38
created

BowlingGame::calculateTotalScore()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Kata\BowlingKata;
4
5
final class BowlingGame
6
{
7
    const FRAME_SCORE = 10;
8
    const MAX_FRAMES = 10;
9
10
    private $total_game_score = 0;
11
    private $frames = [];
12
    private $current_frame = 0;
13
    private $rolls = [];
14
    private $current_roll = 0;
15
16
    public function __invoke(array $rolls) : int
17
    {
18
        $this->rolls = $rolls;
19
20
        $this->checkRolls();
21
22
        return $this->calculateTotalScore();
23
    }
24
25
    private function checkRolls()
26
    {
27
        foreach ($this->rolls as $roll_order => $roll_mark)
28
        {
29
            $current_roll_full_score              = $this->calculateFullRollScore($roll_mark, $roll_order);
30
            $this->frames[$this->current_frame][] = $current_roll_full_score;
31
32
            if ($this->current_frame < self::MAX_FRAMES)
33
            {
34
                $this->total_game_score += $current_roll_full_score;
35
            }
36
37
            if ($this->isSecondTryInFrame() || RollValue::STRIKE == $roll_mark || RollValue::SPARE == $roll_mark)
38
            {
39
                $this->current_frame++;
40
            }
41
42
            $this->current_roll++;
43
        }
44
    }
45
46
    private function calculateSimpleRollScore($roll_mark, $roll_order):int
47
    {
48
        if ($roll_mark == RollValue::SPARE)
49
        {
50
            return self::FRAME_SCORE - $this->rolls[$roll_order - 1];
51
        }
52
53
        return RollValue::fromChar($roll_mark)->value();
54
    }
55
56
    private function calculateFullRollScore($roll_mark, $roll_order)
57
    {
58
        $current_roll_simple_score = $this->calculateSimpleRollScore($roll_mark, $roll_order);
59
60
        if (!in_array($roll_mark, [RollValue::SPARE, RollValue::STRIKE]))
61
        {
62
            return $current_roll_simple_score;
63
        }
64
65
        if ($roll_mark == RollValue::SPARE)
66
        {
67
            $current_roll_simple_score += (!empty($this->rolls[$roll_order + 1])) ? $this->calculateSimpleRollScore($this->rolls[$roll_order + 1], $roll_order + 1) : 0;
68
69
            return $current_roll_simple_score;
70
        }
71
72
        if ($roll_mark == RollValue::STRIKE)
73
        {
74
            $current_roll_simple_score += (!empty($this->rolls[$roll_order + 1])) ? $this->calculateSimpleRollScore($this->rolls[$roll_order + 1], $roll_order + 1) : 0;
75
            $current_roll_simple_score += (!empty($this->rolls[$roll_order + 2])) ? $this->calculateSimpleRollScore($this->rolls[$roll_order + 2], $roll_order + 2) : 0;
76
77
            return $current_roll_simple_score;
78
        }
79
80
        throw new \InvalidArgumentException($roll_mark . ' is an invalid roll.');
81
    }
82
83
    private function calculateTotalScore() : int
84
    {
85
        return $this->total_game_score;
86
    }
87
88
    private function isSecondTryInFrame()
89
    {
90
        return 2 == count($this->frames[$this->current_frame]);
91
    }
92
}
93