128 lines
3.5 KiB
JavaScript
128 lines
3.5 KiB
JavaScript
let currentPuzzle = "";
|
|
class SudokuSolver {
|
|
getPuzzleArray(puzzleString) {
|
|
const puzzleArray = [[], [], [], [], [], [], [], [], []];
|
|
for (let i = 0; i <= 80; i++) {
|
|
let value = puzzleString[i];
|
|
value === "." || !value
|
|
? (puzzleArray[Math.floor(i / 9)][i % 9] = " ")
|
|
: (puzzleArray[Math.floor(i / 9)][i % 9] = value);
|
|
}
|
|
return puzzleArray;
|
|
}
|
|
|
|
getRow(puzzle, row) {
|
|
return puzzle[row];
|
|
}
|
|
|
|
getColumn(puzzle, row, column) {
|
|
let col = [];
|
|
for (let i in puzzle) {
|
|
col.push(puzzle[i][column]);
|
|
}
|
|
return col;
|
|
}
|
|
|
|
getRegion(puzzle, row, column) {
|
|
let region = [];
|
|
for (let r = 0; r < 3; r++) {
|
|
for (let c = 0; c < 3; c++) {
|
|
region.push(
|
|
puzzle[Math.floor(row / 3) * 3 + r][Math.floor(column / 3) * 3 + c]
|
|
);
|
|
}
|
|
}
|
|
return region;
|
|
}
|
|
|
|
validate(puzzleString) {
|
|
if (puzzleString.length !== 81) {
|
|
return {
|
|
error: "Expected puzzle to be 81 characters long",
|
|
};
|
|
} else if (!/^[1-9.]+$/.test(puzzleString)) {
|
|
return { error: "Invalid characters in puzzle" };
|
|
} else {
|
|
for (let i in puzzleString) {
|
|
let val = puzzleString[i];
|
|
let row = Math.floor(i / 9);
|
|
let column = i % 9;
|
|
if (val !== ".") {
|
|
let temp = puzzleString.split("");
|
|
temp[i] = ".";
|
|
if (
|
|
this.checkRowPlacement(temp, row, column, val) &&
|
|
this.checkColPlacement(temp, row, column, val) &&
|
|
this.checkRegionPlacement(temp, row, column, val)
|
|
) {
|
|
temp[i] = val;
|
|
puzzleString = temp.join("");
|
|
} else {
|
|
return { error: "Puzzle cannot be solved" };
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
checkRowPlacement(puzzleString, row, column, value) {
|
|
let puzzle = this.getPuzzleArray(puzzleString);
|
|
let puzzleRow = this.getRow(puzzle, row, column);
|
|
return !(
|
|
puzzleRow.includes(value.toString()) &&
|
|
puzzleRow[column] !== value.toString()
|
|
);
|
|
}
|
|
|
|
checkColPlacement(puzzleString, row, column, value) {
|
|
let puzzle = this.getPuzzleArray(puzzleString);
|
|
let puzzleCol = this.getColumn(puzzle, row, column);
|
|
return !(
|
|
puzzleCol.includes(value.toString()) &&
|
|
puzzleCol[row] !== value.toString()
|
|
);
|
|
}
|
|
|
|
checkRegionPlacement(puzzleString, row, column, value) {
|
|
let puzzle = this.getPuzzleArray(puzzleString);
|
|
let puzzleRegion = this.getRegion(puzzle, row, column);
|
|
return !(
|
|
puzzleRegion.includes(value.toString()) &&
|
|
puzzle[row][column] !== value.toString()
|
|
);
|
|
}
|
|
|
|
solve(puzzleString) {
|
|
if (puzzleString) currentPuzzle = puzzleString;
|
|
let valid = this.validate(currentPuzzle);
|
|
if (valid !== true) {
|
|
return valid;
|
|
}
|
|
let empty = currentPuzzle.indexOf(".");
|
|
let row = Math.floor(empty / 9);
|
|
let column = empty % 9;
|
|
if (empty !== -1) {
|
|
for (let i = 1; i <= 9; i++) {
|
|
if (
|
|
this.checkRowPlacement(currentPuzzle, row, column, i) &&
|
|
this.checkColPlacement(currentPuzzle, row, column, i) &&
|
|
this.checkRegionPlacement(currentPuzzle, row, column, i)
|
|
) {
|
|
let temp = currentPuzzle.split("");
|
|
temp[empty] = i;
|
|
currentPuzzle = temp.join("");
|
|
this.solve();
|
|
}
|
|
}
|
|
}
|
|
if (currentPuzzle.indexOf(".") !== -1) {
|
|
let temp = currentPuzzle.split("");
|
|
temp[empty] = ".";
|
|
currentPuzzle = temp.join("");
|
|
}
|
|
return { solution: currentPuzzle };
|
|
}
|
|
}
|
|
|
|
module.exports = SudokuSolver;
|