jassl
Version:
Just Another Sudoku Solving Library
107 lines (83 loc) • 3.23 kB
JavaScript
const {isUINT} = require('./misc/util.js');
const uniqueInGroup = (self, group, candidate) => !group.cells.find(groupCell => self !== groupCell && !groupCell.solved && groupCell.candidates.indexOf(candidate) > -1);
module.exports = class SudokuCell {
constructor(sudoku, index) {
this.sudoku = sudoku;
this.index = index;
this.candidates = Array(sudoku.groupLength).fill().map((value, index) => index + 1);
this.solved = false;
}
exclude(candidate) {
// Throw error if candidate is not between 1 and groupLength
if (!isUINT(candidate, {min: 1, max: this.sudoku.groupLength})) {
throw new Error('invalid candidate');
}
// return false if the cell has already been solved
if (this.solved) {
return false;
}
// find the specified candidate in the cell's candidates list
let idx = this.candidates.findIndex(value => value === candidate);
// candidate not found
if (idx === -1) {
return false;
}
// no candidates would be left for the cells
if (this.candidates.length === 1) {
throw new Error('No candidates would be left');
}
// remove the candidate
this.candidates.splice(idx, 1);
// return true indicating the cell was changed
return true;
}
solveTo(solution) {
// Throw error if solution is not between 1 and groupLength
if (!isUINT(solution, {min: 1, max: this.sudoku.groupLength})) {
throw new Error('invalid solution');
}
// Throw error if the cell has already been solved
if (this.solved) {
throw new Error('cell already solved');
}
// Throw error if the candidate is not in the cell's candidate list
if (this.candidates.indexOf(solution) === -1) {
throw new Error('given solution for cell is not valid');
}
// Update cell
this.value = solution;
this.solved = true;
this.candidates = [];
// Remove the solution from candidate lists of cells that share this row column or sector
this.row.exclude(solution);
this.column.exclude(solution);
this.sector.exclude(solution);
return true;
}
solve() {
// cell has already been solved
if (this.solved) {
return false;
}
// Sole Candidate
if (this.candidates.length === 1) {
return this.solveTo(this.candidates[0]);
}
// Attempt to find a candidate that is unique to the cell
let uniqueCandidate = this.candidates.find(candidate => {
if (
uniqueInGroup(this, this.row, candidate) ||
uniqueInGroup(this, this.column, candidate) ||
uniqueInGroup(this, this.sector, candidate)
) {
return true;
}
});
// No unqiue candidates for the cell
if (!uniqueCandidate) {
return false;
}
// solve the cell using the uniqueCandidate as the solution
return this.solveTo(uniqueCandidate);
}
};