From 2ec6daee32ad7b2967141aa52ee3327af8055e67 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 2 Apr 2019 21:32:29 +0100 Subject: [PATCH] Dominosa: new deduction deduce_local_duplicate(). This is a reasonably simple local deduction I've been using myself for ages, and feel comfortable adding to the existing Basic difficulty level. --- dominosa.c | 79 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 14 deletions(-) diff --git a/dominosa.c b/dominosa.c index d7e9306..5328e4e 100644 --- a/dominosa.c +++ b/dominosa.c @@ -42,17 +42,6 @@ * careful that we don't rule out precisely the domino * placement that was _included_ in our set! * - * * playing off the two ends of one potential domino, by - * considering the alternatives to that domino that each end - * might otherwise be part of. - * + if not playing this domino would require each end to be - * part of an identical domino, play it. (e.g. the middle of - * 5-4-4-5) - * + if not playing this domino would guarantee that the two - * ends between them used up all of some other square's - * choices, play it. (e.g. the middle of 2-3-3-1 if another 3 - * cell can only link to a 2 or a 1) - * * * identify 'forcing chains', in the sense of any path of cells * each of which has only two possible dominoes to be part of, * and each of those rules out one of the choices for the next @@ -62,8 +51,6 @@ * the chain, or using up all of some other square's choices), * then the whole set can be ruled out, and the other set played * immediately. - * + this is of course a generalisation of the previous idea, - * which is simply a forcing chain of length 3. */ #include @@ -539,6 +526,15 @@ static void solver_setup_grid(struct solver_scratch *sc, const int *numbers) sc->max_diff_used = DIFF_TRIVIAL; } +/* Given two placements p,q that overlap, returns si such that + * p->squares[si] is the square also in q */ +static int common_square_index(struct solver_placement *p, + struct solver_placement *q) +{ + return (p->squares[0] == q->squares[0] || + p->squares[0] == q->squares[1]) ? 0 : 1; +} + static void rule_out_placement( struct solver_scratch *sc, struct solver_placement *p) { @@ -744,6 +740,53 @@ static bool deduce_domino_must_overlap(struct solver_scratch *sc, int di) return true; } + +/* + * If a placement of domino D overlaps the only remaining placement + * for some square S which is not also for domino D, then placing D + * here would require another copy of it in S, so we can rule it out. + */ +static bool deduce_local_duplicate(struct solver_scratch *sc, int pi) +{ + struct solver_placement *p = &sc->placements[pi]; + struct solver_domino *d = p->domino; + int i, j; + + if (!p->active) + return false; + + for (i = 0; i < p->noverlaps; i++) { + struct solver_placement *q = p->overlaps[i]; + struct solver_square *sq; + + if (!q->active) + continue; + + /* Find the square of q that _isn't_ part of p */ + sq = q->squares[1 - common_square_index(q, p)]; + + for (j = 0; j < sq->nplacements; j++) + if (sq->placements[j] != q && sq->placements[j]->domino != d) + goto no; + + /* If we get here, every possible placement for sq is either q + * itself, or another copy of d. Success! We can rule out p. */ +#ifdef SOLVER_DIAGNOSTICS + if (solver_diagnostics) { + printf("placement %s of domino %s would force another copy of %s " + "in square %s\n", p->name, d->name, d->name, sq->name); + } +#endif + + rule_out_placement(sc, p); + return true; + + no:; + } + + return false; +} + /* * Run the solver until it can't make any more progress. * @@ -755,7 +798,7 @@ static bool deduce_domino_must_overlap(struct solver_scratch *sc, int di) */ static int run_solver(struct solver_scratch *sc, int max_diff_allowed) { - int di, si; + int di, si, pi; bool done_something; #ifdef SOLVER_DIAGNOSTICS @@ -810,6 +853,14 @@ static int run_solver(struct solver_scratch *sc, int max_diff_allowed) continue; } + for (pi = 0; pi < sc->pc; pi++) + if (deduce_local_duplicate(sc, pi)) + done_something = true; + if (done_something) { + sc->max_diff_used = max(sc->max_diff_used, DIFF_BASIC); + continue; + } + } while (done_something); #ifdef SOLVER_DIAGNOSTICS