TerrainCost   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 114
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 18
eloc 35
dl 0
loc 114
ccs 41
cts 41
cp 1
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A isEmpty() 0 9 2
A getTotalColumns() 0 3 1
A getTotalRows() 0 3 1
A __construct() 0 13 3
A getCost() 0 7 2
A convertToNumericArray() 0 9 2
A validateTerrainCosts() 0 18 4
A isRectangular() 0 12 3
1
<?php
2
3
namespace JMGQ\AStar\Example\Terrain;
4
5
class TerrainCost
6
{
7
    public const INFINITE = PHP_INT_MAX;
8
9
    /** @var int[][] */
10
    private array $terrainCost;
11
12
    /**
13
     * @param int[][] $terrainCost
14
     */
15 55
    public function __construct(array $terrainCost)
16
    {
17 55
        if (self::isEmpty($terrainCost)) {
18 2
            throw new \InvalidArgumentException('The terrain costs array is empty');
19
        }
20
21 53
        if (!self::isRectangular($terrainCost)) {
22 3
            throw new \InvalidArgumentException('The terrain costs array is not rectangular');
23
        }
24
25 50
        $terrainCost = self::convertToNumericArray($terrainCost);
26
27 50
        $this->terrainCost = self::validateTerrainCosts($terrainCost);
28 48
    }
29
30 13
    public function getCost(int $row, int $column): int
31
    {
32 13
        if (!isset($this->terrainCost[$row][$column])) {
33 2
            throw new \InvalidArgumentException("Invalid tile: $row, $column");
34
        }
35
36 11
        return $this->terrainCost[$row][$column];
37
    }
38
39 22
    public function getTotalRows(): int
40
    {
41 22
        return count($this->terrainCost);
42
    }
43
44 22
    public function getTotalColumns(): int
45
    {
46 22
        return count($this->terrainCost[0]);
47
    }
48
49
    /**
50
     * @param int[][] $terrainCost
51
     * @return bool
52
     */
53 55
    private static function isEmpty(array $terrainCost): bool
54
    {
55 55
        if (!empty($terrainCost)) {
56 54
            $firstRow = reset($terrainCost);
57
58 54
            return empty($firstRow);
59
        }
60
61 1
        return true;
62
    }
63
64
    /**
65
     * @param mixed[][] $terrain
66
     * @return int[][]
67
     */
68 50
    private static function validateTerrainCosts(array $terrain): array
69
    {
70 50
        $validTerrain = [];
71
72 50
        foreach ($terrain as $row => $rowValues) {
73
            /** @psalm-suppress MixedAssignment PSalm is unable to determine that $value is of mixed type */
74 50
            foreach ($rowValues as $column => $value) {
75 50
                $integerValue = filter_var($value, FILTER_VALIDATE_INT);
76
77 50
                if ($integerValue === false) {
78 2
                    throw new \InvalidArgumentException('Invalid terrain cost: ' . print_r($value, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($value, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

78
                    throw new \InvalidArgumentException('Invalid terrain cost: ' . /** @scrutinizer ignore-type */ print_r($value, true));
Loading history...
79
                }
80
81 48
                $validTerrain[$row][$column] = $integerValue;
82
            }
83
        }
84
85 48
        return $validTerrain;
86
    }
87
88
    /**
89
     * @param int[][] $associativeArray
90
     * @return int[][]
91
     */
92 50
    private static function convertToNumericArray(array $associativeArray): array
93
    {
94 50
        $numericArray = [];
95
96 50
        foreach ($associativeArray as $row) {
97 50
            $numericArray[] = array_values($row);
98
        }
99
100 50
        return $numericArray;
101
    }
102
103
    /**
104
     * @param int[][] $terrain
105
     * @return bool
106
     */
107 53
    private static function isRectangular(array $terrain): bool
108
    {
109
        // @phpstan-ignore-next-line reset won't return false as we have already checked that the terrain is not empty
110 53
        $numberOfColumnsInFirstRow = count(reset($terrain));
111
112 53
        foreach ($terrain as $row) {
113 53
            if (count($row) !== $numberOfColumnsInFirstRow) {
114 3
                return false;
115
            }
116
        }
117
118 50
        return true;
119
    }
120
}
121