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