shithub: puzzles

Download patch

ref: 8110518c33c73ab88838bd537fa085e29b1f7c13
parent: 6285c44610cda5146b11fb1fcda45e488a5504de
author: Simon Tatham <anakin@pobox.com>
date: Sat May 23 05:20:49 EDT 2020

Keen: fill in the latin.c validator function.

This seems to make no difference that I can detect: a test generation
run of the form 'keen --generate 1000 6du#12345' outputs an identical
list of 1000 puzzle ids before and after. So the missing validation in
this puzzle seems to have been benign.

--- a/keen.c
+++ b/keen.c
@@ -591,9 +591,90 @@
 #define SOLVER(upper,title,func,lower) func,
 static usersolver_t const keen_solvers[] = { DIFFLIST(SOLVER) };
 
-static bool keen_valid(struct latin_solver *solver, void *ctx)
+static int transpose(int index, int w)
 {
-    return true;                       /* FIXME */
+    return (index % w) * w + (index / w);
+}
+
+static bool keen_valid(struct latin_solver *solver, void *vctx)
+{
+    struct solver_ctx *ctx = (struct solver_ctx *)vctx;
+    int w = ctx->w;
+    int box, i;
+
+    /*
+     * Iterate over each clue box and check it's satisfied.
+     */
+    for (box = 0; box < ctx->nboxes; box++) {
+	int *sq = ctx->boxlist + ctx->boxes[box];
+	int n = ctx->boxes[box+1] - ctx->boxes[box];
+	long value = ctx->clues[box] & ~CMASK;
+	long op = ctx->clues[box] & CMASK;
+        bool fail = false;
+
+        switch (op) {
+          case C_ADD: {
+            long sum = 0;
+            for (i = 0; i < n; i++)
+                sum += solver->grid[transpose(sq[i], w)];
+            fail = (sum != value);
+            break;
+          }
+
+          case C_MUL: {
+            long remaining = value;
+            for (i = 0; i < n; i++) {
+                if (remaining % solver->grid[transpose(sq[i], w)]) {
+                    fail = true;
+                    break;
+                }
+                remaining /= solver->grid[transpose(sq[i], w)];
+            }
+            if (remaining != 1)
+                fail = true;
+            break;
+          }
+
+          case C_SUB:
+            assert(n == 2);
+            if (value != labs(solver->grid[transpose(sq[0], w)] -
+                              solver->grid[transpose(sq[1], w)]))
+                fail = true;
+            break;
+
+          case C_DIV: {
+            int num, den;
+            assert(n == 2);
+            num = max(solver->grid[transpose(sq[0], w)],
+                      solver->grid[transpose(sq[1], w)]);
+            den = min(solver->grid[transpose(sq[0], w)],
+                      solver->grid[transpose(sq[1], w)]);
+            if (den * value != num)
+                fail = true;
+            break;
+          }
+        }
+
+        if (fail) {
+#ifdef STANDALONE_SOLVER
+	    if (solver_show_working) {
+		printf("%*sclue at (%d,%d) is violated\n",
+                       solver_recurse_depth*4, "",
+                       sq[0]/w+1, sq[0]%w+1);
+		printf("%*s  (%s clue with target %ld containing [",
+                       solver_recurse_depth*4, "",
+                       (op == C_ADD ? "addition" : op == C_SUB ? "subtraction":
+                        op == C_MUL ? "multiplication" : "division"), value);
+                for (i = 0; i < n; i++)
+                    printf(" %d", (int)solver->grid[transpose(sq[i], w)]);
+                printf(" ]\n");
+            }
+#endif
+            return false;
+        }
+    }
+
+    return true;
 }
 
 static int solver(int w, int *dsf, long *clues, digit *soln, int maxdiff)