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

Direction   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 104
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 85.19%

Importance

Changes 0
Metric Value
wmc 8
lcom 1
cbo 1
dl 0
loc 104
ccs 23
cts 27
cp 0.8519
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A setDirectionFromString() 0 6 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
    /**
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