Passed
Push — master ( 6d626d...5de675 )
by Janko
09:20
created

LssBlockadeGrid::__construct()   B

Complexity

Conditions 7
Paths 3

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 7.2944

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 7
eloc 10
nc 3
nop 6
dl 0
loc 21
ccs 9
cts 11
cp 0.8182
crap 7.2944
rs 8.8333
c 1
b 0
f 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stu\Lib\Map\VisualPanel\LssBlockade;
6
7
use InvalidArgumentException;
8
use OutOfBoundsException;
9
10
class LssBlockadeGrid
11
{
12
    private int   $minX;
13
    private int   $minY;
14
    private int   $width;
15
    private int   $height;
16
    private int   $obsX;
17
    private int   $obsY;
18
19
    /** @var bool[][]  $blocked[$xIdx][$yIdx]   */
20
    private array $blocked  = [];
21
22 15
    public function __construct(
23
        int $minX,
24
        int $maxX,
25
        int $minY,
26
        int $maxY,
27
        int $obsX,
28
        int $obsY
29
    ) {
30 15
        if ($minX > $maxX || $minY > $maxY) {
31
            throw new InvalidArgumentException('min‑Koordinaten müssen ≤ max sein.');
32
        }
33 15
        if ($obsX < $minX || $obsX > $maxX || $obsY < $minY || $obsY > $maxY) {
34
            throw new InvalidArgumentException('Observer liegt nicht im angegebenen Rechteck.');
35
        }
36
37 15
        $this->minX  = $minX;
38 15
        $this->minY  = $minY;
39 15
        $this->width  = $maxX - $minX + 1;
40 15
        $this->height = $maxY - $minY + 1;
41 15
        $this->obsX  = $obsX;
42 15
        $this->obsY  = $obsY;
43
    }
44
45 15
    private function idxX(int $worldX): int
46
    {
47 15
        return $worldX - $this->minX;
48
    }
49 15
    private function idxY(int $worldY): int
50
    {
51 15
        return $worldY - $this->minY;
52
    }
53
54 15
    private function inRange(int $x, int $y): bool
55
    {
56 15
        return $x >= $this->minX && $x < $this->minX + $this->width
57 15
            && $y >= $this->minY && $y < $this->minY + $this->height;
58
    }
59
60 9
    public function setBlocked(int $x, int $y): void
61
    {
62 9
        if (!$this->inRange($x, $y)) {
63
            throw new OutOfBoundsException("Koordinate ($x,$y) liegt außerhalb des Grids");
64
        }
65
66 9
        $this->blocked[$this->idxX($x)][$this->idxY($y)] = true;
67
    }
68
69 15
    public function isVisible(int $x, int $y): bool
70
    {
71 15
        if (!$this->inRange($x, $y)) return false;
72
73 15
        $ixT = $this->idxX($x);
74 15
        $iyT = $this->idxY($y);
75 15
        if (!empty($this->blocked[$ixT][$iyT])) return false;
76
77 15
        $dx = $x - $this->obsX;
78 15
        $dy = $y - $this->obsY;
79 15
        $sx = $dx >= 0 ? 1 : -1;
80 15
        $sy = $dy >= 0 ? 1 : -1;
81 15
        $dx = abs($dx);
82 15
        $dy = abs($dy);
83
84 15
        $err = $dx - $dy;          // Bresenham‑Setup
85 15
        $cx  = $this->obsX;
86 15
        $cy  = $this->obsY;
87
88 15
        while ($cx !== $x || $cy !== $y) {
89
90 14
            $e2 = $err << 1;       //  = 2*err
91 14
            $nx = $cx;
92 14
            $ny = $cy;
93
94 14
            if ($e2 > -$dy) {      // Schritt in x‑Richtung
95 14
                $err -= $dy;
96 14
                $nx  += $sx;
97
            }
98 14
            if ($e2 <  $dx) {      // Schritt in y‑Richtung
99 13
                $err += $dx;
100 13
                $ny  += $sy;
101
            }
102
103 14
            if ($cx !== $nx && $cy !== $ny) {
104 13
                $side1Blocked = !empty($this->blocked[$this->idxX($cx)][$this->idxY($ny)]);
105 13
                $side2Blocked = !empty($this->blocked[$this->idxX($nx)][$this->idxY($cy)]);
106 13
                if ($side1Blocked || $side2Blocked) return false;
107
            }
108
109 9
            if (!empty($this->blocked[$this->idxX($nx)][$this->idxY($ny)])) return false;
110
111 9
            $cx = $nx;
112 9
            $cy = $ny;
113
        }
114
115 10
        return true;
116
    }
117
}
118