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; |
||||
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 | View Code Duplication | private function is_possible_row($number, $row) |
|||
0 ignored issues
–
show
|
|||||
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 | View Code Duplication | private function is_possible_col($number, $col) |
|||
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||||
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 | } |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.