I managed to create a Sudoku generator but I'll just go ahead and say that it generates 1 out of 500 tries on average. I'd say that's pretty inefficient and I'd like to ask you for advice on improvements.
Basically what I figured is if I had defined a range of numbers that are possible for each cell, then started selecting random numbers for cells 1 by 1 and removing the respective number from its column, row and "box" ( don't really know how they're called ), then it would magically select appropriate numbers and will be left with only one single possible number for the last cell. Well that wasn't the case, but I thought if I gave it a bunch of more tries it would eventually end up as I planned it and it did, the problem is, as I already said that it is very inefficient.
$loop = true;
while ($loop) {
$loop = false;
// define and clear array
$matrix = [];
// Fill all cells with possible numbers
for ($x = 1; $x < 10; $x++) {
for ($y = 1; $y < 10; $y++) {
for ($z = 1; $z < 10; $z++) {
$matrix[$y][$x][$z] = $z;
}
}
}
// Start selecting random numbers for each cell from
// the possible numbers contained in it currently
for ($x = 1; $x < 10; $x++) {
for ($y = 1; $y < 10; $y++) {
$keys = array_keys($matrix[$x][$y]);
// if there are no keys this means there are no possible
// numbers for this cell, which means the generator has
// failed => restart
if(count($keys) == 0){
$loop = true;
break 2;
}
// Set cell number to a random number from the possible
$matrix[$x][$y] = $matrix[$x][$y][$keys[mt_rand(0, count($keys) - 1)]];
// remove the selected number from the possible numbers for
// the appropriate column and row
for ($z = 1; $z < 10; $z ++) {
if ($z != $y) {
unset($matrix[$x][$z][$matrix[$x][$y]]);
}
if ($z != $x) {
unset($matrix[$z][$y][$matrix[$x][$y]]);
}
}
// Define box's start ($w) and end ($W) X position
if ($x < 4) {
$w = 1;
$W = 4;
} else if ($x < 7) {
$w = 4;
$W = 7;
} else {
$w = 7;
$W = 10;
}
// Define box's start ($z) and end ($Z) Y position
if ($y < 4) {
$z = 1;
$Z = 4;
} else if ($y < 7) {
$z = 4;
$Z = 7;
} else {
$z = 7;
$Z = 10;
}
// Remove selected number from all cells' possible numbers
// in the appropriate 3x3 box
for (; $w < $W; $w++) {
for ($z = $Z - 3; $z < $Z; $z++) {
if (is_array($matrix[$z][$w])) {
unset($matrix[$z][$w][$matrix[$x][$y]]);
}
}
}
}
}
}
And please excuse me for the part where variables are named $z, $Z
that doesn't make sense, I just have this obsession about re-using variables that I no longer need, which I know is a bad practice but I do it anyway.
EDIT
I currently discovered that it also produces incorrect puzzles occasionally, debugging to find the reason.
Update: I figured the reason out. It was because of the fact that I was using incorrect coordinates for the removal of the selected number from the respective 3x3 grids, however after putting correct coordinates now, no puzzles are generated, it just goes on forever. I guess I will be deleting this question if I don't find a solution soon.