break; /* got it */
}
+ debug(("%d %dx%d loops before finished puzzle.\n", ngen, w, h));
+
return ngen;
}
{
char *grid, *clues;
char *desc;
- int ngen, w = params->w, h = params->h, i, j;
+ int w = params->w, h = params->h, i, j;
grid = snewn(w*h, char);
clues = snewn(w*h, char);
- ngen = new_clues(params, rs, clues, grid);
-
- debug(("%d %dx%d loops before finished puzzle.\n", ngen, w, h));
+ new_clues(params, rs, clues, grid);
desc = snewn(w * h + 1, char);
for (i = j = 0; i < w*h; i++) {
struct game_ui {
int *dragcoords; /* list of (y*w+x) coords in drag so far */
- int ndragcoords; /* number of entries in dragcoords. 0 = no drag. */
+ int ndragcoords; /* number of entries in dragcoords.
+ * 0 = click but no drag yet. -1 = no drag at all */
int clickx, clicky; /* pixel position of initial click */
};
game_ui *ui = snew(game_ui);
int sz = state->shared->sz;
- ui->ndragcoords = 0;
+ ui->ndragcoords = -1;
ui->dragcoords = snewn(sz, int);
return ui;
if (!INGRID(state, gx, gy))
return; /* square is outside grid */
+ if (ui->ndragcoords < 0)
+ return; /* drag not in progress anyway */
+
pos = gy * w + gx;
lastpos = ui->dragcoords[ui->ndragcoords > 0 ? ui->ndragcoords-1 : 0];
if (ox == gx || oy == gy) {
int dx = (gx < ox ? -1 : gx > ox ? +1 : 0);
int dy = (gy < oy ? -1 : gy > oy ? +1 : 0);
+ int dir = (dy>0 ? D : dy<0 ? U : dx>0 ? R : L);
while (ox != gx || oy != gy) {
+ /*
+ * If the drag attempts to cross a 'no line here' mark,
+ * stop there. We physically don't allow the user to drag
+ * over those marks.
+ */
+ if (state->marks[oy*w+ox] & dir)
+ break;
ox += dx;
oy += dy;
ui->dragcoords[ui->ndragcoords++] = oy * w + ox;
int gx = FROMCOORD(x), gy = FROMCOORD(y), i;
char tmpbuf[80];
- if (button == LEFT_BUTTON) {
- if (!INGRID(state, gx, gy)) return NULL;
+ if (IS_MOUSE_DOWN(button)) {
+ if (!INGRID(state, gx, gy)) {
+ ui->ndragcoords = -1;
+ return NULL;
+ }
ui->clickx = x; ui->clicky = y;
ui->dragcoords[0] = gy * w + gx;
return "";
}
- if (IS_MOUSE_DRAG(button)) {
+ if (button == LEFT_DRAG && ui->ndragcoords >= 0) {
update_ui_drag(state, ui, gx, gy);
return "";
}
if (IS_MOUSE_RELEASE(button)) {
- if (ui->ndragcoords) {
+ if (ui->ndragcoords > 0) {
/* End of a drag: process the cached line data. */
int buflen = 0, bufsize = 256, tmplen;
char *buf = NULL;
}
}
- ui->ndragcoords = 0;
+ ui->ndragcoords = -1;
return buf ? buf : "";
- } else {
- /* Click (or tiny drag). Work out which edge we were closest to. */
- int cx = COORD(gx) + TILE_SIZE/2, cy = COORD(gy) + TILE_SIZE/2;
+ } else if (ui->dragcoords == 0) {
+ /* Click (or tiny drag). Work out which edge we were
+ * closest to. */
+ int cx, cy;
int gx2, gy2, l1, l2, ismark = (button == RIGHT_RELEASE);
char movec = ismark ? 'M' : 'F';
+ ui->ndragcoords = -1;
+
+ /*
+ * We process clicks based on the mouse-down location,
+ * because that's more natural for a user to carefully
+ * control than the mouse-up.
+ */
+ x = ui->clickx;
+ y = ui->clicky;
+
+ gx = FROMCOORD(x);
+ gy = FROMCOORD(y);
+ cx = COORD(gx) + TILE_SIZE/2;
+ cy = COORD(gy) + TILE_SIZE/2;
+
if (!INGRID(state, gx, gy)) return "";
if (max(abs(x-cx),abs(y-cy)) < TILE_SIZE/4) {
if (!INGRID(state, x, y)) goto badmove;
if (l < 0 || l > 15) goto badmove;
- /* TODO trying to set a line over a no-line mark should be
- * a failed move? */
-
if (c == 'L')
ret->lines[y*w + x] |= (char)l;
else if (c == 'N')
else if (c == 'M')
ret->marks[y*w + x] ^= (char)l;
+ /*
+ * If we ended up trying to lay a line _over_ a mark,
+ * that's a failed move: interpret_move() should have
+ * ensured we never received a move string like that in
+ * the first place.
+ */
+ if ((ret->lines[y*w + x] & (char)l) &&
+ (ret->marks[y*w + x] & (char)l))
+ goto badmove;
+
move += n;
} else if (strcmp(move, "H") == 0) {
pearl_solve(ret->shared->w, ret->shared->h,
flashing = DS_FLASH;
memset(ds->draglines, 0, sz);
- if (ui->dragcoords) {
+ if (ui->ndragcoords > 0) {
int i, clearing = TRUE;
for (i = 0; i < ui->ndragcoords - 1; i++) {
int sx, sy, dx, dy, dir, oldstate, newstate;