#include "puzzles.h"
-#define max(x,y) ((x)>(y)?(x):(y))
-
/*
* To save space, I store digits internally as unsigned char. This
* imposes a hard limit of 255 on the order of the puzzle. Since
{ "3x3 Intermediate", { 3, 3, SYMM_ROT2, DIFF_INTERSECT } },
{ "3x3 Advanced", { 3, 3, SYMM_ROT2, DIFF_SET } },
{ "3x3 Unreasonable", { 3, 3, SYMM_ROT2, DIFF_RECURSIVE } },
+#ifndef SLOW_SYSTEM
{ "3x4 Basic", { 3, 4, SYMM_ROT2, DIFF_SIMPLE } },
{ "4x4 Basic", { 4, 4, SYMM_ROT2, DIFF_SIMPLE } },
+#endif
};
if (i < 0 || i >= lenof(presets))
return ret;
}
+struct nsolve_scratch {
+ unsigned char *grid, *rowidx, *colidx, *set;
+};
+
static int nsolve_set(struct nsolve_usage *usage,
+ struct nsolve_scratch *scratch,
int start, int step1, int step2
#ifdef STANDALONE_SOLVER
, char *fmt, ...
{
int c = usage->c, r = usage->r, cr = c*r;
int i, j, n, count;
- unsigned char *grid = snewn(cr*cr, unsigned char);
- unsigned char *rowidx = snewn(cr, unsigned char);
- unsigned char *colidx = snewn(cr, unsigned char);
- unsigned char *set = snewn(cr, unsigned char);
+ unsigned char *grid = scratch->grid;
+ unsigned char *rowidx = scratch->rowidx;
+ unsigned char *colidx = scratch->colidx;
+ unsigned char *set = scratch->set;
/*
* We are passed a cr-by-cr matrix of booleans. Our first job
}
if (progress) {
- sfree(set);
- sfree(colidx);
- sfree(rowidx);
- sfree(grid);
return TRUE;
}
}
break; /* done */
}
- sfree(set);
- sfree(colidx);
- sfree(rowidx);
- sfree(grid);
-
return FALSE;
}
+static struct nsolve_scratch *nsolve_new_scratch(struct nsolve_usage *usage)
+{
+ struct nsolve_scratch *scratch = snew(struct nsolve_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);
+ return scratch;
+}
+
+static void nsolve_free_scratch(struct nsolve_scratch *scratch)
+{
+ sfree(scratch->set);
+ sfree(scratch->colidx);
+ sfree(scratch->rowidx);
+ sfree(scratch->grid);
+ sfree(scratch);
+}
+
static int nsolve(int c, int r, digit *grid)
{
struct nsolve_usage *usage;
+ struct nsolve_scratch *scratch;
int cr = c*r;
int x, y, n;
int diff = DIFF_BLOCK;
memset(usage->col, FALSE, cr * cr);
memset(usage->blk, FALSE, cr * cr);
+ scratch = nsolve_new_scratch(usage);
+
/*
* Place all the clue numbers we are given.
*/
*/
for (x = 0; x < cr; x += r)
for (y = 0; y < r; y++)
- if (nsolve_set(usage, cubepos(x,y,1), r*cr, 1
+ if (nsolve_set(usage, scratch, cubepos(x,y,1), r*cr, 1
#ifdef STANDALONE_SOLVER
, "set elimination, block (%d,%d)", 1+x/r, 1+y
#endif
* Row-wise set elimination.
*/
for (y = 0; y < cr; y++)
- if (nsolve_set(usage, cubepos(0,y,1), cr*cr, 1
+ if (nsolve_set(usage, scratch, cubepos(0,y,1), cr*cr, 1
#ifdef STANDALONE_SOLVER
, "set elimination, row %d", 1+YUNTRANS(y)
#endif
* Column-wise set elimination.
*/
for (x = 0; x < cr; x++)
- if (nsolve_set(usage, cubepos(x,0,1), cr, 1
+ if (nsolve_set(usage, scratch, cubepos(x,0,1), cr, 1
#ifdef STANDALONE_SOLVER
, "set elimination, column %d", 1+x
#endif
break;
}
+ nsolve_free_scratch(scratch);
+
sfree(usage->cube);
sfree(usage->row);
sfree(usage->col);
ai->r = r;
ai->grid = snewn(cr * cr, digit);
memcpy(ai->grid, grid, cr * cr * sizeof(digit));
+ /*
+ * We might already have written *aux the last time we
+ * went round this loop, in which case we should free
+ * the old aux_info before overwriting it with the new
+ * one.
+ */
+ if (*aux) {
+ sfree((*aux)->grid);
+ sfree(*aux);
+ }
*aux = ai;
}
sfree(ui);
}
-static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
- int button)
+static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
+ int x, int y, int button)
{
int c = from->c, r = from->r, cr = c*r;
int tx, ty;
tx = (x + TILE_SIZE - BORDER) / TILE_SIZE - 1;
ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1;
- if (tx >= 0 && tx < cr && ty >= 0 && ty < cr &&
- (button == LEFT_BUTTON || button == RIGHT_BUTTON)) {
- /*
- * Prevent pencil-mode highlighting of a filled square.
- */
- if (button == RIGHT_BUTTON && from->grid[ty*cr+tx])
- return NULL;
-
- if (tx == ui->hx && ty == ui->hy) {
- ui->hx = ui->hy = -1;
- } else {
- ui->hx = tx;
- ui->hy = ty;
- }
- ui->hpencil = (button == RIGHT_BUTTON);
- return from; /* UI activity occurred */
+ if (tx >= 0 && tx < cr && ty >= 0 && ty < cr) {
+ if (button == LEFT_BUTTON) {
+ if (from->immutable[ty*cr+tx]) {
+ ui->hx = ui->hy = -1;
+ } else if (tx == ui->hx && ty == ui->hy && ui->hpencil == 0) {
+ ui->hx = ui->hy = -1;
+ } else {
+ ui->hx = tx;
+ ui->hy = ty;
+ ui->hpencil = 0;
+ }
+ return from; /* UI activity occurred */
+ }
+ if (button == RIGHT_BUTTON) {
+ /*
+ * Pencil-mode highlighting for non filled squares.
+ */
+ if (from->grid[ty*cr+tx] == 0) {
+ if (tx == ui->hx && ty == ui->hy && ui->hpencil) {
+ ui->hx = ui->hy = -1;
+ } else {
+ ui->hpencil = 1;
+ ui->hx = tx;
+ ui->hy = ty;
+ }
+ } else {
+ ui->hx = ui->hy = -1;
+ }
+ return from; /* UI activity occurred */
+ }
}
if (ui->hx != -1 && ui->hy != -1 &&
if (button == ' ')
n = 0;
+ /*
+ * Can't overwrite this square. In principle this shouldn't
+ * happen anyway because we should never have even been
+ * able to highlight the square, but it never hurts to be
+ * careful.
+ */
if (from->immutable[ui->hy*cr+ui->hx])
- return NULL; /* can't overwrite this square */
+ return NULL;
/*
* Can't make pencil marks in a filled square. In principle
game_flash_length,
game_wants_statusbar,
FALSE, game_timing_state,
+ 0, /* mouse_priorities */
};
#ifdef STANDALONE_SOLVER
fprintf(stderr, "%s: %s\n", argv[0], err);
return 1;
}
- s = new_game(p, desc);
+ s = new_game(NULL, p, desc);
if (recurse) {
int ret = rsolve(p->c, p->r, s->grid, NULL, 2);