1 | <?php |
||||||
2 | |||||||
3 | class sudoxu |
||||||
4 | { |
||||||
5 | |||||||
6 | public $sudoku, |
||||||
7 | $result, |
||||||
8 | $number; |
||||||
9 | private $limit, |
||||||
10 | $sq, |
||||||
11 | $chars, |
||||||
12 | $stack = array('1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'); |
||||||
13 | |||||||
14 | public function __construct($limit = 9) |
||||||
15 | { |
||||||
16 | ini_set('memory_limit', -1); |
||||||
17 | set_time_limit(0); |
||||||
18 | |||||||
19 | ini_set('display_errors',1); |
||||||
20 | error_reporting(E_ALL); |
||||||
21 | |||||||
22 | $this->number = 0; |
||||||
23 | $this->limit = $limit; |
||||||
24 | $this->sq = (int)sqrt($this->limit); |
||||||
25 | |||||||
26 | $this->logic(); |
||||||
27 | |||||||
28 | return $this; |
||||||
29 | |||||||
30 | } |
||||||
31 | |||||||
32 | public function logic() |
||||||
33 | { |
||||||
34 | if(count($this->stack) < $this->limit) |
||||||
35 | { |
||||||
36 | echo 'error'; |
||||||
37 | exit; |
||||||
0 ignored issues
–
show
|
|||||||
38 | } |
||||||
39 | } |
||||||
40 | |||||||
41 | public function set($number) |
||||||
42 | { |
||||||
43 | $this->limit = $number; |
||||||
44 | $this->sq = (int)sqrt($this->limit); |
||||||
45 | |||||||
46 | return $this; |
||||||
47 | |||||||
48 | } |
||||||
49 | |||||||
50 | private function return_row($cell) |
||||||
51 | { |
||||||
52 | return floor($cell / $this->limit); |
||||||
53 | |||||||
54 | } |
||||||
55 | |||||||
56 | private function return_col($cell) |
||||||
57 | { |
||||||
58 | return $cell % $this->limit; |
||||||
59 | |||||||
60 | } |
||||||
61 | |||||||
62 | private function return_block($cell) |
||||||
63 | { |
||||||
64 | return floor($this->return_row($cell) / $this->sq) * $this->sq + floor($this->return_col($cell) / $this->sq); |
||||||
65 | |||||||
66 | } |
||||||
67 | |||||||
68 | private function is_possible_row($number, $row) |
||||||
69 | { |
||||||
70 | $possible = true; |
||||||
71 | for ($x = 0; $x < $this->limit; $x++) |
||||||
72 | { |
||||||
73 | if (isset($this->sudoku[$row * $this->limit + $x]) && $this->sudoku[$row * $this->limit + $x] == $number) |
||||||
74 | { |
||||||
75 | $possible = false; |
||||||
76 | } |
||||||
77 | } |
||||||
78 | |||||||
79 | return $possible; |
||||||
80 | } |
||||||
81 | |||||||
82 | private function is_possible_col($number, $col) |
||||||
83 | { |
||||||
84 | $possible = true; |
||||||
85 | for ($x = 0; $x < $this->limit; $x++) |
||||||
86 | { |
||||||
87 | if (isset($this->sudoku[$col + $this->limit * $x]) && $this->sudoku[$col + $this->limit * $x] == $number) |
||||||
88 | { |
||||||
89 | $possible = false; |
||||||
90 | } |
||||||
91 | } |
||||||
92 | |||||||
93 | return $possible; |
||||||
94 | } |
||||||
95 | |||||||
96 | private function is_possible_block($number, $block) |
||||||
97 | { |
||||||
98 | $possible = true; |
||||||
99 | for ($x = 0; $x < $this->limit; $x++) |
||||||
100 | { |
||||||
101 | $index = floor($block / $this->sq) * $this->sq * $this->limit + $x % $this->sq + $this->limit * floor($x / $this->sq) + $this->sq * ($block % $this->sq); |
||||||
102 | if (isset($this->sudoku[$index]) && $this->sudoku[$index] == $number) |
||||||
103 | { |
||||||
104 | $possible = false; |
||||||
105 | } |
||||||
106 | } |
||||||
107 | |||||||
108 | return $possible; |
||||||
109 | } |
||||||
110 | |||||||
111 | private function is_possible_number($cell, $number) |
||||||
112 | { |
||||||
113 | $row = $this->return_row($cell); |
||||||
114 | $col = $this->return_col($cell); |
||||||
115 | $block = $this->return_block($cell); |
||||||
116 | |||||||
117 | return ($this->is_possible_row($number, $row) && $this->is_possible_col($number, $col) && $this->is_possible_block($number, $block)); |
||||||
118 | } |
||||||
119 | |||||||
120 | private function is_correct_row($row) |
||||||
121 | { |
||||||
122 | $row_temp = array(); |
||||||
123 | for ($x = 0; $x < $this->limit; $x++) |
||||||
124 | { |
||||||
125 | if(!isset($this->sudoku[$row * $this->limit + $x])) |
||||||
126 | { |
||||||
127 | $this->sudoku[$row * $this->limit + $x] = null; |
||||||
128 | } |
||||||
129 | $row_temp[$x] = $this->sudoku[$row * $this->limit + $x]; |
||||||
130 | } |
||||||
131 | |||||||
132 | return count(array_diff($this->chars, $row_temp)) == 0; |
||||||
133 | } |
||||||
134 | |||||||
135 | private function is_correct_col($col) |
||||||
136 | { |
||||||
137 | $col_temp = array(); |
||||||
138 | for ($x = 0; $x < $this->limit; $x++) |
||||||
139 | { |
||||||
140 | $col_temp[$x] = $this->sudoku[$col + $x * $this->limit]; |
||||||
141 | } |
||||||
142 | return count(array_diff($this->chars, $col_temp)) == 0; |
||||||
143 | } |
||||||
144 | |||||||
145 | private function is_correct_block($block) |
||||||
146 | { |
||||||
147 | $block_temp = array(); |
||||||
148 | for ($x = 0; $x < $this->limit; $x++) |
||||||
149 | { |
||||||
150 | $lookingfor = floor($block / $this->sq) * ($this->sq * $this->limit) + ($x % $this->sq) + $this->limit * floor($x / $this->sq) + $this->sq * ($block % $this->sq); |
||||||
151 | |||||||
152 | if (!isset($this->sudoku[$lookingfor])) |
||||||
153 | { |
||||||
154 | $this->sudoku[$lookingfor] = null; |
||||||
155 | } |
||||||
156 | |||||||
157 | $block_temp[$x] = $this->sudoku[$lookingfor]; |
||||||
158 | } |
||||||
159 | return count(array_diff($this->chars, $block_temp)) == 0; |
||||||
160 | } |
||||||
161 | |||||||
162 | private function is_solved_sudoku() |
||||||
163 | { |
||||||
164 | for ($x = 0; $x < $this->limit; $x++) |
||||||
165 | { |
||||||
166 | if (!$this->is_correct_block($x) or !$this->is_correct_row($x) or !$this->is_correct_col($x)) |
||||||
167 | { |
||||||
168 | return false; |
||||||
169 | } |
||||||
170 | } |
||||||
171 | return true; |
||||||
172 | } |
||||||
173 | |||||||
174 | private function determine_possible_values($cell) |
||||||
175 | { |
||||||
176 | $possible = array(); |
||||||
177 | for ($x = 0; $x < $this->limit; $x++) |
||||||
178 | { |
||||||
179 | if ($this->is_possible_number($cell, $this->chars[$x])) |
||||||
180 | { |
||||||
181 | array_unshift($possible, $this->chars[$x]); |
||||||
182 | } |
||||||
183 | } |
||||||
184 | |||||||
185 | return $possible; |
||||||
186 | } |
||||||
187 | |||||||
188 | private function determine_random_possible_value($possible, $cell) |
||||||
189 | { |
||||||
190 | return $possible[$cell][rand(0, count($possible[$cell]) - 1)]; |
||||||
191 | } |
||||||
192 | |||||||
193 | private function scan_sudoku_for_unique() |
||||||
194 | { |
||||||
195 | $possible = false; |
||||||
196 | for ($x = 0; $x < $this->limit * $this->limit; $x++) |
||||||
197 | { |
||||||
198 | if (!isset($this->sudoku[$x])) |
||||||
199 | { |
||||||
200 | $possible[$x] = $this->determine_possible_values($x, $this->sudoku); |
||||||
0 ignored issues
–
show
The call to
sudoxu::determine_possible_values() has too many arguments starting with $this->sudoku .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
201 | if (count($possible[$x]) == 0) |
||||||
202 | { |
||||||
203 | return (false); |
||||||
204 | } |
||||||
205 | } |
||||||
206 | } |
||||||
207 | |||||||
208 | return $possible; |
||||||
209 | } |
||||||
210 | |||||||
211 | private function remove_attempt($attempt_array, $number) |
||||||
212 | { |
||||||
213 | $new_array = array(); |
||||||
214 | $count = count($attempt_array); |
||||||
215 | for ($x = 0; $x < $count; $x++) |
||||||
216 | { |
||||||
217 | if ($attempt_array[$x] != $number) |
||||||
218 | { |
||||||
219 | array_unshift($new_array, $attempt_array[$x]); |
||||||
220 | } |
||||||
221 | } |
||||||
222 | return $new_array; |
||||||
223 | } |
||||||
224 | |||||||
225 | |||||||
226 | private function next_random($possible) |
||||||
227 | { |
||||||
228 | $min_choices = null; |
||||||
229 | $max = $this->limit; |
||||||
230 | for ($x = 0; $x < $this->limit * $this->limit; $x++) |
||||||
231 | { |
||||||
232 | if (!isset($possible[$x])) |
||||||
233 | { |
||||||
234 | $possible[$x] = null; |
||||||
235 | } |
||||||
236 | |||||||
237 | if ((count($possible[$x]) <= $max) && (count($possible[$x]) > 0)) |
||||||
238 | { |
||||||
239 | $max = count($possible[$x]); |
||||||
240 | $min_choices = $x; |
||||||
241 | } |
||||||
242 | } |
||||||
243 | return $min_choices; |
||||||
244 | } |
||||||
245 | |||||||
246 | |||||||
247 | private function build() |
||||||
248 | { |
||||||
249 | $this->sudoku = array(); |
||||||
250 | $this->chars = array(); |
||||||
251 | |||||||
252 | for ($i = 0; $i < $this->limit; $i++) |
||||||
253 | { |
||||||
254 | $this->chars[] = $this->stack[$i]; |
||||||
255 | } |
||||||
256 | } |
||||||
257 | |||||||
258 | public function microtime() |
||||||
259 | { |
||||||
260 | return microtime(true); |
||||||
261 | } |
||||||
262 | |||||||
263 | public function generate() |
||||||
264 | { |
||||||
265 | $start = $this->microtime(); |
||||||
266 | $this->build(); |
||||||
267 | |||||||
268 | $x = 0; |
||||||
269 | $saved = array(); |
||||||
270 | $saved_sud = array(); |
||||||
271 | while (!$this->is_solved_sudoku()) |
||||||
272 | { |
||||||
273 | $x++; |
||||||
274 | $next_move = $this->scan_sudoku_for_unique(); |
||||||
275 | |||||||
276 | if ($next_move === false) |
||||||
277 | { |
||||||
278 | $next_move = array_pop($saved); |
||||||
279 | $this->sudoku = array_pop($saved_sud); |
||||||
280 | } |
||||||
281 | |||||||
282 | $what_to_try = $this->next_random($next_move); |
||||||
283 | $attempt = $this->determine_random_possible_value($next_move, $what_to_try); |
||||||
284 | |||||||
285 | |||||||
286 | if (count($next_move[$what_to_try]) > 1) |
||||||
287 | { |
||||||
288 | $next_move[$what_to_try] = $this->remove_attempt($next_move[$what_to_try], $attempt); |
||||||
289 | array_push($saved, $next_move); |
||||||
290 | array_push($saved_sud, $this->sudoku); |
||||||
291 | } |
||||||
292 | $this->sudoku[$what_to_try] = $attempt; |
||||||
293 | } |
||||||
294 | |||||||
295 | $timing = $this->microtime() - $start; |
||||||
296 | $this->result = array( |
||||||
297 | 'created_in' => round($timing,2), |
||||||
298 | 'difficulty' => 'N/A' |
||||||
299 | ); |
||||||
300 | |||||||
301 | return $this; |
||||||
302 | } |
||||||
303 | |||||||
304 | private function array2export() |
||||||
305 | { |
||||||
306 | return array( |
||||||
307 | 'sudoku' => $this->sudoku, |
||||||
308 | 'limit' => $this->limit, |
||||||
309 | 'result' => $this->result, |
||||||
310 | |||||||
311 | ); |
||||||
312 | } |
||||||
313 | |||||||
314 | public function to($to) |
||||||
315 | { |
||||||
316 | if($to == 'json') |
||||||
317 | { |
||||||
318 | return json_encode($this->array2export()); |
||||||
319 | } |
||||||
320 | else if($to == 'serialize') |
||||||
321 | { |
||||||
322 | return serialize($this->array2export()); |
||||||
323 | } |
||||||
324 | else if($to == 'html') |
||||||
325 | { |
||||||
326 | return serialize($this->array2export()); |
||||||
327 | } |
||||||
328 | } |
||||||
329 | |||||||
330 | |||||||
331 | public function draw($echo = true) |
||||||
332 | { |
||||||
333 | |||||||
334 | |||||||
335 | $string = "<table cellpadding='0' cellspacing='0' style='margin:0 auto;font:30px Arial;border:3px solid black'>"; |
||||||
336 | |||||||
337 | for ($u = 0; $u < $this->limit; $u++) |
||||||
338 | { |
||||||
339 | |||||||
340 | |||||||
341 | if (($u + 1) % $this->sq == '0') |
||||||
342 | { |
||||||
343 | $border = 3; |
||||||
344 | } else { |
||||||
345 | $border = 1; |
||||||
346 | } |
||||||
347 | |||||||
348 | $string .= '<tr>'; |
||||||
349 | |||||||
350 | for ($v = 0; $v < $this->limit; $v++) |
||||||
351 | { |
||||||
352 | |||||||
353 | |||||||
354 | if (($v + 1) % $this->sq == '0') |
||||||
355 | { |
||||||
356 | $border2 = 3; |
||||||
357 | } else { |
||||||
358 | $border2 = 1; |
||||||
359 | } |
||||||
360 | |||||||
361 | $string .= '<td |
||||||
362 | data-row="'.$u.'" |
||||||
363 | data-col="'.$v.'" |
||||||
364 | style="border: 1px solid black;border-bottom:' . $border . 'px solid black;border-right:' . $border2 . 'px solid black;line-height: 50px; width: 50px; text-align: center; vertical-align: middle;">'; |
||||||
365 | $string .=($this->sudoku[$v * $this->limit + $u]); |
||||||
366 | $string .= '</td>'; |
||||||
367 | |||||||
368 | } |
||||||
369 | |||||||
370 | $string .= '</tr>'; |
||||||
371 | |||||||
372 | } |
||||||
373 | |||||||
374 | $string .= "</table>"; |
||||||
375 | |||||||
376 | |||||||
377 | if($echo === true) |
||||||
378 | { |
||||||
379 | echo $string; |
||||||
380 | } |
||||||
381 | else |
||||||
382 | { |
||||||
383 | return $string; |
||||||
384 | } |
||||||
385 | |||||||
386 | } |
||||||
387 | |||||||
388 | } |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.