diff --git a/Makefile b/Makefile
index ecb8727..b004aaf 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
CFLAGS += -std=c11 -pedantic -Wall -Wextra
CFLAGS += -O2 -flto
-SRC = main.c sud.c
+SRC = main.c sud.c solve.c
OBJ = $(SRC:.c=.o)
sudoku: $(OBJ)
@@ -26,7 +26,8 @@ sudoku: $(OBJ)
clean:
rm -f sudoku $(OBJ)
-main.o: sud.h
+main.o: sud.h solve.h
sud.o: sud.h
+solve.o: solve.h
.PHONY: clean
diff --git a/main.c b/main.c
index 143f2bb..8816d2c 100644
--- a/main.c
+++ b/main.c
@@ -16,6 +16,7 @@
* .
*/
+#include "solve.h"
#include "sud.h"
#include
@@ -45,7 +46,17 @@ int main(void)
struct sudoku sud;
gen(&sud);
+ puts("Start:");
print(&sud);
+ putchar('\n');
+
+ bool res = solve(&sud);
+ if (!res) {
+ puts("Solver encountered an error\n");
+ } else {
+ puts("End:");
+ print(&sud);
+ }
return 0;
}
diff --git a/solve.c b/solve.c
new file mode 100644
index 0000000..ed9fb61
--- /dev/null
+++ b/solve.c
@@ -0,0 +1,129 @@
+/*
+ * 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;
+ }
+}
diff --git a/solve.h b/solve.h
new file mode 100644
index 0000000..1f65e7b
--- /dev/null
+++ b/solve.h
@@ -0,0 +1,30 @@
+/*
+ * 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
+ * .
+ */
+
+#ifndef SOLVE_H
+#define SOLVE_H
+
+#include "sud.h"
+
+/**
+ * Attempt to solve the given sudoku. Returns when no rules match for
+ * an entire pass over the puzzle.
+ */
+bool solve(struct sudoku *sud);
+
+#endif