diff --git a/solve.c b/solve.c index ba9c90a..f17ae60 100644 --- a/solve.c +++ b/solve.c @@ -20,106 +20,98 @@ #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, np, pr, pc; + unsigned r, c, n, i, j, val, sr, sc; bool match; uint16_t valmask, pvals; for (n = 0;; ++n) { match = false; - /* Check if only one place a value can go on each row. */ - for (r = 0; r < NDIGITS; ++r) { - for (val = 0; val < NDIGITS; ++val) { - valmask = 1 << val; - - np = 0; - for (c = 0; c < NDIGITS; ++c) { - if (!(sud->cells[r][c] & DETMASK) - && sud->cells[r][c] & valmask) { - pr = r; - pc = c; - ++np; - if (np > 1) - break; - } - } - if (np == 1) { - if (update(sud, pr, pc, val) != OK) - return -1; - match = true; - } - } - } - - /* Check if only one place a value can go on each column. */ - for (c = 0; c < NDIGITS; ++c) { - for (val = 0; val < NDIGITS; ++val) { - valmask = 1 << val; - - np = 0; - for (r = 0; r < NDIGITS; ++r) { - if (!(sud->cells[r][c] & DETMASK) - && sud->cells[r][c] & valmask) { - pr = r; - pc = c; - ++np; - if (np > 1) - break; - } - } - if (np == 1) { - if (update(sud, pr, pc, val) != OK) - return -1; - match = true; - } - } - } - - /* Check if only one place a value can go in each segment. */ - for (i = 0; i < NDIGITS; ++i) { - for (val = 0; val < NDIGITS; ++val) { - valmask = 1 << val; - - np = 0; - for (j = 0; j < NDIGITS; ++j) { - r = SEGLEN * (i / SEGLEN) + j / SEGLEN; - c = SEGLEN * (i % SEGLEN) + j % SEGLEN; - if (!(sud->cells[r][c] & DETMASK) - && sud->cells[r][c] & valmask) { - pr = r; - pc = c; - ++np; - if (np > 1) - break; - } - } - if (np == 1) { - if (update(sud, pr, pc, val) != OK) - return -1; - match = true; - } - } - } - - /* Check each cell for if it has only one possible value. */ 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:; } }