Passed
Push — master ( 7b9bef...e624dc )
by Burak
01:36
created

class.sudoxu.php (3 issues)

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
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.

Loading history...
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.

Loading history...
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 ignore-call  annotation

200
                $possible[$x] = /** @scrutinizer ignore-call */ $this->determine_possible_values($x, $this->sudoku);

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.

Loading history...
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
}