Passed
Push — master ( 29d3e7...ffc574 )
by Craig
06:37 queued 03:28
created

Grid::getGridSize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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