Completed
Push — master ( fbabbd...8184b0 )
by Douglas
01:43
created

Direction   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 88.57%

Importance

Changes 0
Metric Value
wmc 12
lcom 1
cbo 1
dl 0
loc 124
ccs 31
cts 35
cp 0.8857
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A setDirectionFromString() 0 6 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 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 2
    public function northward(): Vector
76
    {
77 2
        return new Vector(self::CHAR_VECTOR_MAPPING['N']);
78
    }
79
80 1
    public function eastward(): Vector
81
    {
82 1
        return new Vector(self::CHAR_VECTOR_MAPPING['E']);
83
    }
84
85 2
    public function westward(): Vector
86
    {
87 2
        return new Vector(self::CHAR_VECTOR_MAPPING['W']);
88
    }
89
90 2
    public function southward(): Vector
91
    {
92 2
        return new Vector(self::CHAR_VECTOR_MAPPING['S']);
93
    }
94
95
    /**
96
     * @return Direction
97
     */
98 1
    public function rotateLeft(): Direction
99
    {
100 1
        $this->direction = $this->leftTransform->vectorMultiply(
101 1
            $this->direction
102
        );
103
104 1
        return $this;
105
    }
106
107
    /**
108
     * @return Direction
109
     */
110 1
    public function rotateRight()
111
    {
112 1
        $this->direction = $this->rightTransform->vectorMultiply(
113 1
            $this->direction
114
        );
115
116 1
        return $this;
117
    }
118
119
    /**
120
     * @return Vector
121
     */
122
    public function getDirectionAsVector(): Vector
123
    {
124
        return $this->direction;
125
    }
126
127
    /**
128
     * @return string
129
     * @throws \LogicException
130
     */
131 2
    public function getDirectionAsString(): string
132
    {
133 2
        foreach (self::CHAR_VECTOR_MAPPING as $char => $coords) {
134
            // Array equality === same key, value pairs in the same
135
            // order (no type casting)
136 2
            if ($coords === $this->direction->getVector()) {
137 2
                return $char;
138
            }
139
        }
140
141
        throw new \LogicException(
142
            'Unable to find the direction char from the vector'
143
        );
144
    }
145
}
146