X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/f0ee053c2a4a214a0e77b22462d0c42806d0462b..19f243063515d14b1d97e234b86340649f2c47bc:/sixteen.c diff --git a/sixteen.c b/sixteen.c index 2bfaadd..744e01d 100644 --- a/sixteen.c +++ b/sixteen.c @@ -194,7 +194,7 @@ static int perm_parity(int *perm, int n) } static char *new_game_desc(game_params *params, random_state *rs, - game_aux_info **aux) + game_aux_info **aux, int interactive) { int stop, n, i, x; int x1, x2, p1, p2; @@ -207,7 +207,9 @@ static char *new_game_desc(game_params *params, random_state *rs, tiles = snewn(n, int); if (params->movetarget) { - int prevstart = -1, prevoffset = -1, prevdirection = 0, nrepeats = 0; + int prevoffset = -1; + int max = (params->w > params->h ? params->w : params->h); + int *prevmoves = snewn(max, int); /* * Shuffle the old-fashioned way, by making a series of @@ -218,7 +220,7 @@ static char *new_game_desc(game_params *params, random_state *rs, tiles[i] = i; for (i = 0; i < params->movetarget; i++) { - int start, offset, len, direction; + int start, offset, len, direction, index; int j, tmp; /* @@ -230,12 +232,14 @@ static char *new_game_desc(game_params *params, random_state *rs, if (j < params->w) { /* Column. */ + index = j; start = j; offset = params->w; len = params->h; } else { /* Row. */ - start = (j - params->w) * params->w; + index = j - params->w; + start = index * params->w; offset = 1; len = params->w; } @@ -243,36 +247,42 @@ static char *new_game_desc(game_params *params, random_state *rs, direction = -1 + 2 * random_upto(rs, 2); /* - * To at least _try_ to avoid boring cases, check that - * this move doesn't directly undo the previous one, or - * repeat it so many times as to turn it into fewer - * moves. + * To at least _try_ to avoid boring cases, check + * that this move doesn't directly undo a previous + * one, or repeat it so many times as to turn it + * into fewer moves in the opposite direction. (For + * example, in a row of length 4, we're allowed to + * move it the same way twice, but not three + * times.) + * + * We track this for each individual row/column, + * and clear all the counters as soon as a + * perpendicular move is made. This isn't perfect + * (it _can't_ guaranteeably be perfect - there + * will always come a move count beyond which a + * shorter solution will be possible than the one + * which constructed the position) but it should + * sort out all the obvious cases. */ - if (start == prevstart && offset == prevoffset) { - if (direction == -prevdirection) - continue; /* inverse of previous move */ - else if (2 * (nrepeats+1) > len) - continue; /* previous move repeated too often */ - } + if (offset == prevoffset) { + tmp = prevmoves[index] + direction; + if (abs(2*tmp) > len || abs(tmp) < abs(prevmoves[index])) + continue; + } /* If we didn't `continue', we've found an OK move to make. */ + if (offset != prevoffset) { + int i; + for (i = 0; i < max; i++) + prevmoves[i] = 0; + prevoffset = offset; + } + prevmoves[index] += direction; break; } /* - * Now save the move into the `prev' variables. - */ - if (start == prevstart && offset == prevoffset) { - nrepeats++; - } else { - prevstart = start; - prevoffset = offset; - prevdirection = direction; - nrepeats = 1; - } - - /* - * And make it. + * Make the move. */ if (direction < 0) { start += (len-1) * offset; @@ -284,6 +294,8 @@ static char *new_game_desc(game_params *params, random_state *rs, tiles[start + (len-1) * offset] = tmp; } + sfree(prevmoves); + } else { used = snewn(n, int); @@ -442,7 +454,7 @@ static char *validate_desc(game_params *params, char *desc) return err; } -static game_state *new_game(game_params *params, char *desc) +static game_state *new_game(midend_data *me, game_params *params, char *desc) { game_state *state = snew(game_state); int i; @@ -565,9 +577,8 @@ static void free_ui(game_ui *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 cx, cy; int dx, dy, tx, ty, n; game_state *ret; @@ -763,7 +774,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, bgcolour = COL_BACKGROUND; if (!ds->started) { - int coords[6]; + int coords[10]; draw_rect(fe, 0, 0, TILE_SIZE * state->w + 2 * BORDER, @@ -779,15 +790,19 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, coords[1] = COORD(state->h) + HIGHLIGHT_WIDTH - 1; coords[2] = COORD(state->w) + HIGHLIGHT_WIDTH - 1; coords[3] = COORD(0) - HIGHLIGHT_WIDTH; - coords[4] = COORD(0) - HIGHLIGHT_WIDTH; - coords[5] = COORD(state->h) + HIGHLIGHT_WIDTH - 1; - draw_polygon(fe, coords, 3, TRUE, COL_HIGHLIGHT); - draw_polygon(fe, coords, 3, FALSE, COL_HIGHLIGHT); + coords[4] = coords[2] - TILE_SIZE; + coords[5] = coords[3] + TILE_SIZE; + coords[8] = COORD(0) - HIGHLIGHT_WIDTH; + coords[9] = COORD(state->h) + HIGHLIGHT_WIDTH - 1; + coords[6] = coords[8] + TILE_SIZE; + coords[7] = coords[9] - TILE_SIZE; + draw_polygon(fe, coords, 5, TRUE, COL_HIGHLIGHT); + draw_polygon(fe, coords, 5, FALSE, COL_HIGHLIGHT); coords[1] = COORD(0) - HIGHLIGHT_WIDTH; coords[0] = COORD(0) - HIGHLIGHT_WIDTH; - draw_polygon(fe, coords, 3, TRUE, COL_LOWLIGHT); - draw_polygon(fe, coords, 3, FALSE, COL_LOWLIGHT); + draw_polygon(fe, coords, 5, TRUE, COL_LOWLIGHT); + draw_polygon(fe, coords, 5, FALSE, COL_LOWLIGHT); /* * Arrows for making moves. @@ -937,7 +952,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, } static float game_anim_length(game_state *oldstate, - game_state *newstate, int dir) + game_state *newstate, int dir, game_ui *ui) { if ((dir > 0 && newstate->just_used_solve) || (dir < 0 && oldstate->just_used_solve)) @@ -947,7 +962,7 @@ static float game_anim_length(game_state *oldstate, } static float game_flash_length(game_state *oldstate, - game_state *newstate, int dir) + game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->used_solve && !newstate->used_solve) @@ -961,6 +976,11 @@ static int game_wants_statusbar(void) return TRUE; } +static int game_timing_state(game_state *state) +{ + return TRUE; +} + #ifdef COMBINED #define thegame sixteen #endif @@ -994,4 +1014,6 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, + 0, /* mouse_priorities */ };