Completed
Push — master ( af3c22...fbabbd )
by Douglas
01:45
created

Direction::rotateRight()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
crap 1
1
<?php
2
3
/**
4
 * (c) 2018 Douglas Reith.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
declare(strict_types=1);
10
11
namespace Reith\ToyRobot\Domain\Robot;
12
13
use Assert\Assertion;
14
use MathPHP\LinearAlgebra\MatrixFactory;
15
use MathPHP\LinearAlgebra\Vector;
16
17
/**
18
 * Manage robot direction.
19
 *
20
 * Matrix multiplication gives us the new direction.
21
 */
22
class Direction
23
{
24
    // Counter clockwise
25
    private const ROTATE_LEFT_MATRIX = [
26
        [0, -1],
27
        [1, 0]
28
    ];
29
30
    // Clockwise
31
    private const ROTATE_RIGHT_MATRIX = [
32
        [0, 1],
33
        [-1, 0]
34
    ];
35
36
    private const CHAR_VECTOR_MAPPING = [
37
        'N' => [0, 1],
38
        'E' => [1, 0],
39
        'S' => [0, -1],
40
        'W' => [-1, 0],
41
    ];
42
43
    private $leftTransform;
44
45
    private $rightTransform;
46
47
    private $direction;
48
49
    /**
50
     * @param string|null $startingDirection
51
     */
52 11
    public function __construct(?string $startingDirection = 'E')
53
    {
54
        // Normalise
55 11
        $startingDirection = strtoupper(trim($startingDirection));
56
57 11
        Assertion::choice($startingDirection, ['N', 'S', 'E', 'W']);
58
59 10
        $this->setDirectionFromString($startingDirection);
60
61 10
        $this->leftTransform = MatrixFactory::create(self::ROTATE_LEFT_MATRIX);
62 10
        $this->rightTransform = MatrixFactory::create(self::ROTATE_RIGHT_MATRIX);
63 10
    }
64
65
    /**
66
     * @param string $direction
67
     */
68 10
    private function setDirectionFromString(string $direction): void
69
    {
70 10
        $this->direction = new Vector(
71 10
            self::CHAR_VECTOR_MAPPING[$direction]
72
        );
73 10
    }
74
75
    /**
76
     * @return Direction
77
     */
78 1
    public function rotateLeft(): Direction
79
    {
80 1
        $this->direction = $this->leftTransform->vectorMultiply(
81 1
            $this->direction
82
        );
83
84 1
        return $this;
85
    }
86
87
    /**
88
     * @return Direction
89
     */
90 1
    public function rotateRight()
91
    {
92 1
        $this->direction = $this->rightTransform->vectorMultiply(
93 1
            $this->direction
94
        );
95
96 1
        return $this;
97
    }
98
99
    /**
100
     * @return Vector
101
     */
102
    public function getDirectionAsVector(): Vector
103
    {
104
        return $this->direction;
105
    }
106
107
    /**
108
     * @return string
109
     * @throws \LogicException
110
     */
111 2
    public function getDirectionAsString(): string
112
    {
113 2
        foreach (self::CHAR_VECTOR_MAPPING as $char => $coords) {
114
            // Array equality === same key, value pairs in the same
115
            // order (no type casting)
116 2
            if ($coords === $this->direction->getVector()) {
117 2
                return $char;
118
            }
119
        }
120
121
        throw new \LogicException(
122
            'Unable to find the direction char from the vector'
123
        );
124
    }
125
}
126