mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 08:01:30 -07:00
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.
This commit is contained in:
79
dominosa.c
79
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 <stdio.h>
|
||||
@ -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
|
||||
|
Reference in New Issue
Block a user