X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/8266f3fccfd8621ac980d6209cbeac94e0a9c69b..bf58c93a413e6924dc8d8664363084fbdfaf8b56:/guess.c diff --git a/guess.c b/guess.c index 67abe20..ead9280 100644 --- a/guess.c +++ b/guess.c @@ -39,6 +39,7 @@ typedef struct pegrow { struct game_state { game_params params; pegrow *guesses; /* length params->nguesses */ + int *holds; pegrow solution; int next_go; /* from 0 to nguesses-1; if next_go == nguesses then they've lost. */ @@ -319,6 +320,7 @@ static game_state *new_game(midend *me, game_params *params, char *desc) state->guesses = snewn(params->nguesses, pegrow); for (i = 0; i < params->nguesses; i++) state->guesses[i] = new_pegrow(params->npegs); + state->holds = snewn(params->npegs, int); state->solution = new_pegrow(params->npegs); bmp = hex2bin(desc, params->npegs); @@ -327,6 +329,7 @@ static game_state *new_game(midend *me, game_params *params, char *desc) state->solution->pegs[i] = (int)bmp[i]; sfree(bmp); + memset(state->holds, 0, sizeof(int) * params->npegs); state->next_go = state->solved = 0; return state; @@ -342,6 +345,8 @@ static game_state *dup_game(game_state *state) ret->guesses = snewn(state->params.nguesses, pegrow); for (i = 0; i < state->params.nguesses; i++) ret->guesses[i] = dup_pegrow(state->guesses[i]); + ret->holds = snewn(state->params.npegs, int); + memcpy(ret->holds, state->holds, sizeof(int) * state->params.npegs); ret->solution = dup_pegrow(state->solution); return ret; @@ -354,6 +359,7 @@ static void free_game(game_state *state) free_pegrow(state->solution); for (i = 0; i < state->params.nguesses; i++) free_pegrow(state->guesses[i]); + sfree(state->holds); sfree(state->guesses); sfree(state); @@ -435,17 +441,19 @@ static char *encode_ui(game_ui *ui) /* * For this game it's worth storing the contents of the current - * guess. + * guess, and the current set of holds. */ ret = snewn(40 * ui->curr_pegs->npegs, char); p = ret; sep = ""; for (i = 0; i < ui->curr_pegs->npegs; i++) { - p += sprintf(p, "%s%d", sep, ui->curr_pegs->pegs[i]); + p += sprintf(p, "%s%d%s", sep, ui->curr_pegs->pegs[i], + ui->holds[i] ? "_" : ""); sep = ","; } + *p++ = '\0'; assert(p - ret < 40 * ui->curr_pegs->npegs); - return sresize(ret, p - ret + 1, char); + return sresize(ret, p - ret, char); } static void decode_ui(game_ui *ui, char *encoding) @@ -455,6 +463,12 @@ static void decode_ui(game_ui *ui, char *encoding) for (i = 0; i < ui->curr_pegs->npegs; i++) { ui->curr_pegs->pegs[i] = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; + if (*p == '_') { + /* NB: old versions didn't store holds */ + ui->holds[i] = 1; + p++; + } else + ui->holds[i] = 0; if (*p == ',') p++; } ui->markable = is_markable(&ui->params, ui->curr_pegs); @@ -465,10 +479,24 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, { int i; - /* just clear the row-in-progress when we have an undo/redo. */ - for (i = 0; i < ui->curr_pegs->npegs; i++) - ui->curr_pegs->pegs[i] = 0; - ui->markable = FALSE; + /* Implement holds, clear other pegs. + * This does something that is arguably the Right Thing even + * for undo. */ + for (i = 0; i < newstate->solution->npegs; i++) { + if (newstate->solved) + ui->holds[i] = 0; + else + ui->holds[i] = newstate->holds[i]; + if (newstate->solved || (newstate->next_go == 0) || !ui->holds[i]) { + ui->curr_pegs->pegs[i] = 0; + } else + ui->curr_pegs->pegs[i] = + newstate->guesses[newstate->next_go-1]->pegs[i]; + } + ui->markable = is_markable(&newstate->params, ui->curr_pegs); + /* Clean up cursor position */ + if (!ui->markable && ui->peg_cur == newstate->solution->npegs) + ui->peg_cur--; } #define PEGSZ (ds->pegsz) @@ -578,8 +606,7 @@ static int mark_pegs(pegrow guess, pegrow solution, int ncols) static char *encode_move(game_state *from, game_ui *ui) { char *buf, *p, *sep; - int len, i, solved; - pegrow tmppegs; + int len, i; len = ui->curr_pegs->npegs * 20 + 2; buf = snewn(len, char); @@ -587,28 +614,14 @@ static char *encode_move(game_state *from, game_ui *ui) *p++ = 'G'; sep = ""; for (i = 0; i < ui->curr_pegs->npegs; i++) { - p += sprintf(p, "%s%d", sep, ui->curr_pegs->pegs[i]); + p += sprintf(p, "%s%d%s", sep, ui->curr_pegs->pegs[i], + ui->holds[i] ? "_" : ""); sep = ","; } *p++ = '\0'; assert(p - buf <= len); buf = sresize(buf, len, char); - tmppegs = dup_pegrow(ui->curr_pegs); - solved = mark_pegs(tmppegs, from->solution, from->params.ncolours); - solved = (solved == from->params.ncolours); - free_pegrow(tmppegs); - - for (i = 0; i < from->solution->npegs; i++) { - if (!ui->holds[i] || solved) { - ui->curr_pegs->pegs[i] = 0; - } - if (solved) ui->holds[i] = 0; - } - ui->markable = is_markable(&from->params, ui->curr_pegs); - if (!ui->markable && ui->peg_cur == from->solution->npegs) - ui->peg_cur--; - return buf; } @@ -775,6 +788,11 @@ static game_state *execute_move(game_state *from, char *move) } ret->guesses[from->next_go]->pegs[i] = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; + if (*p == '_') { + ret->holds[i] = 1; + p++; + } else + ret->holds[i] = 0; if (*p == ',') p++; } @@ -876,14 +894,14 @@ static float *game_colours(frontend *fe, int *ncolours) ret[COL_1 * 3 + 1] = 0.0F; ret[COL_1 * 3 + 2] = 0.0F; - /* yellow (toned down a bit due to pale grey background) */ - ret[COL_2 * 3 + 0] = 0.7F; - ret[COL_2 * 3 + 1] = 0.7F; + /* yellow */ + ret[COL_2 * 3 + 0] = 1.0F; + ret[COL_2 * 3 + 1] = 1.0F; ret[COL_2 * 3 + 2] = 0.0F; - /* green (also toned down) */ + /* green */ ret[COL_3 * 3 + 0] = 0.0F; - ret[COL_3 * 3 + 1] = 0.5F; + ret[COL_3 * 3 + 1] = 1.0F; ret[COL_3 * 3 + 2] = 0.0F; /* blue */ @@ -912,9 +930,9 @@ static float *game_colours(frontend *fe, int *ncolours) ret[COL_8 * 3 + 2] = 1.0F; /* light green */ - ret[COL_9 * 3 + 0] = 0.5F; - ret[COL_9 * 3 + 1] = 0.8F; - ret[COL_9 * 3 + 2] = 0.5F; + ret[COL_9 * 3 + 0] = 0.7F; + ret[COL_9 * 3 + 1] = 1.0F; + ret[COL_9 * 3 + 2] = 0.7F; /* pink */ ret[COL_10 * 3 + 0] = 1.0F; @@ -1022,7 +1040,7 @@ static void draw_peg(drawing *dr, game_drawstate *ds, int cx, int cy, COL_BACKGROUND); if (PEGRAD > 0) { draw_circle(dr, cx+PEGRAD, cy+PEGRAD, PEGRAD, - COL_EMPTY + col, COL_EMPTY + col); + COL_EMPTY + col, (col ? COL_FRAME : COL_EMPTY)); } else draw_rect(dr, cx, cy, PEGSZ, PEGSZ, COL_EMPTY + col); draw_update(dr, cx-CGAP, cy-CGAP, PEGSZ+CGAP*2, PEGSZ+CGAP*2); @@ -1129,7 +1147,8 @@ static void hint_redraw(drawing *dr, game_drawstate *ds, int guess, rowy += HINTOFF; } if (HINTRAD > 0) { - draw_circle(dr, rowx+HINTRAD, rowy+HINTRAD, HINTRAD, col, col); + draw_circle(dr, rowx+HINTRAD, rowy+HINTRAD, HINTRAD, col, + (col == emptycol ? emptycol : COL_FRAME)); } else { draw_rect(dr, rowx, rowy, HINTSZ, HINTSZ, col); } @@ -1190,8 +1209,9 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, } } - /* draw the guesses (so far) and the hints */ - for (i = 0; i < state->params.nguesses; i++) { + /* draw the guesses (so far) and the hints + * (in reverse order to avoid trampling holds) */ + for (i = state->params.nguesses - 1; i >= 0; i--) { if (state->next_go > i || state->solved) { /* this info is stored in the game_state already */ guess_redraw(dr, ds, i, state->guesses[i], NULL, -1, 0); @@ -1258,11 +1278,6 @@ static float game_flash_length(game_state *oldstate, game_state *newstate, return 0.0F; } -static int game_wants_statusbar(void) -{ - return FALSE; -} - static int game_timing_state(game_state *state, game_ui *ui) { return TRUE; @@ -1312,7 +1327,7 @@ const struct game thegame = { game_anim_length, game_flash_length, FALSE, FALSE, game_print_size, game_print, - game_wants_statusbar, + FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ };