UNPKG

sudoku-solve

Version:

Konni's Sudoku solving library

159 lines (158 loc) 5.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Sudoku = void 0; const Changes_1 = require("./Changes"); const CommonFunctions_1 = require("./CommonFunctions"); const Group_1 = require("./Group"); const Rule_1 = require("./Rule"); const SudokuNumber_1 = require("./SudokuNumber"); class Sudoku { constructor(numbers) { this.numbers = numbers.map((n, i) => { return new SudokuNumber_1.SudokuNumber(CommonFunctions_1.row(i), CommonFunctions_1.col(i), n); }); this.groups = []; for (let i = 0; i < 9; i++) { this.groups.push(Group_1.Group.group(Group_1.GroupType.ROW, i, this.numbers)); this.groups.push(Group_1.Group.group(Group_1.GroupType.COL, i, this.numbers)); this.groups.push(Group_1.Group.group(Group_1.GroupType.BOX, i, this.numbers)); } } get(row, col) { const foundNumber = this.numbers.find((n) => n.row === row && n.col === col); if (!foundNumber) { throw new Error(`there is no number at ${row}, ${col}`); } return foundNumber; } copy() { return new Sudoku(this.numbers.map((n) => (n.isSolved() ? n.get() : 0))); } allImmediatelyPossibleSteps() { const copy = this.copy(); const changes = copy.groups .map((g) => Rule_1.Rule.elimination(g)) .reduce((a1, a2) => a1.concat(a2)) .concat(copy.groups .map((g) => Rule_1.Rule.onlyPossiblePosition(g)) .reduce((a1, a2) => a1.concat(a2))) .concat(copy.groups .map((g) => Rule_1.Rule.twins(g)) .reduce((a1, a2) => a1.concat(a2))); changes.concat(copy.groups .map((g) => Rule_1.Rule.elimination(g)) .reduce((a1, a2) => a1.concat(a2)) .concat(copy.groups .map((g) => Rule_1.Rule.onlyPossiblePosition(g)) .reduce((a1, a2) => a1.concat(a2))) .concat(copy.groups .map((g) => Rule_1.Rule.twins(g)) .reduce((a1, a2) => a1.concat(a2)))); return changes; } allStepsUntilSolution() { const copy = this.copy(); let changes = new Changes_1.Changes([]); let newChanges = new Changes_1.Changes([]); do { newChanges = copy.groups .map((g) => Rule_1.Rule.elimination(g)) .reduce((a1, a2) => a1.concat(a2)); newChanges = newChanges.concat(copy.groups .map((g) => Rule_1.Rule.onlyPossiblePosition(g)) .reduce((a1, a2) => a1.concat(a2))); newChanges = newChanges.concat(copy.groups .map((g) => Rule_1.Rule.twins(g)) .reduce((a1, a2) => a1.concat(a2))); changes = changes.concat(newChanges); } while (copy.unsolvedCount() > 0 && newChanges.changes.length > 0); return changes; } apply(change) { if (change.isNone) return; if (change.hasSolvedNumber()) { const solvedNumber = change.solvedNumber; const number = this.numbers.find((n) => n.row === solvedNumber.row && n.col === solvedNumber.col); if (number === null || number === void 0 ? void 0 : number.isPossible(solvedNumber.value)) { number.solve(solvedNumber.rule, solvedNumber.value); } else { throw new Error(`Cannot apply SolvedNumber to ${number}`); } } else if (change.hasRemovedNumbers()) { const removedNumbers = change.removedNumbers; const number = this.numbers.find((n) => n.row === removedNumbers.row && n.col === removedNumbers.col); number === null || number === void 0 ? void 0 : number.remove(removedNumbers.numbers, removedNumbers.rule); } } solve() { this.allStepsUntilSolution().changes.forEach(change => this.apply(change)); } solvedCount() { return this.numbers.filter(n => n.isSolved()).length; } unsolvedCount() { return 81 - this.solvedCount(); } isSolved() { return this.solvedCount() === 81; } canBeSolved() { return this.isCorrect() && this.solvedCount() + this.allStepsUntilSolution().solvedNumbers().length === 81; } isCorrect() { return this.groups.every(g => g.isCorrect()) && this.numbers.every(n => n.isImpossible() === false); } incorrectGroups() { if (this.isCorrect()) { throw new Error(`This Sudoku is correct!`); } return this.groups.filter(g => !g.isCorrect()); } toString() { const numbers = this.numbers.map(n => n.toSimpleString()); let text = `---------------------\n${numbers[0]}`; for (let i = 1; i < numbers.length; i++) { if (i % 27 === 0) { text += "\n---------------------\n"; } else if (i % 9 === 0) { text += "\n"; } else if (i % 3 === 0) { text += " | "; } else { text += " "; } text += numbers[i]; } text += "\n---------------------"; return text; } toDetailedString() { const numbers = this.numbers.map(n => n.toDetailedString()); let text = `---------------------\n${numbers[0]}`; for (let i = 1; i < numbers.length; i++) { if (i % 27 === 0) { text += "\n---------------------\n"; } else if (i % 9 === 0) { text += "\n"; } else if (i % 3 === 0) { text += " | "; } else { text += " "; } text += numbers[i]; } text += "\n---------------------"; return text; } } exports.Sudoku = Sudoku;