/*
* Copyright (C) 2022 Camden Dixie O'Brien
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this program. If not, see
* .
*/
#include "solve.h"
#include
static void setpval(struct sudoku *sud, unsigned r, unsigned c, uint16_t pval)
{
for (unsigned val = 0; val < NDIGITS; ++val) {
if (pval & 1) {
update(sud, r, c, val);
return;
}
pval >>= 1;
}
}
int solve(struct sudoku *sud)
{
unsigned r, c, n, i, j, val, sr, sc;
bool match;
uint16_t valmask, pvals;
for (n = 0;; ++n) {
match = false;
for (r = 0; r < NDIGITS; ++r) {
for (c = 0; c < NDIGITS; ++c) {
if (DET(sud->cells[r][c]))
continue;
/*
* Check if there's only one possible value this cell
* can have.
*/
pvals = sud->cells[r][c] & PVALSMASK;
for (val = 0; val < NDIGITS; ++val) {
if (pvals & 1) {
if (pvals == 1) {
update(sud, r, c, val);
match = true;
goto next_cell;
}
break;
}
pvals >>= 1;
}
/*
* Check if there's a possible value unique to this
* cell in its row.
*/
valmask = 0;
for (i = 0; i < NDIGITS; ++i) {
if (i != r && !DET(sud->cells[i][c]))
valmask |= sud->cells[i][c];
}
if ((pvals = sud->cells[r][c] & ~valmask)) {
setpval(sud, r, c, pvals);
match = true;
continue;
}
/*
* Check if there's a possible value unique to this
* cell in its column.
*/
valmask = 0;
for (i = 0; i < NDIGITS; ++i) {
if (i != c && !DET(sud->cells[r][i]))
valmask |= sud->cells[r][i];
}
if ((pvals = sud->cells[r][c] & ~valmask)) {
setpval(sud, r, c, pvals);
match = true;
continue;
}
/*
* Check if there's a possible value unique to this
* cell in its segment.
*/
sr = SEGLEN * (r / SEGLEN);
sc = SEGLEN * (c / SEGLEN);
valmask = 0;
for (i = sr; i < sr + SEGLEN; ++i) {
for (j = sc; j < sc + SEGLEN; ++j) {
if ((i != r || j != c) && !DET(sud->cells[i][j]))
valmask |= sud->cells[i][j];
}
}
if ((pvals = sud->cells[r][c] & ~valmask)) {
setpval(sud, r, c, pvals);
match = true;
continue;
}
next_cell:;
}
}
/* Exit if no matches. */
if (!match)
return n;
}
}