+ int cr = usage->cr;
+ int *bfsqueue = scratch->bfsqueue;
+#ifdef STANDALONE_SOLVER
+ int *bfsprev = scratch->bfsprev;
+#endif
+ unsigned char *number = scratch->grid;
+ int *neighbours = scratch->neighbours;
+ int x, y;
+
+ for (y = 0; y < cr; y++)
+ for (x = 0; x < cr; x++) {
+ int count, t, n;
+
+ /*
+ * If this square doesn't have exactly two candidate
+ * numbers, don't try it.
+ *
+ * In this loop we also sum the candidate numbers,
+ * which is a nasty hack to allow us to quickly find
+ * `the other one' (since we will shortly know there
+ * are exactly two).
+ */
+ for (count = t = 0, n = 1; n <= cr; n++)
+ if (cube(x, y, n))
+ count++, t += n;
+ if (count != 2)
+ continue;
+
+ /*
+ * Now attempt a bfs for each candidate.
+ */
+ for (n = 1; n <= cr; n++)
+ if (cube(x, y, n)) {
+ int orign, currn, head, tail;
+
+ /*
+ * Begin a bfs.
+ */
+ orign = n;
+
+ memset(number, cr+1, cr*cr);
+ head = tail = 0;
+ bfsqueue[tail++] = y*cr+x;
+#ifdef STANDALONE_SOLVER
+ bfsprev[y*cr+x] = -1;
+#endif
+ number[y*cr+x] = t - n;
+
+ while (head < tail) {
+ int xx, yy, nneighbours, xt, yt, i;
+
+ xx = bfsqueue[head++];
+ yy = xx / cr;
+ xx %= cr;
+
+ currn = number[yy*cr+xx];
+
+ /*
+ * Find neighbours of yy,xx.
+ */
+ nneighbours = 0;
+ for (yt = 0; yt < cr; yt++)
+ neighbours[nneighbours++] = yt*cr+xx;
+ for (xt = 0; xt < cr; xt++)
+ neighbours[nneighbours++] = yy*cr+xt;
+ xt = usage->blocks->whichblock[yy*cr+xx];
+ for (yt = 0; yt < cr; yt++)
+ neighbours[nneighbours++] = usage->blocks->blocks[xt][yt];
+ if (usage->diag) {
+ int sqindex = yy*cr+xx;
+ if (ondiag0(sqindex)) {
+ for (i = 0; i < cr; i++)
+ neighbours[nneighbours++] = diag0(i);
+ }
+ if (ondiag1(sqindex)) {
+ for (i = 0; i < cr; i++)
+ neighbours[nneighbours++] = diag1(i);
+ }
+ }
+
+ /*
+ * Try visiting each of those neighbours.
+ */
+ for (i = 0; i < nneighbours; i++) {
+ int cc, tt, nn;
+
+ xt = neighbours[i] % cr;
+ yt = neighbours[i] / cr;
+
+ /*
+ * We need this square to not be
+ * already visited, and to include
+ * currn as a possible number.
+ */
+ if (number[yt*cr+xt] <= cr)
+ continue;
+ if (!cube(xt, yt, currn))
+ continue;
+
+ /*
+ * Don't visit _this_ square a second
+ * time!
+ */
+ if (xt == xx && yt == yy)
+ continue;
+
+ /*
+ * To continue with the bfs, we need
+ * this square to have exactly two
+ * possible numbers.
+ */
+ for (cc = tt = 0, nn = 1; nn <= cr; nn++)
+ if (cube(xt, yt, nn))
+ cc++, tt += nn;
+ if (cc == 2) {
+ bfsqueue[tail++] = yt*cr+xt;
+#ifdef STANDALONE_SOLVER
+ bfsprev[yt*cr+xt] = yy*cr+xx;
+#endif
+ number[yt*cr+xt] = tt - currn;
+ }
+
+ /*
+ * One other possibility is that this
+ * might be the square in which we can
+ * make a real deduction: if it's
+ * adjacent to x,y, and currn is equal
+ * to the original number we ruled out.
+ */
+ if (currn == orign &&
+ (xt == x || yt == y ||
+ (usage->blocks->whichblock[yt*cr+xt] == usage->blocks->whichblock[y*cr+x]) ||
+ (usage->diag && ((ondiag0(yt*cr+xt) && ondiag0(y*cr+x)) ||
+ (ondiag1(yt*cr+xt) && ondiag1(y*cr+x)))))) {
+#ifdef STANDALONE_SOLVER
+ if (solver_show_working) {
+ char *sep = "";
+ int xl, yl;
+ printf("%*sforcing chain, %d at ends of ",
+ solver_recurse_depth*4, "", orign);
+ xl = xx;
+ yl = yy;
+ while (1) {
+ printf("%s(%d,%d)", sep, 1+xl,
+ 1+yl);
+ xl = bfsprev[yl*cr+xl];
+ if (xl < 0)
+ break;
+ yl = xl / cr;
+ xl %= cr;
+ sep = "-";
+ }
+ printf("\n%*s ruling out %d at (%d,%d)\n",
+ solver_recurse_depth*4, "",
+ orign, 1+xt, 1+yt);
+ }
+#endif
+ cube(xt, yt, orign) = FALSE;
+ return 1;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int solver_killer_minmax(struct solver_usage *usage,
+ struct block_structure *cages, digit *clues,
+ int b
+#ifdef STANDALONE_SOLVER
+ , const char *extra
+#endif
+ )
+{
+ int cr = usage->cr;
+ int i;
+ int ret = 0;
+ int nsquares = cages->nr_squares[b];
+
+ if (clues[b] == 0)
+ return 0;
+
+ for (i = 0; i < nsquares; i++) {
+ int n, x = cages->blocks[b][i];
+
+ for (n = 1; n <= cr; n++)
+ if (cube2(x, n)) {
+ int maxval = 0, minval = 0;
+ int j;
+ for (j = 0; j < nsquares; j++) {
+ int m;
+ int y = cages->blocks[b][j];
+ if (i == j)
+ continue;
+ for (m = 1; m <= cr; m++)
+ if (cube2(y, m)) {
+ minval += m;
+ break;
+ }
+ for (m = cr; m > 0; m--)
+ if (cube2(y, m)) {
+ maxval += m;
+ break;
+ }
+ }
+ if (maxval + n < clues[b]) {
+ cube2(x, n) = FALSE;
+ ret = 1;
+#ifdef STANDALONE_SOLVER
+ if (solver_show_working)
+ printf("%*s ruling out %d at (%d,%d) as too low %s\n",
+ solver_recurse_depth*4, "killer minmax analysis",
+ n, 1 + x%cr, 1 + x/cr, extra);
+#endif
+ }
+ if (minval + n > clues[b]) {
+ cube2(x, n) = FALSE;
+ ret = 1;
+#ifdef STANDALONE_SOLVER
+ if (solver_show_working)
+ printf("%*s ruling out %d at (%d,%d) as too high %s\n",
+ solver_recurse_depth*4, "killer minmax analysis",
+ n, 1 + x%cr, 1 + x/cr, extra);
+#endif
+ }
+ }
+ }
+ return ret;
+}
+
+static int solver_killer_sums(struct solver_usage *usage, int b,
+ struct block_structure *cages, int clue,
+ int cage_is_region
+#ifdef STANDALONE_SOLVER
+ , const char *cage_type
+#endif
+ )
+{
+ int cr = usage->cr;
+ int i, ret, max_sums;
+ int nsquares = cages->nr_squares[b];
+ unsigned long *sumbits, possible_addends;
+
+ if (clue == 0) {
+ assert(nsquares == 0);
+ return 0;
+ }
+ assert(nsquares > 0);
+
+ if (nsquares > 4)
+ return 0;
+
+ if (!cage_is_region) {
+ int known_row = -1, known_col = -1, known_block = -1;
+ /*
+ * Verify that the cage lies entirely within one region,
+ * so that using the precomputed sums is valid.
+ */
+ for (i = 0; i < nsquares; i++) {
+ int x = cages->blocks[b][i];
+
+ assert(usage->grid[x] == 0);
+
+ if (i == 0) {
+ known_row = x/cr;
+ known_col = x%cr;
+ known_block = usage->blocks->whichblock[x];
+ } else {
+ if (known_row != x/cr)
+ known_row = -1;
+ if (known_col != x%cr)
+ known_col = -1;
+ if (known_block != usage->blocks->whichblock[x])
+ known_block = -1;
+ }
+ }
+ if (known_block == -1 && known_col == -1 && known_row == -1)
+ return 0;
+ }
+ if (nsquares == 2) {
+ if (clue < 3 || clue > 17)
+ return -1;
+
+ sumbits = sum_bits2[clue];
+ max_sums = MAX_2SUMS;
+ } else if (nsquares == 3) {
+ if (clue < 6 || clue > 24)
+ return -1;
+
+ sumbits = sum_bits3[clue];
+ max_sums = MAX_3SUMS;
+ } else {
+ if (clue < 10 || clue > 30)
+ return -1;
+
+ sumbits = sum_bits4[clue];
+ max_sums = MAX_4SUMS;
+ }
+ /*
+ * For every possible way to get the sum, see if there is
+ * one square in the cage that disallows all the required
+ * addends. If we find one such square, this way to compute
+ * the sum is impossible.
+ */
+ possible_addends = 0;
+ for (i = 0; i < max_sums; i++) {
+ int j;
+ unsigned long bits = sumbits[i];
+
+ if (bits == 0)
+ break;
+
+ for (j = 0; j < nsquares; j++) {
+ int n;
+ unsigned long square_bits = bits;
+ int x = cages->blocks[b][j];
+ for (n = 1; n <= cr; n++)
+ if (!cube2(x, n))
+ square_bits &= ~(1L << n);
+ if (square_bits == 0) {
+ break;
+ }
+ }
+ if (j == nsquares)
+ possible_addends |= bits;
+ }
+ /*
+ * Now we know which addends can possibly be used to
+ * compute the sum. Remove all other digits from the
+ * set of possibilities.
+ */
+ if (possible_addends == 0)
+ return -1;
+
+ ret = 0;
+ for (i = 0; i < nsquares; i++) {
+ int n;
+ int x = cages->blocks[b][i];
+ for (n = 1; n <= cr; n++) {
+ if (!cube2(x, n))
+ continue;
+ if ((possible_addends & (1 << n)) == 0) {
+ cube2(x, n) = FALSE;
+ ret = 1;
+#ifdef STANDALONE_SOLVER
+ if (solver_show_working) {
+ printf("%*s using %s\n",
+ solver_recurse_depth*4, "killer sums analysis",
+ cage_type);
+ printf("%*s ruling out %d at (%d,%d) due to impossible %d-sum\n",
+ solver_recurse_depth*4, "",
+ n, 1 + x%cr, 1 + x/cr, nsquares);
+ }
+#endif
+ }
+ }
+ }
+ return ret;
+}
+
+static int filter_whole_cages(struct solver_usage *usage, int *squares, int n,
+ int *filtered_sum)
+{
+ int b, i, j, off;
+ *filtered_sum = 0;
+
+ /* First, filter squares with a clue. */
+ for (i = j = 0; i < n; i++)
+ if (usage->grid[squares[i]])
+ *filtered_sum += usage->grid[squares[i]];
+ else
+ squares[j++] = squares[i];
+ n = j;
+
+ /*
+ * Filter all cages that are covered entirely by the list of
+ * squares.
+ */
+ off = 0;
+ for (b = 0; b < usage->kblocks->nr_blocks && off < n; b++) {
+ int b_squares = usage->kblocks->nr_squares[b];
+ int matched = 0;
+
+ if (b_squares == 0)
+ continue;
+
+ /*
+ * Find all squares of block b that lie in our list,
+ * and make them contiguous at off, which is the current position
+ * in the output list.
+ */
+ for (i = 0; i < b_squares; i++) {
+ for (j = off; j < n; j++)
+ if (squares[j] == usage->kblocks->blocks[b][i]) {
+ int t = squares[off + matched];
+ squares[off + matched] = squares[j];
+ squares[j] = t;
+ matched++;
+ break;
+ }
+ }
+ /* If so, filter out all squares of b from the list. */
+ if (matched != usage->kblocks->nr_squares[b]) {
+ off += matched;
+ continue;
+ }
+ memmove(squares + off, squares + off + matched,
+ (n - off - matched) * sizeof *squares);
+ n -= matched;
+
+ *filtered_sum += usage->kclues[b];
+ }
+ assert(off == n);
+ return off;
+}
+
+static struct solver_scratch *solver_new_scratch(struct solver_usage *usage)
+{
+ struct solver_scratch *scratch = snew(struct solver_scratch);
+ int cr = usage->cr;
+ scratch->grid = snewn(cr*cr, unsigned char);
+ scratch->rowidx = snewn(cr, unsigned char);
+ scratch->colidx = snewn(cr, unsigned char);
+ scratch->set = snewn(cr, unsigned char);
+ scratch->neighbours = snewn(5*cr, int);
+ scratch->bfsqueue = snewn(cr*cr, int);
+#ifdef STANDALONE_SOLVER
+ scratch->bfsprev = snewn(cr*cr, int);
+#endif
+ scratch->indexlist = snewn(cr*cr, int); /* used for set elimination */
+ scratch->indexlist2 = snewn(cr, int); /* only used for intersect() */
+ return scratch;
+}
+
+static void solver_free_scratch(struct solver_scratch *scratch)
+{
+#ifdef STANDALONE_SOLVER
+ sfree(scratch->bfsprev);
+#endif
+ sfree(scratch->bfsqueue);
+ sfree(scratch->neighbours);
+ sfree(scratch->set);
+ sfree(scratch->colidx);
+ sfree(scratch->rowidx);
+ sfree(scratch->grid);
+ sfree(scratch->indexlist);
+ sfree(scratch->indexlist2);
+ sfree(scratch);
+}
+
+/*
+ * Used for passing information about difficulty levels between the solver
+ * and its callers.
+ */
+struct difficulty {
+ /* Maximum levels allowed. */
+ int maxdiff, maxkdiff;
+ /* Levels reached by the solver. */
+ int diff, kdiff;
+};
+
+static void solver(int cr, struct block_structure *blocks,
+ struct block_structure *kblocks, int xtype,
+ digit *grid, digit *kgrid, struct difficulty *dlev)
+{
+ struct solver_usage *usage;
+ struct solver_scratch *scratch;
+ int x, y, b, i, n, ret;