Add a facility in the latin.c solver diagnostics to allow a puzzle

to call the digit values by custom names.

[originally from svn r8811]
This commit is contained in:
Simon Tatham
2010-01-05 23:40:40 +00:00
parent a7b220ff9a
commit 13d7ff6ae5
2 changed files with 111 additions and 25 deletions

132
latin.c
View File

@ -16,6 +16,12 @@
* Solver. * Solver.
*/ */
static int latin_solver_top(struct latin_solver *solver, int maxdiff,
int diff_simple, int diff_set_0, int diff_set_1,
int diff_forcing, int diff_recursive,
usersolver_t const *usersolvers, void *ctx,
ctxnew_t ctxnew, ctxfree_t ctxfree);
#ifdef STANDALONE_SOLVER #ifdef STANDALONE_SOLVER
int solver_show_working, solver_recurse_depth; int solver_show_working, solver_recurse_depth;
#endif #endif
@ -72,6 +78,9 @@ int latin_solver_elim(struct latin_solver *solver, int start, int step
) )
{ {
int o = solver->o; int o = solver->o;
#ifdef STANDALONE_SOLVER
char **names = solver->names;
#endif
int fpos, m, i; int fpos, m, i;
/* /*
@ -103,8 +112,9 @@ int latin_solver_elim(struct latin_solver *solver, int start, int step
va_start(ap, fmt); va_start(ap, fmt);
vprintf(fmt, ap); vprintf(fmt, ap);
va_end(ap); va_end(ap);
printf(":\n%*s placing %d at (%d,%d)\n", printf(":\n%*s placing %s at (%d,%d)\n",
solver_recurse_depth*4, "", n, x+1, YUNTRANS(y)+1); solver_recurse_depth*4, "", names[n-1],
x+1, YUNTRANS(y)+1);
} }
#endif #endif
latin_solver_place(solver, x, y, n); latin_solver_place(solver, x, y, n);
@ -145,6 +155,9 @@ int latin_solver_set(struct latin_solver *solver,
) )
{ {
int o = solver->o; int o = solver->o;
#ifdef STANDALONE_SOLVER
char **names = solver->names;
#endif
int i, j, n, count; int i, j, n, count;
unsigned char *grid = scratch->grid; unsigned char *grid = scratch->grid;
unsigned char *rowidx = scratch->rowidx; unsigned char *rowidx = scratch->rowidx;
@ -292,9 +305,9 @@ int latin_solver_set(struct latin_solver *solver,
px = py / o; px = py / o;
py %= o; py %= o;
printf("%*s ruling out %d at (%d,%d)\n", printf("%*s ruling out %s at (%d,%d)\n",
solver_recurse_depth*4, "", solver_recurse_depth*4, "",
pn, px+1, YUNTRANS(py)+1); names[pn-1], px+1, YUNTRANS(py)+1);
} }
#endif #endif
progress = TRUE; progress = TRUE;
@ -365,6 +378,9 @@ int latin_solver_forcing(struct latin_solver *solver,
struct latin_solver_scratch *scratch) struct latin_solver_scratch *scratch)
{ {
int o = solver->o; int o = solver->o;
#ifdef STANDALONE_SOLVER
char **names = solver->names;
#endif
int *bfsqueue = scratch->bfsqueue; int *bfsqueue = scratch->bfsqueue;
#ifdef STANDALONE_SOLVER #ifdef STANDALONE_SOLVER
int *bfsprev = scratch->bfsprev; int *bfsprev = scratch->bfsprev;
@ -485,8 +501,9 @@ int latin_solver_forcing(struct latin_solver *solver,
if (solver_show_working) { if (solver_show_working) {
char *sep = ""; char *sep = "";
int xl, yl; int xl, yl;
printf("%*sforcing chain, %d at ends of ", printf("%*sforcing chain, %s at ends of ",
solver_recurse_depth*4, "", orign); solver_recurse_depth*4, "",
names[orign-1]);
xl = xx; xl = xx;
yl = yy; yl = yy;
while (1) { while (1) {
@ -499,9 +516,10 @@ int latin_solver_forcing(struct latin_solver *solver,
xl %= o; xl %= o;
sep = "-"; sep = "-";
} }
printf("\n%*s ruling out %d at (%d,%d)\n", printf("\n%*s ruling out %s at (%d,%d)\n",
solver_recurse_depth*4, "", solver_recurse_depth*4, "",
orign, xt+1, YUNTRANS(yt)+1); names[orign-1],
xt+1, YUNTRANS(yt)+1);
} }
#endif #endif
cube(xt, yt, orign) = FALSE; cube(xt, yt, orign) = FALSE;
@ -563,6 +581,10 @@ void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o)
for (y = 0; y < o; y++) for (y = 0; y < o; y++)
if (grid[y*o+x]) if (grid[y*o+x])
latin_solver_place(solver, x, YTRANS(y), grid[y*o+x]); latin_solver_place(solver, x, YTRANS(y), grid[y*o+x]);
#ifdef STANDALONE_SOLVER
solver->names = NULL;
#endif
} }
void latin_solver_free(struct latin_solver *solver) void latin_solver_free(struct latin_solver *solver)
@ -575,6 +597,10 @@ void latin_solver_free(struct latin_solver *solver)
int latin_solver_diff_simple(struct latin_solver *solver) int latin_solver_diff_simple(struct latin_solver *solver)
{ {
int x, y, n, ret, o = solver->o; int x, y, n, ret, o = solver->o;
#ifdef STANDALONE_SOLVER
char **names = solver->names;
#endif
/* /*
* Row-wise positional elimination. * Row-wise positional elimination.
*/ */
@ -584,7 +610,8 @@ int latin_solver_diff_simple(struct latin_solver *solver)
ret = latin_solver_elim(solver, cubepos(0,y,n), o*o ret = latin_solver_elim(solver, cubepos(0,y,n), o*o
#ifdef STANDALONE_SOLVER #ifdef STANDALONE_SOLVER
, "positional elimination," , "positional elimination,"
" %d in row %d", n, YUNTRANS(y)+1 " %s in row %d", names[n-1],
YUNTRANS(y)+1
#endif #endif
); );
if (ret != 0) return ret; if (ret != 0) return ret;
@ -598,7 +625,7 @@ int latin_solver_diff_simple(struct latin_solver *solver)
ret = latin_solver_elim(solver, cubepos(x,0,n), o ret = latin_solver_elim(solver, cubepos(x,0,n), o
#ifdef STANDALONE_SOLVER #ifdef STANDALONE_SOLVER
, "positional elimination," , "positional elimination,"
" %d in column %d", n, x+1 " %s in column %d", names[n-1], x+1
#endif #endif
); );
if (ret != 0) return ret; if (ret != 0) return ret;
@ -626,6 +653,9 @@ int latin_solver_diff_set(struct latin_solver *solver,
int extreme) int extreme)
{ {
int x, y, n, ret, o = solver->o; int x, y, n, ret, o = solver->o;
#ifdef STANDALONE_SOLVER
char **names = solver->names;
#endif
if (!extreme) { if (!extreme) {
/* /*
@ -658,7 +688,8 @@ int latin_solver_diff_set(struct latin_solver *solver,
for (n = 1; n <= o; n++) { for (n = 1; n <= o; n++) {
ret = latin_solver_set(solver, scratch, cubepos(0,0,n), o*o, o ret = latin_solver_set(solver, scratch, cubepos(0,0,n), o*o, o
#ifdef STANDALONE_SOLVER #ifdef STANDALONE_SOLVER
, "positional set elimination, number %d", n , "positional set elimination on %s",
names[n-1]
#endif #endif
); );
if (ret != 0) return ret; if (ret != 0) return ret;
@ -685,6 +716,9 @@ static int latin_solver_recurse
{ {
int best, bestcount; int best, bestcount;
int o = solver->o, x, y, n; int o = solver->o, x, y, n;
#ifdef STANDALONE_SOLVER
char **names = solver->names;
#endif
best = -1; best = -1;
bestcount = o+1; bestcount = o+1;
@ -745,7 +779,7 @@ static int latin_solver_recurse
printf("%*srecursing on (%d,%d) [", printf("%*srecursing on (%d,%d) [",
solver_recurse_depth*4, "", x+1, y+1); solver_recurse_depth*4, "", x+1, y+1);
for (i = 0; i < j; i++) { for (i = 0; i < j; i++) {
printf("%s%d", sep, list[i]); printf("%s%s", sep, names[list[i]-1]);
sep = " or "; sep = " or ";
} }
printf("]\n"); printf("]\n");
@ -759,14 +793,15 @@ static int latin_solver_recurse
for (i = 0; i < j; i++) { for (i = 0; i < j; i++) {
int ret; int ret;
void *newctx; void *newctx;
struct latin_solver subsolver;
memcpy(outgrid, ingrid, o*o); memcpy(outgrid, ingrid, o*o);
outgrid[y*o+x] = list[i]; outgrid[y*o+x] = list[i];
#ifdef STANDALONE_SOLVER #ifdef STANDALONE_SOLVER
if (solver_show_working) if (solver_show_working)
printf("%*sguessing %d at (%d,%d)\n", printf("%*sguessing %s at (%d,%d)\n",
solver_recurse_depth*4, "", list[i], x+1, y+1); solver_recurse_depth*4, "", names[list[i]-1], x+1, y+1);
solver_recurse_depth++; solver_recurse_depth++;
#endif #endif
@ -775,18 +810,23 @@ static int latin_solver_recurse
} else { } else {
newctx = ctx; newctx = ctx;
} }
ret = latin_solver(outgrid, o, diff_recursive, latin_solver_alloc(&subsolver, outgrid, o);
diff_simple, diff_set_0, diff_set_1, #ifdef STANDALONE_SOLVER
diff_forcing, diff_recursive, subsolver.names = solver->names;
usersolvers, newctx, ctxnew, ctxfree); #endif
ret = latin_solver_top(&subsolver, diff_recursive,
diff_simple, diff_set_0, diff_set_1,
diff_forcing, diff_recursive,
usersolvers, newctx, ctxnew, ctxfree);
latin_solver_free(&subsolver);
if (ctxnew) if (ctxnew)
ctxfree(newctx); ctxfree(newctx);
#ifdef STANDALONE_SOLVER #ifdef STANDALONE_SOLVER
solver_recurse_depth--; solver_recurse_depth--;
if (solver_show_working) { if (solver_show_working) {
printf("%*sretracting %d at (%d,%d)\n", printf("%*sretracting %s at (%d,%d)\n",
solver_recurse_depth*4, "", list[i], x+1, y+1); solver_recurse_depth*4, "", names[list[i]-1], x+1, y+1);
} }
#endif #endif
/* we recurse as deep as we can, so we should never find /* we recurse as deep as we can, so we should never find
@ -836,11 +876,11 @@ static int latin_solver_recurse
} }
} }
int latin_solver_main(struct latin_solver *solver, int maxdiff, static int latin_solver_top(struct latin_solver *solver, int maxdiff,
int diff_simple, int diff_set_0, int diff_set_1, int diff_simple, int diff_set_0, int diff_set_1,
int diff_forcing, int diff_recursive, int diff_forcing, int diff_recursive,
usersolver_t const *usersolvers, void *ctx, usersolver_t const *usersolvers, void *ctx,
ctxnew_t ctxnew, ctxfree_t ctxfree) ctxnew_t ctxnew, ctxfree_t ctxfree)
{ {
struct latin_solver_scratch *scratch = latin_solver_new_scratch(solver); struct latin_solver_scratch *scratch = latin_solver_new_scratch(solver);
int ret, diff = diff_simple; int ret, diff = diff_simple;
@ -938,6 +978,48 @@ int latin_solver_main(struct latin_solver *solver, int maxdiff,
return diff; return diff;
} }
int latin_solver_main(struct latin_solver *solver, int maxdiff,
int diff_simple, int diff_set_0, int diff_set_1,
int diff_forcing, int diff_recursive,
usersolver_t const *usersolvers, void *ctx,
ctxnew_t ctxnew, ctxfree_t ctxfree)
{
int diff;
#ifdef STANDALONE_SOLVER
int o = solver->o;
char *text = NULL, **names = NULL;
#endif
#ifdef STANDALONE_SOLVER
if (!solver->names) {
char *p;
int i;
text = snewn(40 * o, char);
p = text;
solver->names = snewn(o, char *);
for (i = 0; i < o; i++) {
solver->names[i] = p;
p += 1 + sprintf(p, "%d", i+1);
}
}
#endif
diff = latin_solver_top(solver, maxdiff,
diff_simple, diff_set_0, diff_set_1,
diff_forcing, diff_recursive,
usersolvers, ctx, ctxnew, ctxfree);
#ifdef STANDALONE_SOLVER
sfree(names);
sfree(text);
#endif
return diff;
}
int latin_solver(digit *grid, int o, int maxdiff, int latin_solver(digit *grid, int o, int maxdiff,
int diff_simple, int diff_set_0, int diff_set_1, int diff_simple, int diff_set_0, int diff_set_1,
int diff_forcing, int diff_recursive, int diff_forcing, int diff_recursive,

View File

@ -19,6 +19,10 @@ struct latin_solver {
unsigned char *row; /* o^2: row[y*cr+n-1] TRUE if n is in row y */ unsigned char *row; /* o^2: row[y*cr+n-1] TRUE if n is in row y */
unsigned char *col; /* o^2: col[x*cr+n-1] TRUE if n is in col x */ unsigned char *col; /* o^2: col[x*cr+n-1] TRUE if n is in col x */
#ifdef STANDALONE_SOLVER
char **names; /* o: names[n-1] gives name of 'digit' n */
#endif
}; };
#define cubepos(x,y,n) (((x)*solver->o+(y))*solver->o+(n)-1) #define cubepos(x,y,n) (((x)*solver->o+(y))*solver->o+(n)-1)
#define cube(x,y,n) (solver->cube[cubepos(x,y,n)]) #define cube(x,y,n) (solver->cube[cubepos(x,y,n)])