GraphEnvironment::determineEdgeCostsAs()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php declare(strict_types=1);
2
3
namespace Stratadox\Pathfinder\Graph\Builder;
4
5
use function array_merge;
6
use InvalidArgumentException;
7
use Stratadox\Pathfinder\Environment;
8
use Stratadox\Pathfinder\Graph\GeometricGraph;
9
use Stratadox\Pathfinder\Graph\Location;
10
use Stratadox\Pathfinder\Graph\Road;
11
use Stratadox\Pathfinder\Graph\Roads;
12
use Stratadox\Pathfinder\Metric;
13
use Stratadox\Pathfinder\Position;
14
15
final class GraphEnvironment
16
{
17
    private $metric;
18
    private $locations;
19
20
    private function __construct(?Metric $metric, Location ...$locations)
21
    {
22
        $this->metric = $metric;
23
        $this->locations = $locations;
24
    }
25
26
    public static function create(): self
27
    {
28
        return new self(null);
29
    }
30
31
    public function withLocation(
32
        string $label,
33
        Position $position,
34
        EdgeDefinition $edges
35
    ): self {
36
        return new self($this->metric, ...array_merge(
37
            $this->locations,
38
            [Location::at($position, $label, $edges->gather())]
39
        ));
40
    }
41
42
    public function determineEdgeCostsAs(Metric $metric): self
43
    {
44
        return new self($metric, ...$this->locations);
45
    }
46
47
    public function make(): Environment
48
    {
49
        return GeometricGraph::with(...$this->actualLocations());
50
    }
51
52
    private function actualLocations(): array
53
    {
54
        if (null === $this->metric) {
55
            return $this->locations;
56
        }
57
        $actualLocations = [];
58
        foreach ($this->locations as $i => $location) {
59
            $newEdges = [];
60
            foreach ($location->edges() as $edge) {
61
                $newEdges[] = Road::towards($edge->target(), $this->newCost(
62
                    $edge->cost(),
63
                    $this->metric->distanceBetween(
64
                        $location->position(),
65
                        $this->positionOf($edge->target())
66
                    )
67
                ));
68
            }
69
            $actualLocations[] = Location::at(
70
                $location->position(),
71
                $location->label(),
72
                Roads::available(...$newEdges)
73
            );
74
        }
75
        return $actualLocations;
76
    }
77
78
    private function newCost(float $previousCost, float $distance): float
79
    {
80
        return $previousCost - 1.0 + $distance;
81
    }
82
83
    private function positionOf(string $node): Position
84
    {
85
        foreach ($this->locations as $location) {
86
            if ($node === $location->label()) {
87
                return $location->position();
88
            }
89
        }
90
        throw new InvalidArgumentException("$node does not exist!");
91
    }
92
}
93