unsigned char *vedge; /* (w+1) x h */
unsigned char *hedge; /* w x (h+1) */
int completed, cheated;
+ unsigned char *correct;
};
static game_params *default_params(void)
return ret;
}
-static char *validate_params(game_params *params)
+static char *validate_params(game_params *params, int full)
{
if (params->w <= 0 || params->h <= 0)
return "Width and height must both be greater than zero";
return NULL;
}
+static unsigned char *get_correct(game_state *state)
+{
+ unsigned char *ret;
+ int x, y;
+
+ ret = snewn(state->w * state->h, unsigned char);
+ memset(ret, 0xFF, state->w * state->h);
+
+ for (x = 0; x < state->w; x++)
+ for (y = 0; y < state->h; y++)
+ if (index(state,ret,x,y) == 0xFF) {
+ int rw, rh;
+ int xx, yy;
+ int num, area, valid;
+
+ /*
+ * Find a rectangle starting at this point.
+ */
+ rw = 1;
+ while (x+rw < state->w && !vedge(state,x+rw,y))
+ rw++;
+ rh = 1;
+ while (y+rh < state->h && !hedge(state,x,y+rh))
+ rh++;
+
+ /*
+ * We know what the dimensions of the rectangle
+ * should be if it's there at all. Find out if we
+ * really have a valid rectangle.
+ */
+ valid = TRUE;
+ /* Check the horizontal edges. */
+ for (xx = x; xx < x+rw; xx++) {
+ for (yy = y; yy <= y+rh; yy++) {
+ int e = !HRANGE(state,xx,yy) || hedge(state,xx,yy);
+ int ec = (yy == y || yy == y+rh);
+ if (e != ec)
+ valid = FALSE;
+ }
+ }
+ /* Check the vertical edges. */
+ for (yy = y; yy < y+rh; yy++) {
+ for (xx = x; xx <= x+rw; xx++) {
+ int e = !VRANGE(state,xx,yy) || vedge(state,xx,yy);
+ int ec = (xx == x || xx == x+rw);
+ if (e != ec)
+ valid = FALSE;
+ }
+ }
+
+ /*
+ * If this is not a valid rectangle with no other
+ * edges inside it, we just mark this square as not
+ * complete and proceed to the next square.
+ */
+ if (!valid) {
+ index(state, ret, x, y) = 0;
+ continue;
+ }
+
+ /*
+ * We have a rectangle. Now see what its area is,
+ * and how many numbers are in it.
+ */
+ num = 0;
+ area = 0;
+ for (xx = x; xx < x+rw; xx++) {
+ for (yy = y; yy < y+rh; yy++) {
+ area++;
+ if (grid(state,xx,yy)) {
+ if (num > 0)
+ valid = FALSE; /* two numbers */
+ num = grid(state,xx,yy);
+ }
+ }
+ }
+ if (num != area)
+ valid = FALSE;
+
+ /*
+ * Now fill in the whole rectangle based on the
+ * value of `valid'.
+ */
+ for (xx = x; xx < x+rw; xx++) {
+ for (yy = y; yy < y+rh; yy++) {
+ index(state, ret, xx, yy) = valid;
+ }
+ }
+ }
+
+ return ret;
+}
+
static game_state *new_game(midend_data *me, game_params *params, char *desc)
{
game_state *state = snew(game_state);
for (x = 0; x < state->w; x++)
vedge(state,x,y) = hedge(state,x,y) = 0;
+ state->correct = get_correct(state);
+
return state;
}
ret->vedge = snewn(state->w * state->h, unsigned char);
ret->hedge = snewn(state->w * state->h, unsigned char);
ret->grid = snewn(state->w * state->h, int);
+ ret->correct = snewn(ret->w * ret->h, unsigned char);
ret->completed = state->completed;
ret->cheated = state->cheated;
memcpy(ret->vedge, state->vedge, state->w*state->h*sizeof(unsigned char));
memcpy(ret->hedge, state->hedge, state->w*state->h*sizeof(unsigned char));
+ memcpy(ret->correct, state->correct, state->w*state->h*sizeof(unsigned char));
+
return ret;
}
sfree(state->grid);
sfree(state->vedge);
sfree(state->hedge);
+ sfree(state->correct);
sfree(state);
}
return ret;
}
-static unsigned char *get_correct(game_state *state)
-{
- unsigned char *ret;
- int x, y;
-
- ret = snewn(state->w * state->h, unsigned char);
- memset(ret, 0xFF, state->w * state->h);
-
- for (x = 0; x < state->w; x++)
- for (y = 0; y < state->h; y++)
- if (index(state,ret,x,y) == 0xFF) {
- int rw, rh;
- int xx, yy;
- int num, area, valid;
-
- /*
- * Find a rectangle starting at this point.
- */
- rw = 1;
- while (x+rw < state->w && !vedge(state,x+rw,y))
- rw++;
- rh = 1;
- while (y+rh < state->h && !hedge(state,x,y+rh))
- rh++;
-
- /*
- * We know what the dimensions of the rectangle
- * should be if it's there at all. Find out if we
- * really have a valid rectangle.
- */
- valid = TRUE;
- /* Check the horizontal edges. */
- for (xx = x; xx < x+rw; xx++) {
- for (yy = y; yy <= y+rh; yy++) {
- int e = !HRANGE(state,xx,yy) || hedge(state,xx,yy);
- int ec = (yy == y || yy == y+rh);
- if (e != ec)
- valid = FALSE;
- }
- }
- /* Check the vertical edges. */
- for (yy = y; yy < y+rh; yy++) {
- for (xx = x; xx <= x+rw; xx++) {
- int e = !VRANGE(state,xx,yy) || vedge(state,xx,yy);
- int ec = (xx == x || xx == x+rw);
- if (e != ec)
- valid = FALSE;
- }
- }
-
- /*
- * If this is not a valid rectangle with no other
- * edges inside it, we just mark this square as not
- * complete and proceed to the next square.
- */
- if (!valid) {
- index(state, ret, x, y) = 0;
- continue;
- }
-
- /*
- * We have a rectangle. Now see what its area is,
- * and how many numbers are in it.
- */
- num = 0;
- area = 0;
- for (xx = x; xx < x+rw; xx++) {
- for (yy = y; yy < y+rh; yy++) {
- area++;
- if (grid(state,xx,yy)) {
- if (num > 0)
- valid = FALSE; /* two numbers */
- num = grid(state,xx,yy);
- }
- }
- }
- if (num != area)
- valid = FALSE;
-
- /*
- * Now fill in the whole rectangle based on the
- * value of `valid'.
- */
- for (xx = x; xx < x+rw; xx++) {
- for (yy = y; yy < y+rh; yy++) {
- index(state, ret, xx, yy) = valid;
- }
- }
- }
-
- return ret;
-}
-
struct game_ui {
/*
* These coordinates are 2 times the obvious grid coordinates.
sfree(ui);
}
-char *encode_ui(game_ui *ui)
+static char *encode_ui(game_ui *ui)
{
return NULL;
}
-void decode_ui(game_ui *ui, char *encoding)
+static void decode_ui(game_ui *ui, char *encoding)
{
}
coord_round(FROMCOORD((float)x), FROMCOORD((float)y), &xc, &yc);
- if (startdrag) {
+ if (startdrag &&
+ xc >= 0 && xc <= 2*from->w &&
+ yc >= 0 && yc <= 2*from->h) {
+
ui->drag_start_x = xc;
ui->drag_start_y = yc;
ui->drag_end_x = xc;
active = TRUE;
}
- if (xc != ui->drag_end_x || yc != ui->drag_end_y) {
+ if (ui->drag_start_x >= 0 &&
+ (xc != ui->drag_end_x || yc != ui->drag_end_y)) {
int t;
ui->drag_end_x = xc;
ret = NULL;
- if (enddrag) {
+ if (enddrag && (ui->drag_start_x >= 0)) {
if (xc >= 0 && xc <= 2*from->w &&
yc >= 0 && yc <= 2*from->h) {
if (*p) p++;
}
+ sfree(ret->correct);
+ ret->correct = get_correct(ret);
+
return ret;
} else if (move[0] == 'R' &&
vedge(ret,x1,y1) = !vedge(ret,x1,y1);
}
+ sfree(ret->correct);
+ ret->correct = get_correct(ret);
+
/*
* We've made a real change to the grid. Check to see
* if the game has been completed.
*/
if (!ret->completed) {
int x, y, ok;
- unsigned char *correct = get_correct(ret);
ok = TRUE;
for (x = 0; x < ret->w; x++)
for (y = 0; y < ret->h; y++)
- if (!index(ret, correct, x, y))
+ if (!index(ret, ret->correct, x, y))
ok = FALSE;
- sfree(correct);
-
if (ok)
ret->completed = TRUE;
}
#define COLOUR(k) ( (k)==1 ? COL_LINE : COL_DRAG )
#define MAX4(x,y,z,w) ( max(max(x,y),max(z,w)) )
-static void game_size(game_params *params, game_drawstate *ds,
- int *x, int *y, int expand)
+static void game_compute_size(game_params *params, int tilesize,
+ int *x, int *y)
{
- int tsx, tsy, ts;
- /*
- * Each window dimension equals the tile size times 1.5 more
- * than the grid dimension (the border is 3/4 the width of the
- * tiles).
- *
- * We must cast to unsigned before multiplying by two, because
- * *x might be INT_MAX.
- */
- tsx = 2 * (unsigned)*x / (2 * params->w + 3);
- tsy = 2 * (unsigned)*y / (2 * params->h + 3);
- ts = min(tsx, tsy);
- if (expand)
- ds->tilesize = ts;
- else
- ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
+ /* Ick: fake up `ds->tilesize' for macro expansion purposes */
+ struct { int tilesize; } ads, *ds = &ads;
+ ads.tilesize = tilesize;
*x = params->w * TILE_SIZE + 2*BORDER + 1;
*y = params->h * TILE_SIZE + 2*BORDER + 1;
}
+static void game_set_size(game_drawstate *ds, game_params *params,
+ int tilesize)
+{
+ ds->tilesize = tilesize;
+}
+
static float *game_colours(frontend *fe, game_state *state, int *ncolours)
{
float *ret = snewn(3 * NCOLOURS, float);
float animtime, float flashtime)
{
int x, y;
- unsigned char *correct;
unsigned char *hedge, *vedge, *corners;
- correct = get_correct(state);
-
if (ui->dragged) {
hedge = snewn(state->w*state->h, unsigned char);
vedge = snewn(state->w*state->h, unsigned char);
if (x+1 < state->w && y+1 < state->h)
/* cast to prevent 2<<14 sign-extending on promotion to long */
c |= (unsigned long)index(state,corners,x+1,y+1) << 14;
- if (index(state, correct, x, y) && !flashtime)
+ if (index(state, state->correct, x, y) && !flashtime)
c |= CORRECT;
if (index(ds,ds->visible,x,y) != c) {
}
sfree(corners);
- sfree(correct);
}
static float game_anim_length(game_state *oldstate,
return TRUE;
}
-static int game_timing_state(game_state *state)
+static int game_timing_state(game_state *state, game_ui *ui)
{
return TRUE;
}
game_changed_state,
interpret_move,
execute_move,
- game_size,
+ PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
game_colours,
game_new_drawstate,
game_free_drawstate,