Direction   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 127
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 94.29%

Importance

Changes 0
Metric Value
wmc 12
lcom 1
cbo 1
dl 0
loc 127
ccs 33
cts 35
cp 0.9429
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A setDirectionFromString() 0 8 1
A northward() 0 4 1
A eastward() 0 4 1
A westward() 0 4 1
A southward() 0 4 1
A rotateLeft() 0 8 1
A rotateRight() 0 8 1
A getDirectionAsVector() 0 4 1
A getDirectionAsString() 0 14 3
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 16
    public function __construct(?string $startingDirection = 'E')
53
    {
54
        // Normalise
55 16
        $startingDirection = strtoupper(trim($startingDirection));
56
57 16
        Assertion::choice($startingDirection, ['N', 'S', 'E', 'W']);
58
59 15
        $this->setDirectionFromString($startingDirection);
60
61 15
        $this->leftTransform = MatrixFactory::create(self::ROTATE_LEFT_MATRIX);
62 15
        $this->rightTransform = MatrixFactory::create(self::ROTATE_RIGHT_MATRIX);
63 15
    }
64
65
    /**
66
     * @param string $direction
67
     * @return Direction
68
     */
69 15
    private function setDirectionFromString(string $direction): Direction
70
    {
71 15
        $this->direction = new Vector(
72 15
            self::CHAR_VECTOR_MAPPING[$direction]
73
        );
74
75 15
        return $this;
76
    }
77
78 2
    public function northward(): Vector
79
    {
80 2
        return $this->setDirectionFromString('N')->getDirectionAsVector();
81
    }
82
83 1
    public function eastward(): Vector
84
    {
85 1
        return $this->setDirectionFromString('E')->getDirectionAsVector();
86
    }
87
88 2
    public function westward(): Vector
89
    {
90 2
        return $this->setDirectionFromString('W')->getDirectionAsVector();
91
    }
92
93 2
    public function southward(): Vector
94
    {
95 2
        return $this->setDirectionFromString('S')->getDirectionAsVector();
96
    }
97
98
    /**
99
     * @return Direction
100
     */
101 2
    public function rotateLeft(): Direction
102
    {
103 2
        $this->direction = $this->leftTransform->vectorMultiply(
104 2
            $this->direction
105
        );
106
107 2
        return $this;
108
    }
109
110
    /**
111
     * @return Direction
112
     */
113 2
    public function rotateRight()
114
    {
115 2
        $this->direction = $this->rightTransform->vectorMultiply(
116 2
            $this->direction
117
        );
118
119 2
        return $this;
120
    }
121
122
    /**
123
     * @return Vector
124
     */
125 5
    public function getDirectionAsVector(): Vector
126
    {
127 5
        return $this->direction;
128
    }
129
130
    /**
131
     * @return string
132
     * @throws \LogicException
133
     */
134 10
    public function getDirectionAsString(): string
135
    {
136 10
        foreach (self::CHAR_VECTOR_MAPPING as $char => $coords) {
137
            // Array equality === same key, value pairs in the same
138
            // order (no type casting)
139 10
            if ($coords === $this->direction->getVector()) {
140 10
                return $char;
141
            }
142
        }
143
144
        throw new \LogicException(
145
            'Unable to find the direction char from the vector'
146
        );
147
    }
148
}
149