I build a function that generates random sudoku boards 9x9. It fills the sudoku board with a specified amount of random numbers. It takes into account sudoku rules: no replicates in each row, in each column and each 3x3 square. The problem is that the printed boards are unsolvable. Although there are no replicate in the output board, when the player fills the empty cells he has no choice but to produce replicates in rows/columns and squares. The generated boards are indeed invalid. How can I code so that the function takes into account the empty cells and generates valid boards with possible solution? Also when I ask the function to fill more than 60 random numbers in the board it creates a bug, it loops too long and the window freezes (it seems like it takes too much to fill a board with 60+ random numbers with no replicate).
here is an example of unsolvable board i got from that function:
0: (9) [null, 5, 3, 1, 7, 9, 2, 6, 4]
1: (9) [1, 4, 7, 6, null, 5, 9, 8, null]
2: (9) [6, 8, null, 3, 4, 2, 1, 7, 5]
3: (9) [null, 9, 2, 4, null, 8, 5, null, 3]
4: (9) [null, 1, 5, null, 9, 6, 8, 2, 7]
5: (9) [null, 3, null, 7, null, null, 4, 1, null]
6: (9) [4, null, 1, 9, 2, null, 3, 5, 6]
7: (9) [null, 7, 9, 5, 3, 4, null, null, 8]
8: (9) [5, 2, 6, null, 8, 7, null, 4, 9]
let sudoku = [
[null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null],
];
window.onload = function () {
generateSudoku(60);
fillEmptySudoku();
};
function generateSudoku(displayedNumbers) {
let numAdded = 0;
while (numAdded < displayedNumbers) {
let row = Math.floor(Math.random() * 9);
let col = Math.floor(Math.random() * 9);
let number = Math.floor(Math.random() * 9) + 1;
if (sudoku[row][col] === null) {
sudoku[row][col] = number;
if (duplicateExist(sudoku, row, col)) {
sudoku[row][col] = null;
continue;
}
numAdded++;
}
}
console.log(sudoku);
return sudoku;
}
let table = document.getElementById("table");
//map the matrix values into the html table
function fillEmptySudoku() {
for (let i = 0; i < table.rows.length; i++) {
for (let j = 0; j < table.rows[i].cells.length; j++) {
if (sudoku[i][j] === null) {
table.rows[i].cells[j].setAttribute("contenteditable", "true");
} else {
table.rows[i].cells[j].textContent = sudoku[i][j];
}
}
}
}
//only allow 1 to 9 in cells
table.addEventListener("keypress", function (e) {
if (e.which < 49 || e.which > 57) e.preventDefault();
});
//restrict inputs to one number only
table.addEventListener("input", function (e) {
e.target.value = e.data;
});
//Eliminate duplicates
function duplicatesInRow(grid, row) {
let numbers = [];
for (let i = 0; i < 9; i++) {
if (grid[row][i] !== null) {
if (numbers.includes(grid[row][i])) {
return true;
} else {
numbers.push(grid[row][i]);
}
}
}
return false;
}
function duplicatesInCol(grid, col) {
let numbers = [];
for (let i = 0; i < 9; i++) {
if (grid[i][col] !== null) {
if (numbers.includes(grid[i][col])) {
return true;
} else {
numbers.push(grid[i][col]);
}
}
}
return false;
}
function duplicatesInSquare(grid, row, col) {
let rowsOfSquare = Math.floor(row / 3);
let colOfSquare = Math.floor(col / 3);
let numbers = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
x = i + 3 * rowsOfSquare;
y = j + 3 * colOfSquare;
if (grid[x][y] !== null) {
if (numbers.includes(grid[x][y])) {
return true;
} else {
numbers.push(grid[x][y]);
}
}
}
}
return false;
}
function duplicateExist(grid, row, col) {
if (duplicatesInRow(grid, row)) {
return true;
}
if (duplicatesInCol(grid, col)) {
return true;
}
if (duplicatesInSquare(grid, row, col)) {
return true;
}
return false;
}
<table id="table">
<tr class="tr" id="row1">
<td class="td" id="cell1">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell2">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell3">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell4">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell5">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell6">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell7">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell8">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell9">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
</tr>
<tr class="tr" id="row2">
<td class="td" id="cell10">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell11">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell12">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell13">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell14">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell15">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell16">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell17">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell18">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
</tr>
<tr class="tr" id="row3">
<td class="td" id="cell19">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell20">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell21">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell22">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell23">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell24">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell25">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell26">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell27">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
</tr>
<tr class="tr" id="row4">
<td class="td" id="cell28">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell29">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell30">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell31">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell32">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell33">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell34">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell35">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell36">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
</tr>
<tr class="tr" id="row5">
<td class="td" id="cell37">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell38">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell39">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell40">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell41">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell42">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell43">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell44">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell45">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
</tr>
<tr class="tr" id="row6">
<td class="td" id="cell46">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell47">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell48">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell49">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell50">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell51">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell52">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell53">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell54">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
</tr>
<tr class="tr" id="row7">
<td class="td" id="cell55">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell56">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell57">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell58">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell59">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell60">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell61">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell62">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell63">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
</tr>
<tr class="tr" id="row8">
<td class="td" id="cell64">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell65">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell66">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell67">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell68">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell69">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell70">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell71">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell72">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
</tr>
<tr class="tr" id="row9">
<td class="td" id="cell73">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell74">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell75">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell76">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell77">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell78">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell79">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell80">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
<td class="td" id="cell81">
<input type="number" min="1" max="9" step="1" class="inp" />
</td>
</tr>
</table>
I'm afraid that my answer disappoint you. It is impossible to create a solvable sudoku puzzle from a randomly filled board! All sudoku puzzles you could find are created from already solved boards. The appearance, i.e. the digits and the location of these, is created by randomly "shuffling" existing solved puzzles. The shuffling process is based on the symmetries of a sudoku grid.