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

class.sudoxu.php (1 issue)

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)
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)
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);
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
        for ($x = 0; $x < count($attempt_array); $x++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
215
        {
216
            if ($attempt_array[$x] != $number)
217
            {
218
                array_unshift($new_array, $attempt_array[$x]);
219
            }
220
        }
221
        return $new_array;
222
    }
223
224
225
    private function next_random($possible)
226
    {
227
        $min_choices = null;
228
        $max         = $this->limit;
229
        for ($x = 0; $x < $this->limit * $this->limit; $x++)
230
        {
231
            if (!isset($possible[$x]))
232
            {
233
                $possible[$x] = null;
234
            }
235
236
            if ((count($possible[$x]) <= $max) && (count($possible[$x]) > 0))
237
            {
238
                $max         = count($possible[$x]);
239
                $min_choices = $x;
240
            }
241
        }
242
        return $min_choices;
243
    }
244
245
246
    private function build()
247
    {
248
        $this->sudoku = array();
249
        $this->chars  = array();
250
251
        for ($i = 0; $i < $this->limit; $i++)
252
        {
253
            $this->chars[] = $this->stack[$i];
254
        }
255
    }
256
257
    public function microtime()
258
    {
259
        return microtime(true);
260
    }
261
262
    public function generate()
263
    {
264
        $start     = $this->microtime();
265
        $this->build();
266
267
        $x         = 0;
268
        $saved     = array();
269
        $saved_sud = array();
270
        while (!$this->is_solved_sudoku())
271
        {
272
            $x++;
273
            $next_move = $this->scan_sudoku_for_unique();
274
275
            if ($next_move === false)
276
            {
277
                $next_move    = array_pop($saved);
278
                $this->sudoku = array_pop($saved_sud);
279
            }
280
281
            $what_to_try = $this->next_random($next_move);
282
            $attempt     = $this->determine_random_possible_value($next_move, $what_to_try);
283
284
285
            if (count($next_move[$what_to_try]) > 1)
286
            {
287
                $next_move[$what_to_try] = $this->remove_attempt($next_move[$what_to_try], $attempt);
288
                array_push($saved, $next_move);
289
                array_push($saved_sud, $this->sudoku);
290
            }
291
            $this->sudoku[$what_to_try] = $attempt;
292
        }
293
294
        $timing       = $this->microtime() - $start;
295
        $this->result = array(
296
            'created_in' => round($timing,2),
297
            'difficulty' => 'N/A'
298
        );
299
300
        return $this;
301
    }
302
303
    private function array2export()
304
    {
305
        return array(
306
            'sudoku' => $this->sudoku,
307
            'limit'  => $this->limit,
308
            'result' => $this->result,
309
310
        );
311
    }
312
313
    public function to($to)
314
    {
315
        if($to == 'json')
316
        {
317
            return json_encode($this->array2export());
318
        }
319
        else if($to == 'serialize')
320
        {
321
            return serialize($this->array2export());
322
        }
323
        else if($to == 'html')
324
        {
325
            return serialize($this->array2export());
326
        }
327
    }
328
329
330
    public function draw($echo = true)
331
    {
332
333
334
        $string = "<table cellpadding='0' cellspacing='0' style='margin:0 auto;font:30px Arial;border:3px solid black'>";
335
336
        for ($u = 0; $u < $this->limit; $u++)
337
        {
338
339
340
            if (($u + 1) % $this->sq == '0')
341
            {
342
                $border = 3;
343
            } else {
344
                $border = 1;
345
            }
346
347
            $string .= '<tr>';
348
349
            for ($v = 0; $v < $this->limit; $v++)
350
            {
351
352
353
                if (($v + 1) % $this->sq == '0')
354
                {
355
                    $border2 = 3;
356
                } else {
357
                    $border2 = 1;
358
                }
359
360
                $string .= '<td
361
                            data-row="'.$u.'"
362
                            data-col="'.$v.'"
363
                            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;">';
364
                $string .=($this->sudoku[$v * $this->limit + $u]);
365
                $string .= '</td>';
366
367
            }
368
369
            $string .= '</tr>';
370
371
        }
372
373
        $string .= "</table>";
374
375
376
        if($echo === true)
377
        {
378
            echo $string;
379
        }
380
        else
381
        {
382
            return $string;
383
        }
384
385
    }
386
387
}