DomainLogic   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 119
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 17
eloc 42
c 1
b 0
f 0
dl 0
loc 119
ccs 43
cts 43
cp 1
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A euclideanDistance() 0 6 1
A generatePositions() 0 11 3
A calculateEstimatedCost() 0 3 1
A calculateAdjacentBoundaries() 0 27 5
A calculateRealCost() 0 7 2
A __construct() 0 8 1
A getAdjacentNodes() 0 17 4
1
<?php
2
3
namespace JMGQ\AStar\Example\Terrain;
4
5
use JMGQ\AStar\DomainLogicInterface;
6
7
/**
8
 * @implements DomainLogicInterface<Position>
9
 */
10
class DomainLogic implements DomainLogicInterface
11
{
12
    private TerrainCost $terrainCost;
13
    /** @var Position[][] */
14
    private array $positions;
15
16 15
    public function __construct(TerrainCost $terrainCost)
17
    {
18 15
        $this->terrainCost = $terrainCost;
19
20
        // We store all the Position objects in a matrix for efficiency, so that we don't need to create new Position
21
        // instances every time we call "getAdjacentNodes". If we created new positions with every call, the algorithm
22
        // would still work correctly but it would be a bit slower.
23 15
        $this->positions = $this->generatePositions($terrainCost);
24 15
    }
25
26
    /**
27
     * @param Position $node
28
     * @return Position[]
29
     */
30 10
    public function getAdjacentNodes(mixed $node): iterable
31
    {
32 10
        $adjacentNodes = [];
33
34 10
        [$startingRow, $endingRow, $startingColumn, $endingColumn] = $this->calculateAdjacentBoundaries($node);
35
36 10
        for ($row = $startingRow; $row <= $endingRow; $row++) {
37 10
            for ($column = $startingColumn; $column <= $endingColumn; $column++) {
38 10
                $adjacentNode = $this->positions[$row][$column];
39
40 10
                if (!$node->isEqualTo($adjacentNode)) {
41 10
                    $adjacentNodes[] = $adjacentNode;
42
                }
43
            }
44
        }
45
46 10
        return $adjacentNodes;
47
    }
48
49
    /**
50
     * @param Position $node
51
     * @param Position $adjacent
52
     * @return float|int
53
     */
54 8
    public function calculateRealCost(mixed $node, mixed $adjacent): float | int
55
    {
56 8
        if ($node->isAdjacentTo($adjacent)) {
57 7
            return $this->terrainCost->getCost($adjacent->getRow(), $adjacent->getColumn());
58
        }
59
60 1
        return TerrainCost::INFINITE;
61
    }
62
63
    /**
64
     * @param Position $fromNode
65
     * @param Position $toNode
66
     * @return float|int
67
     */
68 8
    public function calculateEstimatedCost(mixed $fromNode, mixed $toNode): float | int
69
    {
70 8
        return $this->euclideanDistance($fromNode, $toNode);
71
    }
72
73 8
    private function euclideanDistance(Position $a, Position $b): float
74
    {
75 8
        $rowFactor = ($a->getRow() - $b->getRow()) ** 2;
76 8
        $columnFactor = ($a->getColumn() - $b->getColumn()) ** 2;
77
78 8
        return sqrt($rowFactor + $columnFactor);
79
    }
80
81
    /**
82
     * @param Position $position
83
     * @return int[]
84
     */
85 10
    private function calculateAdjacentBoundaries(Position $position): array
86
    {
87 10
        if ($position->getRow() === 0) {
88 8
            $startingRow = 0;
89
        } else {
90 8
            $startingRow = $position->getRow() - 1;
91
        }
92
93 10
        if ($position->getRow() === $this->terrainCost->getTotalRows() - 1) {
94 5
            $endingRow = $position->getRow();
95
        } else {
96 9
            $endingRow = $position->getRow() + 1;
97
        }
98
99 10
        if ($position->getColumn() === 0) {
100 8
            $startingColumn = 0;
101
        } else {
102 8
            $startingColumn = $position->getColumn() - 1;
103
        }
104
105 10
        if ($position->getColumn() === $this->terrainCost->getTotalColumns() - 1) {
106 4
            $endingColumn = $position->getColumn();
107
        } else {
108 9
            $endingColumn = $position->getColumn() + 1;
109
        }
110
111 10
        return [$startingRow, $endingRow, $startingColumn, $endingColumn];
112
    }
113
114
    /**
115
     * @param TerrainCost $terrainCost
116
     * @return Position[][]
117
     */
118 15
    private function generatePositions(TerrainCost $terrainCost): array
119
    {
120 15
        $positions = [];
121
122 15
        for ($row = 0; $row < $terrainCost->getTotalRows(); $row++) {
123 15
            for ($column = 0; $column < $terrainCost->getTotalColumns(); $column++) {
124 15
                $positions[$row][$column] = new Position($row, $column);
125
            }
126
        }
127
128 15
        return $positions;
129
    }
130
}
131