├── gfg.png ├── index.html └── sudoku.js /gfg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cv692001/sudokuSolver/2a1837f2fc9501e4ebf8a0951cbef5be573cd806/gfg.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 |

Sudoku Solver

26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | 48 |
49 |
50 | 51 |
52 |
53 | 54 | 55 | 114 | 115 | -------------------------------------------------------------------------------- /sudoku.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var EASY_PUZZLE = "1-58-2----9--764-52--4--819-19--73-6762-83-9-----61-5---76---3-43--2-5-16--3-89--"; 4 | var MEDIUM_PUZZLE = "-3-5--8-45-42---1---8--9---79-8-61-3-----54---5------78-----7-2---7-46--61-3--5--"; 5 | var HARD_PUZZLE = "8----------36------7--9-2---5---7-------457-----1---3---1----68--85---1--9----4--"; 6 | 7 | // Set this variable to true to publicly expose otherwise private functions inside of SudokuSolver 8 | var TESTABLE = true; 9 | 10 | var SudokuSolver = function (testable) { 11 | var solver; 12 | 13 | // PUBLIC FUNCTIONS 14 | function solve(boardString) { 15 | var boardArray = boardString.split(""); 16 | if (boardIsInvalid(boardArray)) { 17 | return false; 18 | } 19 | return recursiveSolve(boardString); 20 | } 21 | 22 | function solveAndPrint(boardString) { 23 | var solvedBoard = solve(boardString); 24 | console.log(toString(solvedBoard.split(""))); 25 | return solvedBoard; 26 | } 27 | 28 | // PRIVATE FUNCTIONS 29 | function recursiveSolve(boardString) { 30 | var boardArray = boardString.split(""); 31 | if (boardIsSolved(boardArray)) { 32 | return boardArray.join(""); 33 | } 34 | var cellPossibilities = getNextCellAndPossibilities(boardArray); 35 | var nextUnsolvedCellIndex = cellPossibilities.index; 36 | var possibilities = cellPossibilities.choices; 37 | for (var i = 0; i < possibilities.length; i++) { 38 | boardArray[nextUnsolvedCellIndex] = possibilities[i]; 39 | var solvedBoard = recursiveSolve(boardArray.join("")); 40 | if (solvedBoard) { 41 | return solvedBoard; 42 | } 43 | } 44 | return false; 45 | } 46 | 47 | function boardIsInvalid(boardArray) { 48 | return !boardIsValid(boardArray); 49 | } 50 | 51 | function boardIsValid(boardArray) { 52 | return allRowsValid(boardArray) && allColumnsValid(boardArray) && allBoxesValid(boardArray); 53 | } 54 | 55 | function boardIsSolved(boardArray) { 56 | for (var i = 0; i < boardArray.length; i++) { 57 | if (boardArray[i] === "-") { 58 | return false; 59 | } 60 | } 61 | return true; 62 | } 63 | 64 | function getNextCellAndPossibilities(boardArray) { 65 | for (var i = 0; i < boardArray.length; i++) { 66 | if (boardArray[i] === "-") { 67 | var existingValues = getAllIntersections(boardArray, i); 68 | var choices = ["1", "2", "3", "4", "5", "6", "7", "8", "9"].filter(function (num) { 69 | return existingValues.indexOf(num) < 0; 70 | }); 71 | return { index: i, choices: choices }; 72 | } 73 | } 74 | } 75 | 76 | function getAllIntersections(boardArray, i) { 77 | return getRow(boardArray, i).concat(getColumn(boardArray, i)).concat(getBox(boardArray, i)); 78 | } 79 | 80 | function allRowsValid(boardArray) { 81 | return [0, 9, 18, 27, 36, 45, 54, 63, 72].map(function (i) { 82 | return getRow(boardArray, i); 83 | }).reduce(function (validity, row) { 84 | return collectionIsValid(row) && validity; 85 | }, true); 86 | } 87 | 88 | function getRow(boardArray, i) { 89 | var startingEl = Math.floor(i / 9) * 9; 90 | return boardArray.slice(startingEl, startingEl + 9); 91 | } 92 | 93 | function allColumnsValid(boardArray) { 94 | return [0, 1, 2, 3, 4, 5, 6, 7, 8].map(function (i) { 95 | return getColumn(boardArray, i); 96 | }).reduce(function (validity, row) { 97 | return collectionIsValid(row) && validity; 98 | }, true); 99 | } 100 | 101 | function getColumn(boardArray, i) { 102 | var startingEl = Math.floor(i % 9); 103 | return [0, 1, 2, 3, 4, 5, 6, 7, 8].map(function (num) { 104 | return boardArray[startingEl + num * 9]; 105 | }); 106 | } 107 | 108 | function allBoxesValid(boardArray) { 109 | return [0, 3, 6, 27, 30, 33, 54, 57, 60].map(function (i) { 110 | return getBox(boardArray, i); 111 | }).reduce(function (validity, row) { 112 | return collectionIsValid(row) && validity; 113 | }, true); 114 | } 115 | 116 | function getBox(boardArray, i) { 117 | var boxCol = Math.floor(i / 3) % 3; 118 | var boxRow = Math.floor(i / 27); 119 | var startingIndex = boxCol * 3 + boxRow * 27; 120 | return [0, 1, 2, 9, 10, 11, 18, 19, 20].map(function (num) { 121 | return boardArray[startingIndex + num]; 122 | }); 123 | } 124 | 125 | function collectionIsValid(collection) { 126 | var numCounts = {}; 127 | for(var i = 0; i < collection.length; i++) { 128 | if (collection[i] != "-") { 129 | if (numCounts[collection[i]] === undefined) { 130 | numCounts[collection[i]] = 1; 131 | } else { 132 | return false; 133 | } 134 | } 135 | } 136 | return true; 137 | } 138 | 139 | function toString(boardArray) { 140 | return [0, 9, 18, 27, 36, 45, 54, 63, 72].map(function (i) { 141 | return getRow(boardArray, i).join(" "); 142 | }).join("\n"); 143 | } 144 | 145 | if (testable) { 146 | // These methods will be exposed publicly when testing is on. 147 | solver = { 148 | solve: solve, 149 | solveAndPrint: solveAndPrint, 150 | recursiveSolve: recursiveSolve, 151 | boardIsInvalid: boardIsInvalid, 152 | boardIsValid: boardIsValid, 153 | boardIsSolved: boardIsSolved, 154 | getNextCellAndPossibilities: getNextCellAndPossibilities, 155 | getAllIntersections: getAllIntersections, 156 | allRowsValid: allRowsValid, 157 | getRow: getRow, 158 | allColumnsValid: allColumnsValid, 159 | getColumn: getColumn, 160 | allBoxesValid: allBoxesValid, 161 | getBox: getBox, 162 | collectionIsValid: collectionIsValid, 163 | toString: toString }; 164 | } else { 165 | // These will be the only public methods when testing is off. 166 | solver = { solve: solve, 167 | solveAndPrint: solveAndPrint }; 168 | } 169 | 170 | return solver; 171 | }(TESTABLE); 172 | --------------------------------------------------------------------------------