ref: 1114a2af332ecfa61a3ae0df478d26b9a3b863a4
parent: d96298ed0100873c59b3be698b01c369f888499b
author: Simon Tatham <anakin@pobox.com>
date: Sat Apr 13 07:26:54 EDT 2019
Dominosa: another forcing-chain based deduction. We've already spotted when a domino occurs twice in the _same_ forcing chain. But now we also spot when it occurs twice in the same _pair_ of complementary forcing chains, one in each of the two options. Then it must appear in one of those two places, and hence, can't appear anywhere else.
--- a/dominosa.c
+++ b/dominosa.c
@@ -1347,6 +1347,10 @@
* Now read out the whole dsf into pc_scratch, flattening its
* structured data into a simple integer id per chain of dominoes
* that must occur together.
+ *
+ * The integer ids have the property that any two that differ only
+ * in the lowest bit (i.e. of the form {2n,2n+1}) represent
+ * complementary chains, each of which rules out the other.
*/
for (pi = 0; pi < sc->pc; pi++) {
bool inv;
@@ -1516,6 +1520,64 @@
done_something = true;
}
+ }
+
+ /*
+ * Another thing you can do with forcing chains, besides ruling
+ * out a whole one at a time, is to look at each pair of chains
+ * that overlap each other. Each such pair gives you two sets of
+ * domino placements, such that if either set is not placed, then
+ * the other one must be.
+ *
+ * This means that any domino which has a placement in _both_
+ * chains of a pair must occupy one of those two placements, i.e.
+ * we can rule that domino out anywhere else it might appear.
+ */
+ for (di = 0; di < sc->dc; di++) {
+ struct solver_domino *d = &sc->dominoes[di];
+
+ if (d->nplacements <= 2)
+ continue; /* not enough placements to rule one out */
+
+ for (j = 0; j+1 < d->nplacements; j++) {
+ int ij = d->placements[j]->index;
+ int cj = sc->pc_scratch[ij];
+ for (k = j+1; k < d->nplacements; k++) {
+ int ik = d->placements[k]->index;
+ int ck = sc->pc_scratch[ik];
+ if ((cj ^ ck) == 1) {
+ /*
+ * Placements j,k of domino d are in complementary
+ * chains, so we can rule out all the others.
+ */
+ int i;
+
+#ifdef SOLVER_DIAGNOSTICS
+ if (solver_diagnostics) {
+ printf("domino %s occurs in both complementary "
+ "forced chains:", d->name);
+ for (i = 0; i < sc->pc; i++)
+ if (sc->pc_scratch[i] == cj)
+ printf(" %s", sc->placements[i].name);
+ printf(" and");
+ for (i = 0; i < sc->pc; i++)
+ if (sc->pc_scratch[i] == ck)
+ printf(" %s", sc->placements[i].name);
+ printf("\n");
+ }
+#endif
+
+ for (i = d->nplacements; i-- > 0 ;)
+ if (i != j && i != k)
+ rule_out_placement(sc, d->placements[i]);
+
+ done_something = true;
+ goto done_this_domino;
+ }
+ }
+ }
+
+ done_this_domino:;
}
return done_something;