/* * 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 struct match { unsigned row; unsigned col; unsigned val; }; struct cellref { unsigned row, col; struct cellstate *state; }; enum apply_res { ERROR, NO_MATCH, MATCH }; typedef struct cellref cellgroup[NDIGITS]; typedef bool (*rulefn)(cellgroup *group, struct match *match_out); static bool one_place_for_digit(cellgroup *group, struct match *match_out) { for (unsigned val = 0; val < NDIGITS; ++val) { unsigned n = 0, row = NDIGITS, col = NDIGITS; for (unsigned i = 0; i < NDIGITS; ++i) { if (!(*group)[i].state->det && (*group)[i].state->pvals[val]) { row = (*group)[i].row; col = (*group)[i].col; ++n; if (n > 1) break; } } if (n == 1) { match_out->row = row; match_out->col = col; match_out->val = val; return true; } } return false; } static const rulefn rules[] = { &one_place_for_digit, }; static const unsigned nrules = sizeof(rules) / sizeof(rules[0]); static enum apply_res apply_rules(struct sudoku *sud, cellgroup *group) { struct match m; bool matched = false; for (unsigned i = 0; i < nrules; ++i) { if (!rules[i](group, &m)) continue; if (!update(sud, m.row, m.col, m.val)) return ERROR; matched = true; } return matched ? MATCH : NO_MATCH; } bool solve(struct sudoku *sud) { cellgroup group = { 0 }; unsigned r, c; bool match; enum apply_res res; for (unsigned i = 0;; ++i) { match = false; /* Apply rules to each row. */ for (r = 0; r < NDIGITS; ++r) { for (c = 0; c < NDIGITS; ++c) { group[c].row = r; group[c].col = c; group[c].state = &sud->cells[r][c]; } res = apply_rules(sud, &group); if (res == ERROR) return false; else if (res == MATCH) match = true; } /* Apply rules to each column. */ for (c = 0; c < NDIGITS; ++c) { for (r = 0; r < NDIGITS; ++r) { group[r].row = r; group[r].col = c; group[r].state = &sud->cells[r][c]; } res = apply_rules(sud, &group); if (res == ERROR) return false; else if (res == MATCH) match = true; } /* TODO: Apply rules to each segment. */ /* Exit if no matches. */ if (!match) return true; } }