X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/5d8c6c556982ae44f786d14a6d641182ced15043..14a7c1c61f81ae6fca148299c2f736e3283adc16:/flip.c diff --git a/flip.c b/flip.c index e6c4077..b38aff1 100644 --- a/flip.c +++ b/flip.c @@ -20,6 +20,7 @@ enum { COL_GRID, COL_DIAG, COL_HINT, + COL_CURSOR, NCOLOURS }; @@ -347,7 +348,7 @@ static void addneighbours(tree234 *t, int w, int h, int cx, int cy, } static char *new_game_desc(game_params *params, random_state *rs, - game_aux_info **aux, int interactive) + char **aux, int interactive) { int w = params->w, h = params->h, wh = w * h; int i, j; @@ -595,11 +596,6 @@ static char *new_game_desc(game_params *params, random_state *rs, return ret; } -static void game_free_aux_info(game_aux_info *aux) -{ - assert(!"Shouldn't happen"); -} - static char *validate_desc(game_params *params, char *desc) { int w = params->w, h = params->h, wh = w * h; @@ -675,15 +671,15 @@ static void rowxor(unsigned char *row1, unsigned char *row2, int len) row1[i] ^= row2[i]; } -static game_state *solve_game(game_state *state, game_state *currstate, - game_aux_info *aux, char **error) +static char *solve_game(game_state *state, game_state *currstate, + char *aux, char **error) { int w = state->w, h = state->h, wh = w * h; unsigned char *equations, *solution, *shortest; int *und, nund; int rowsdone, colsdone; int i, j, k, len, bestlen; - game_state *ret; + char *ret; /* * Set up a list of simultaneous equations. Each one is of @@ -840,17 +836,14 @@ static game_state *solve_game(game_state *state, game_state *currstate, } /* - * We have a solution. Produce a game state with the solution - * marked in annotations. + * We have a solution. Produce a move string encoding the + * solution. */ - ret = dup_game(currstate); - ret->hints_active = TRUE; - ret->cheated = TRUE; - for (i = 0; i < wh; i++) { - ret->grid[i] &= ~2; - if (shortest[i]) - ret->grid[i] |= 2; - } + ret = snewn(wh + 2, char); + ret[0] = 'S'; + for (i = 0; i < wh; i++) + ret[i+1] = shortest[i] ? '1' : '0'; + ret[wh+1] = '\0'; sfree(shortest); sfree(solution); @@ -865,13 +858,29 @@ static char *game_text_format(game_state *state) return NULL; } +struct game_ui { + int cx, cy, cdraw; +}; + static game_ui *new_ui(game_state *state) { - return NULL; + game_ui *ui = snew(game_ui); + ui->cx = ui->cy = ui->cdraw = 0; + return ui; } static void free_ui(game_ui *ui) { + sfree(ui); +} + +static char *encode_ui(game_ui *ui) +{ + return NULL; +} + +static void decode_ui(game_ui *ui, char *encoding) +{ } static void game_changed_state(game_ui *ui, game_state *oldstate, @@ -885,68 +894,117 @@ struct game_drawstate { int tilesize; }; -static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, - int x, int y, int button) +static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds, + int x, int y, int button) { - int w = from->w, h = from->h, wh = w * h; - game_state *ret; + int w = state->w, h = state->h /*, wh = w * h */; + char buf[80], *nullret = NULL; + + if (button == LEFT_BUTTON || button == CURSOR_SELECT || + button == ' ' || button == '\r' || button == '\n') { + int tx, ty; + if (button == LEFT_BUTTON) { + tx = FROMCOORD(x), ty = FROMCOORD(y); + ui->cdraw = 0; + } else { + tx = ui->cx; ty = ui->cy; + ui->cdraw = 1; + } + nullret = ""; - if (button == LEFT_BUTTON) { - int tx = FROMCOORD(x), ty = FROMCOORD(y); if (tx >= 0 && tx < w && ty >= 0 && ty < h) { - int i, j, done; + sprintf(buf, "M%d,%d", tx, ty); + return dupstr(buf); + } + } + else if (button == CURSOR_UP || button == CURSOR_DOWN || + button == CURSOR_RIGHT || button == CURSOR_LEFT) { + int dx = 0, dy = 0; + switch (button) { + case CURSOR_UP: dy = -1; break; + case CURSOR_DOWN: dy = 1; break; + case CURSOR_RIGHT: dx = 1; break; + case CURSOR_LEFT: dx = -1; break; + default: assert(!"shouldn't get here"); + } + ui->cx += dx; ui->cy += dy; + ui->cx = min(max(ui->cx, 0), state->w - 1); + ui->cy = min(max(ui->cy, 0), state->h - 1); + ui->cdraw = 1; + nullret = ""; + } - ret = dup_game(from); + return nullret; +} - if (!ret->completed) - ret->moves++; +static game_state *execute_move(game_state *from, char *move) +{ + int w = from->w, h = from->h, wh = w * h; + game_state *ret; + int x, y; + + if (move[0] == 'S' && strlen(move) == wh+1) { + int i; + + ret = dup_game(from); + ret->hints_active = TRUE; + ret->cheated = TRUE; + for (i = 0; i < wh; i++) { + ret->grid[i] &= ~2; + if (move[i+1] != '0') + ret->grid[i] |= 2; + } + return ret; + } else if (move[0] == 'M' && + sscanf(move+1, "%d,%d", &x, &y) == 2 && + x >= 0 && x < w && y >= 0 && y < h) { + int i, j, done; - i = ty * w + tx; + ret = dup_game(from); - done = TRUE; - for (j = 0; j < wh; j++) { - ret->grid[j] ^= ret->matrix->matrix[i*wh+j]; - if (ret->grid[j] & 1) - done = FALSE; - } - ret->grid[i] ^= 2; /* toggle hint */ - if (done) { - ret->completed = TRUE; - ret->hints_active = FALSE; - } + if (!ret->completed) + ret->moves++; - return ret; - } - } + i = y * w + x; - return NULL; + done = TRUE; + for (j = 0; j < wh; j++) { + ret->grid[j] ^= ret->matrix->matrix[i*wh+j]; + if (ret->grid[j] & 1) + done = FALSE; + } + ret->grid[i] ^= 2; /* toggle hint */ + if (done) { + ret->completed = TRUE; + ret->hints_active = FALSE; + } + + return ret; + } else + return NULL; /* can't parse move string */ } /* ---------------------------------------------------------------------- * Drawing routines. */ -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 one more - * than the grid dimension (the border is half the width of the - * tiles). - */ - tsx = *x / (params->w + 1); - tsy = *y / (params->h + 1); - 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 = TILE_SIZE * params->w + 2 * BORDER; *y = TILE_SIZE * params->h + 2 * BORDER; } +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); @@ -973,6 +1031,10 @@ static float *game_colours(frontend *fe, game_state *state, int *ncolours) ret[COL_HINT * 3 + 1] = 0.0F; ret[COL_HINT * 3 + 2] = 0.0F; + ret[COL_CURSOR * 3 + 0] = 0.8F; + ret[COL_CURSOR * 3 + 1] = 0.0F; + ret[COL_CURSOR * 3 + 2] = 0.0F; + *ncolours = NCOLOURS; return ret; } @@ -1005,7 +1067,7 @@ static void draw_tile(frontend *fe, game_drawstate *ds, { int w = ds->w, h = ds->h, wh = w * h; int bx = x * TILE_SIZE + BORDER, by = y * TILE_SIZE + BORDER; - int i, j; + int i, j, dcol = (tile & 4) ? COL_CURSOR : COL_DIAG; clip(fe, bx+1, by+1, TILE_SIZE-1, TILE_SIZE-1); @@ -1031,8 +1093,7 @@ static void draw_tile(frontend *fe, game_drawstate *ds, if (animtime < 0.5) colour = COL_WRONG + COL_RIGHT - colour; - draw_polygon(fe, coords, 4, TRUE, colour); - draw_polygon(fe, coords, 4, FALSE, COL_GRID); + draw_polygon(fe, coords, 4, colour, COL_GRID); } /* @@ -1047,12 +1108,12 @@ static void draw_tile(frontend *fe, game_drawstate *ds, int cx = (bx + TILE_SIZE/2) + (2 * ox - 1) * td; int cy = (by + TILE_SIZE/2) + (2 * oy - 1) * td; if (ox == 0 && oy == 0) - draw_rect(fe, cx, cy, 2*td+1, 2*td+1, COL_DIAG); + draw_rect(fe, cx, cy, 2*td+1, 2*td+1, dcol); else { - draw_line(fe, cx, cy, cx+2*td, cy, COL_DIAG); - draw_line(fe, cx, cy+2*td, cx+2*td, cy+2*td, COL_DIAG); - draw_line(fe, cx, cy, cx, cy+2*td, COL_DIAG); - draw_line(fe, cx+2*td, cy, cx+2*td, cy+2*td, COL_DIAG); + draw_line(fe, cx, cy, cx+2*td, cy, dcol); + draw_line(fe, cx, cy+2*td, cx+2*td, cy+2*td, dcol); + draw_line(fe, cx, cy, cx, cy+2*td, dcol); + draw_line(fe, cx+2*td, cy, cx+2*td, cy+2*td, dcol); } } @@ -1131,6 +1192,8 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, if (!state->hints_active) v &= ~2; + if (ui->cdraw && ui->cx == x && ui->cy == y) + v |= 4; if (oldstate && state->grid[i] != oldstate->grid[i]) vv = 255; /* means `animated' */ @@ -1196,7 +1259,6 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, @@ -1205,9 +1267,12 @@ const struct game thegame = { FALSE, game_text_format, new_ui, free_ui, + encode_ui, + decode_ui, game_changed_state, - make_move, - game_size, + interpret_move, + execute_move, + PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate,