Passed
Push — master ( 05198c...c56a1e )
by Craig
03:33
created

Grid   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 271
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 138
c 2
b 1
f 0
dl 0
loc 271
rs 8.8
wmc 45

15 Methods

Rating   Name   Duplication   Size   Complexity  
A setGridSize() 0 11 2
A placeWordHorizontally() 0 10 2
A placeWord() 0 21 5
A __construct() 0 8 1
A getGrid() 0 15 3
A placeWordDiagonallyLtr() 0 13 3
A placeWordDiagonallyRtl() 0 13 3
B addWord() 0 32 7
A placeWordVertical() 0 10 2
A getColumnDefault() 0 3 1
A getTextGrid() 0 10 3
A addPlacedWord() 0 27 6
A getPuzzleWords() 0 8 2
A initGrid() 0 9 2
A generate() 0 16 3

How to fix   Complexity   

Complex Class

Complex classes like Grid often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Grid, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace CustomD\WordFinder;
4
5
use RuntimeException;
6
use Illuminate\Support\Collection;
7
use CustomD\WordFinder\Traits\HasWordCollection;
8
9
class Grid
10
{
11
12
    use HasWordCollection;
13
14
15
    /**
16
     * minimum word length for the puzzle
17
     */
18
    protected int $minWordLen;
19
20
    /**
21
     * maximium word length for the puzzle
22
     */
23
    protected int $maxWordLen;
24
25
    /**
26
     * grid side length
27
     */
28
    protected int $gridSize;
29
30
    /**
31
     * cells holding the collection of lettes
32
     */
33
    protected array $cells = [];
34
35
    /**
36
     * Words used within the puzzle
37
     */
38
    protected array $wordsList = [];
39
40
    /**
41
     * column mapping
42
     */
43
    protected array $columnArray = [];
44
45
    public function __construct(int $gridSize, int $minWordLen, int $maxWordLen, Collection $wordsCollection)
46
    {
47
        $this->minWordLen = $minWordLen;
48
        $this->maxWordLen = $maxWordLen;
49
50
        $this->setGridsize($gridSize)
51
            ->setWordsCollection($wordsCollection)
52
            ->initGrid();
53
    }
54
55
    protected function setGridSize(int $gridSize): self
56
    {
57
        if ($gridSize < $this->minWordLen) {
58
            throw new RuntimeException('size must be greater than '.$this->minWordLen);
59
        }
60
61
        $this->gridSize = $gridSize;
62
        //max word length cannot be greater than the grid size.
63
        $this->maxWordLen = min($gridSize, $this->maxWordLen);
64
65
        return $this;
66
    }
67
68
    protected function initGrid(): self
69
    {
70
        $this->cells = array_fill(0, $this->gridSize * $this->gridSize, null);
71
72
        for ($i = 0; $i < (2 * $this->gridSize * $this->gridSize); $i++) {
73
            $this->columnArray[$i]=$this->getColumnDefault($i);
74
        }
75
76
        return $this;
77
    }
78
79
    public function generate(): self
80
    {
81
        $blocks = $this->gridSize * $this->gridSize;
82
        $i=rand(0, $blocks-1);
83
84
        $complete=0;
85
        while ($complete < $blocks) {
86
            $this->placeWord($i);
87
            $complete++;
88
            $i++;
89
            if ($i==$blocks) {
90
                $i=0;
91
            }
92
        }
93
94
        return $this;
95
    }
96
97
    protected function addPlacedWord(Word $word, int $increment, int $len): void
98
    {
99
        $string = '';
100
        $flag=false;
101
102
        for ($i=$word->getStart(); $i<=$word->getEnd(); $i+=$increment) {
103
            if ($this->cells[$i] === null) {
104
                $string .= '_';
105
            } else {
106
                $string .= $this->cells[$i];
107
                $flag=true;
108
            }
109
        }
110
111
        if (! $flag) {
0 ignored issues
show
introduced by
The condition $flag is always false.
Loading history...
112
            $randomWord = $this->getRandomWord($len);
113
            $word->setLabel($word->getInversed() ? strrev($randomWord) : $randomWord);
114
            $this->addWord($word);
115
            return;
116
        }
117
118
        if (strpos($string, '_')===false) {
119
            return;
120
        }
121
122
        $word->setLabel($this->getWordLike($string))->setInversed(false);
123
        $this->addWord($word);
124
    }
125
126
    protected function placeWordHorizontally(Word $word, int $len): void
127
    {
128
        $inc = 1;
129
        $word->setEnd($word->getStart()+$len-1);
130
        while ($this->columnArray[$word->getEnd()] < $this->columnArray[$word->getStart()]) {
131
            $word->setStart($word->getStart()-1);
132
            $word->setEnd($word->getStart()+$len-1);
133
        }
134
135
        $this->addPlacedWord($word, $inc, $len);
136
    }
137
138
    protected function placeWordVertical(Word $word, int $len): void
139
    {
140
        $inc=$this->gridSize;
141
        $word->setEnd($word->getStart()+($len*$this->gridSize)-$this->gridSize);
142
        while ($word->getEnd()>($this->gridSize*$this->gridSize)-1) {
143
            $word->setStart($word->getStart()-$this->gridSize);
144
            $word->setEnd($word->getStart()+($len*$this->gridSize)-$this->gridSize);
145
        }
146
147
        $this->addPlacedWord($word, $inc, $len);
148
    }
149
150
    protected function placeWordDiagonallyLtr(Word $word, int $len): void
151
    {
152
        $inc=$this->gridSize+1;
153
        $word->setEnd($word->getStart()+($len*($this->gridSize+1))-($this->gridSize+1));
154
        while ($this->columnArray[$word->getEnd()] < $this->columnArray[$word->getStart()]) {
155
            $word->setStart($word->getStart()-1);
156
            $word->setEnd($word->getStart()+($len*($this->gridSize+1))-($this->gridSize+1));
157
        }
158
        while ($word->getEnd()>($this->gridSize*$this->gridSize)-1) {
159
            $word->setStart($word->getStart()-$this->gridSize);
160
            $word->setEnd($word->getStart()+($len*($this->gridSize+1))-($this->gridSize+1));
161
        }
162
        $this->addPlacedWord($word, $inc, $len);
163
    }
164
165
    protected function placeWordDiagonallyRtl(Word $word, int $len): void
166
    {
167
        $inc=$this->gridSize-1;
168
        $word->setEnd($word->getStart()+(($len-1)*($this->gridSize-1)));
169
        while ($this->columnArray[$word->getEnd()] > $this->columnArray[$word->getStart()]) {
170
            $word->setStart($word->getStart()+1);
171
            $word->setEnd($word->getStart()+(($len-1)*($this->gridSize-1)));
172
        }
173
        while ($word->getEnd()>($this->gridSize*$this->gridSize)-1) {
174
            $word->setStart($word->getStart()-$this->gridSize);
175
            $word->setEnd($word->getStart()+(($len-1)*($this->gridSize-1)));
176
        }
177
        $this->addPlacedWord($word, $inc, $len);
178
    }
179
180
    protected function placeWord($start): void
181
    {
182
        $len = $this->getRandomWordLength();
183
        $word = Word::createRandom($start);
184
185
        switch ($word->getOrientation()) {
186
            case Word::HORIZONTAL:
187
                $this->placeWordHorizontally($word, $len);
188
                return;
189
190
            case Word::VERTICAL:
191
                $this->placeWordVertical($word, $len);
192
                return;
193
194
            case Word::DIAGONAL_LEFT_TO_RIGHT:
195
                $this->placeWordDiagonallyLtr($word, $len);
196
                return;
197
198
            case Word::DIAGONAL_RIGHT_TO_LEFT:
199
                $this->placeWordDiagonallyRtl($word, $len);
200
                return;
201
        }
202
    }
203
204
    protected function getColumnDefault(int $x): int
205
    {
206
        return ($x % $this->gridSize)+1;
207
    }
208
209
    protected function addWord(Word $word): void
210
    {
211
        if ($word->getLabel() === null) {
212
            return;
213
        }
214
215
        $j=0;
216
        $incrementBy = 1;
217
        switch ($word->getOrientation()) {
218
            case Word::HORIZONTAL:
219
                $incrementBy=1;
220
                break;
221
222
            case Word::VERTICAL:
223
                $incrementBy=$this->gridSize;
224
                break;
225
226
            case Word::DIAGONAL_LEFT_TO_RIGHT:
227
                $incrementBy=$this->gridSize+1;
228
                break;
229
230
            case Word::DIAGONAL_RIGHT_TO_LEFT:
231
                $incrementBy=$this->gridSize-1;
232
                break;
233
        }
234
235
        for ($i = $word->getStart(); $j < strlen($word->getLabel()); $i += $incrementBy) {
236
            $this->cells[$i] = substr($word->getLabel(), $j, 1);
237
            $j++;
238
        }
239
240
        $this->wordsList[]=$word;
241
    }
242
243
    public function getTextGrid()
244
    {
245
        $r = '';
246
        foreach ($this->getGrid() as $idx => $row) {
247
            if ($idx > 0) {
248
                $r .= "\n";
249
            }
250
            $r .= implode(" ", $row);
251
        }
252
        return $r;
253
    }
254
255
    public function getGrid()
256
    {
257
        $return = [];
258
        $column = 0;
259
        $row = 0;
260
        foreach ($this->cells as $letter) {
261
            $cell = $letter ?? chr(rand(65, 90));
262
            $return[$row][$column] = $cell;
263
            $column++;
264
            if ($column === $this->gridSize) {
265
                $row++;
266
                $column = 0;
267
            }
268
        }
269
        return $return;
270
    }
271
272
    public function getPuzzleWords()
273
    {
274
        return collect($this->wordsList)->map(function (Word $word) {
275
            $label = $word->getLabel();
276
            if ($word->getInversed()) {
277
                $label = strrev(/** @scrutinizer ignore-type */$label);
278
            }
279
            return $label;
280
        });
281
    }
282
}
283