1var speedOfSolve = 500;
2
3var sudokuBoard = generateEmptyBoard();
4
5function generateEmptyBoard() {
6 return [
7 [[], [], [], [], [], [], [], [], []],
8 [[], [], [], [], [], [], [], [], []],
9 [[], [], [], [], [], [], [], [], []],
10 [[], [], [], [], [], [], [], [], []],
11 [[], [], [], [], [], [], [], [], []],
12 [[], [], [], [], [], [], [], [], []],
13 [[], [], [], [], [], [], [], [], []],
14 [[], [], [], [], [], [], [], [], []],
15 [[], [], [], [], [], [], [], [], []],
16 ];
17}
18
19function getCoordsOfBoxesInSameSubBox(x, y) {
20 let subBoxX = Math.floor(x / 3);
21 let subBoxY = Math.floor(y / 3);
22 let coords = [];
23 for (let subBoxBoxX = 0; subBoxBoxX < 3; subBoxBoxX++) {
24 for (let subBoxBoxY = 0; subBoxBoxY < 3; subBoxBoxY++) {
25 let globalX = subBoxBoxX + subBoxX * 3;
26 let globalY = subBoxBoxY + subBoxY * 3;
27 if (!(globalX === x && globalY === y)) {
28 coords.push({ x: globalX, y: globalY });
29 }
30 }
31 }
32 return coords;
33}
34
35function getCoordsOfBoxesInSameXandY(x, y) {
36 let coords = [];
37 for (let boxX = 0; boxX < 9; boxX++) {
38 if (!(boxX === x)) {
39 coords.push({ x: boxX, y: y });
40 }
41 }
42 for (let boxY = 0; boxY < 9; boxY++) {
43 if (!(boxY === y)) {
44 coords.push({ x: x, y: boxY });
45 }
46 }
47 return coords;
48}
49
50function getPossibleNumbers(x, y, sudokuBoard) {
51 let possibleNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
52 let coordsToCheck = getCoordsOfBoxesInSameSubBox(x, y).concat(
53 getCoordsOfBoxesInSameXandY(x, y)
54 );
55 for (let coordIndex in coordsToCheck) {
56 let coord = coordsToCheck[coordIndex];
57 let boxData = sudokuBoard[coord.x][coord.y];
58 if (boxData.length === 1) {
59 var index = possibleNumbers.indexOf(boxData[0]);
60 if (index !== -1) {
61 possibleNumbers.splice(index, 1);
62 }
63 }
64 }
65 return possibleNumbers;
66}
67
68function iterativelySolveSudokuBoard(sudokuBoard) {
69 let newSudokuBoard = sudokuBoard;
70 for (let x in sudokuBoard) {
71 let sudokuBoardRow = sudokuBoard[x];
72 for (let y in sudokuBoard) {
73 let sudokuBox = sudokuBoardRow[y];
74 if (!(sudokuBox.length === 1)) {
75 newSudokuBoard[x][y] = getPossibleNumbers(x, y, sudokuBoard);
76 }
77 }
78 }
79 for (let x in sudokuBoard) {
80 let sudokuBoardRow = newSudokuBoard[x];
81 for (let y in sudokuBoard) {
82 let sudokuBox = sudokuBoardRow[y];
83 if (!(sudokuBox.length === 1)) {
84 let coordsToCheck = getCoordsOfBoxesInSameSubBox(x, y);
85 let commonNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
86 for (let coordIndex in coordsToCheck) {
87 let coord = coordsToCheck[coordIndex];
88 let boxData = newSudokuBoard[coord.x][coord.y];
89 if (boxData.length !== 1) {
90 let numbersToRemove = [];
91 for (let numberIndex in commonNumbers) {
92 if (!boxData.includes(commonNumbers[numberIndex])) {
93 numbersToRemove.push(commonNumbers[numberIndex]);
94 }
95 }
96 for (let numberIndex in numbersToRemove) {
97 const index = commonNumbers.indexOf(numbersToRemove[numberIndex]);
98 if (index > -1) {
99 commonNumbers.splice(index, 1);
100 }
101 }
102 }
103 }
104 if (x == 1 && y == 6) {
105 console.log(commonNumbers);
106 }
107
108 let potentialSolutionA = newSudokuBoard[x][y];
109 for (let numberIndex in commonNumbers) {
110 const index = potentialSolutionA.indexOf(commonNumbers[numberIndex]);
111 if (index > -1) {
112 potentialSolutionA.splice(index, 1);
113 }
114 }
115 if (potentialSolutionA.length == 1) {
116 let noOtherBoxHasIt = true;
117 for (let coordIndex in coordsToCheck) {
118 let coord = coordsToCheck[coordIndex];
119 let boxData = newSudokuBoard[coord.x][coord.y];
120 let potentialSolution = boxData;
121 for (let numberIndex in commonNumbers) {
122 const index = potentialSolution.indexOf(
123 commonNumbers[numberIndex]
124 );
125 if (index > -1) {
126 potentialSolution.splice(index, 1);
127 }
128 }
129 if (potentialSolution.length == 1) {
130 if (potentialSolutionA[0] === potentialSolution[0]) {
131 noOtherBoxHasIt = false;
132 }
133 }
134 }
135 if (noOtherBoxHasIt) {
136 newSudokuBoard[x][y] = potentialSolutionA;
137 }
138 }
139 }
140 }
141 }
142 return newSudokuBoard;
143}
144
145function initDisplay() {
146 let sudokuBoardElement = document.getElementById("sudoku-board");
147 sudokuBoardElement.innerHTML = "";
148 for (let boxX = 0; boxX < 9; boxX++) {
149 let sudokuBoardRow = document.createElement("div");
150 sudokuBoardRow.className = "sudoku-board-row";
151 for (let boxY = 0; boxY < 9; boxY++) {
152 let sudokuBoardBox = document.createElement("div");
153 sudokuBoardBox.className = "sudoku-board-box";
154 sudokuBoardBox.id = "sudoku-board-box-" + boxX + "-" + boxY;
155 sudokuBoardBox.innerHTML = `<input type="text" class="sudoku-board-box-input" id="${
156 "sudoku-board-box-input-" + boxX + "-" + boxY
157 }">`;
158 sudokuBoardRow.appendChild(sudokuBoardBox);
159 }
160 sudokuBoardElement.appendChild(sudokuBoardRow);
161 }
162}
163
164function updateDisplay(sudokuBoard) {
165 for (let boxX = 0; boxX < 9; boxX++) {
166 for (let boxY = 0; boxY < 9; boxY++) {
167 let currentSudokuBoardBox = document.getElementById(
168 "sudoku-board-box-" + boxX + "-" + boxY
169 );
170 let currentBoxData = sudokuBoard[boxX][boxY];
171 if (currentBoxData.length === 1) {
172 currentSudokuBoardBox.className =
173 "sudoku-board-box sudoku-board-box-solved";
174 currentSudokuBoardBox.innerHTML = currentBoxData[0];
175 } else if (currentBoxData.length === 0) {
176 currentSudokuBoardBox.className =
177 "sudoku-board-box sudoku-board-box-empty";
178 } else {
179 currentSudokuBoardBox.className =
180 "sudoku-board-box sudoku-board-box-unsolved";
181 currentSudokuBoardBox.innerHTML = currentBoxData[0];
182 for (let boxDataIndex in currentBoxData.slice(1)) {
183 currentSudokuBoardBox.innerHTML +=
184 ", " + currentBoxData.slice(1)[boxDataIndex];
185 }
186 }
187 }
188 }
189}
190
191function runIteration() {
192 if (shouldBeSolving) {
193 sudokuBoard = iterativelySolveSudokuBoard(sudokuBoard);
194 updateDisplay(sudokuBoard);
195 let solved = true;
196 for (let x in sudokuBoard) {
197 let sudokuBoardRow = sudokuBoard[x];
198 for (let y in sudokuBoard) {
199 let sudokuBox = sudokuBoardRow[y];
200 if (!(sudokuBox.length === 1)) {
201 solved = false;
202 }
203 }
204 }
205 if (!solved) {
206 setTimeout(runIteration, speedOfSolve);
207 } else {
208 shouldBeSolving = false;
209 }
210 }
211}
212
213function loadUserInput() {
214 for (let boxX = 0; boxX < 9; boxX++) {
215 for (let boxY = 0; boxY < 9; boxY++) {
216 let currentSudokuBoardBoxInput = document.getElementById(
217 "sudoku-board-box-input-" + boxX + "-" + boxY
218 );
219 if (currentSudokuBoardBoxInput.value == "") {
220 sudokuBoard[boxX][boxY] = [];
221 } else {
222 sudokuBoard[boxX][boxY] = [parseInt(currentSudokuBoardBoxInput.value)];
223 }
224 }
225 }
226}
227
228let shouldBeSolving = false;
229function runSolver() {
230 shouldBeSolving = true;
231 loadUserInput();
232 sudokuBoard = [
233 [[7], [9], [], [2], [], [], [1], [3], [5]],
234 [[], [], [3], [9], [], [], [], [], []],
235 [[5], [6], [], [], [3], [], [4], [2], [9]],
236 [[], [], [], [], [2], [], [], [], []],
237 [[], [4], [5], [], [1], [], [8], [], [2]],
238 [[], [7], [], [3], [], [], [], [], [1]],
239 [[4], [], [], [], [9], [], [2], [], [6]],
240 [[], [], [], [4], [], [6], [3], [1], []],
241 [[1], [3], [], [8], [7], [], [9], [5], []],
242 ];
243 runIteration();
244}
245
246function haltSolverAndReset() {
247 shouldBeSolving = false;
248 sudokuBoard = generateEmptyBoard();
249 console.log(sudokuBoard);
250 updateDisplay(sudokuBoard);
251 setTimeout(initDisplay, 500);
252}
253
254initDisplay();