/* * 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 int solve(struct sudoku *sud) { unsigned r, c, n, i, j, val, np, pr, pc; 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; 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; } break; } pvals >>= 1; } } } /* Exit if no matches. */ if (!match) return n; } }