Passed
Push — master ( 1fb483...35eebd )
by Roman
04:31
created

RowYScanner::isFitRow()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
eloc 9
nc 4
nop 2
dl 0
loc 18
ccs 0
cts 10
cp 0
crap 56
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace App\Crossword\Features\Constructor\Scanner;
6
7
use App\Crossword\Features\Constructor\Scanner\Grid\Cell;
8
use App\Crossword\Features\Constructor\Scanner\Grid\Coordinate;
9
use App\Crossword\Features\Constructor\Scanner\Grid\Grid;
10
use App\Crossword\Features\Constructor\Scanner\Grid\Row;
11
12
final class RowYScanner
13
{
14
    /**
15
     * @return Row[]
16
     */
17
    public function scan(Grid $grid, int $length): array
18
    {
19
        $result = [];
20
        foreach ($grid as $cell) {
21
            if (!$cell->isLetter()) {
22
                continue;
23
            }
24
25
            $leftLine = $this->doScan($grid, $cell, new Move(Move::LEFT), $length);
26
            $rightLine = $this->doScan($grid, $cell, new Move(Move::RIGHT), $length);
27
            if (count($leftLine) || count($rightLine)) {
28
                $result[] = new Row(...array_merge(array_reverse($leftLine), [$cell], $rightLine));
29
            }
30
        }
31
32
        return $result;
33
    }
34
35
    private function doScan(Grid $grid, Cell $cell, Move $move, int $length): array
36
    {
37
        $cell = $this->startCell($grid, $cell, $move);
38
39
        $line = [];
40
        for ($counter = 1; $counter <= $length; $counter++) {
41
            $coordinate = $cell->coordinate();
42
43
            if ($cell->isBlack() || !$coordinate->inFrame()) {
44
                return $line;
45
            }
46
47
            if (!$this->isFitRow($grid, $coordinate)) {
48
                return [];
49
            }
50
51
            $topCell = $grid->shiftCell($coordinate->top());
52
            $downCell = $grid->shiftCell($coordinate->down());
53
            if (!($topCell->isEmpty() && $downCell->isEmpty())) {
54
                array_pop($line);
55
56
                return $line;
57
            }
58
59
            $line[] = $cell;
60
            $cell = $this->nextCell($grid, $move, $coordinate);
61
            if ($length === $counter && $cell->isLetter()) {
62
                array_pop($line);
63
            }
64
        }
65
66
        return $line;
67
    }
68
69
    private function isFitRow(Grid $grid, Coordinate $coordinate): bool
70
    {
71
        $leftCell = $grid->shiftCell($coordinate->left());
72
        $rightCell = $grid->shiftCell($coordinate->right());
73
74
        if ($leftCell->isBlack() && $rightCell->isLetter()) {
75
            return false;
76
        }
77
78
        if ($leftCell->letter() && $rightCell->isLetter()) {
79
            return false;
80
        }
81
82
        if ($leftCell->letter() && $rightCell->isBlack()) {
83
            return false;
84
        }
85
86
        return true;
87
    }
88
89
    private function nextCell(Grid $grid, Move $move, Coordinate $coordinate): Cell
90
    {
91
        $leftCell = $grid->shiftCell($coordinate->left());
92
        $rightCell = $grid->shiftCell($coordinate->right());
93
94
        return match ((string) $move->getValue()) {
95
            Move::LEFT => $leftCell,
96
            Move::RIGHT => $rightCell,
97
        };
98
    }
99
100
    private function startCell(Grid $grid, Cell $cell, Move $move): Cell
101
    {
102
        $coordinate = $cell->coordinate();
103
104
        return match ((string) $move->getValue()) {
105
            Move::LEFT => $grid->shiftCell($coordinate->left()),
106
            Move::RIGHT => $grid->shiftCell($coordinate->right()),
107
        };
108
    }
109
}
110