X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/4a9957b631033dd550ade368dddad95fbc9d115d..250838c2ac88e6852d62392bc84feb7678702c06:/midend.c diff --git a/midend.c b/midend.c index a316bcd..c1f3a01 100644 --- a/midend.c +++ b/midend.c @@ -156,6 +156,15 @@ midend *midend_new(frontend *fe, const game *ourgame, return me; } +static void midend_purge_states(midend *me) +{ + while (me->nstates > me->statepos) { + me->ourgame->free_game(me->states[--me->nstates].state); + if (me->states[me->nstates].movestr) + sfree(me->states[me->nstates].movestr); + } +} + static void midend_free_game(midend *me) { while (me->nstates > 0) { @@ -278,6 +287,8 @@ void midend_size(midend *me, int *x, int *y, int user_size) *y = me->winheight; } +int midend_tilesize(midend *me) { return me->tilesize; } + void midend_set_params(midend *me, game_params *params) { me->ourgame->free_params(me->params); @@ -335,9 +346,9 @@ void midend_new_game(midend *me) char newseed[16]; int i; newseed[15] = '\0'; - newseed[0] = '1' + random_upto(me->random, 9); + newseed[0] = '1' + (char)random_upto(me->random, 9); for (i = 1; i < 15; i++) - newseed[i] = '0' + random_upto(me->random, 10); + newseed[i] = '0' + (char)random_upto(me->random, 10); sfree(me->seedstr); me->seedstr = dupstr(newseed); @@ -383,6 +394,25 @@ void midend_new_game(midend *me) me->states[me->nstates].state = me->ourgame->new_game(me, me->params, me->desc); + /* + * As part of our commitment to self-testing, test the aux + * string to make sure nothing ghastly went wrong. + */ + if (me->ourgame->can_solve && me->aux_info) { + game_state *s; + char *msg, *movestr; + + msg = NULL; + movestr = me->ourgame->solve(me->states[0].state, + me->states[0].state, + me->aux_info, &msg); + assert(movestr && !msg); + s = me->ourgame->execute_move(me->states[0].state, movestr); + assert(s); + me->ourgame->free_game(s); + sfree(movestr); + } + me->states[me->nstates].movestr = NULL; me->states[me->nstates].movetype = NEWGAME; me->nstates++; @@ -398,6 +428,16 @@ void midend_new_game(midend *me) me->pressed_mouse_button = 0; } +int midend_can_undo(midend *me) +{ + return (me->statepos > 1); +} + +int midend_can_redo(midend *me) +{ + return (me->statepos < me->nstates); +} + static int midend_undo(midend *me) { if (me->statepos > 1) { @@ -490,8 +530,7 @@ void midend_restart_game(midend *me) * Now enter the restarted state as the next move. */ midend_stop_anim(me); - while (me->nstates > me->statepos) - me->ourgame->free_game(me->states[--me->nstates].state); + midend_purge_states(me); ensure(me); me->states[me->nstates].state = s; me->states[me->nstates].movestr = dupstr(me->desc); @@ -538,6 +577,9 @@ static int midend_really_process_key(midend *me, int x, int y, int button) midend_stop_anim(me); if (!midend_redo(me)) goto done; + } else if (button == '\x13' && me->ourgame->can_solve) { + if (midend_solve(me)) + goto done; } else if (button == 'q' || button == 'Q' || button == '\x11') { ret = 0; goto done; @@ -563,8 +605,7 @@ static int midend_really_process_key(midend *me, int x, int y, int button) goto done; } else if (s) { midend_stop_anim(me); - while (me->nstates > me->statepos) - me->ourgame->free_game(me->states[--me->nstates].state); + midend_purge_states(me); ensure(me); assert(movestr != NULL); me->states[me->nstates].state = s; @@ -729,6 +770,15 @@ int midend_process_key(midend *me, int x, int y, int button) button = CURSOR_SELECT2; /* + * Normalise both backspace characters (8 and 127) to \b. Easier + * to do this once, here, than to require all front ends to + * carefully generate the same one - now each front end can + * generate whichever is easiest. + */ + if (button == '\177') + button = '\b'; + + /* * Now send on the event we originally received. */ ret = ret && midend_really_process_key(me, x, y, button); @@ -832,9 +882,9 @@ float *midend_colours(midend *me, int *ncolours) buf[k] = '\0'; if ((e = getenv(buf)) != NULL && sscanf(e, "%2x%2x%2x", &r, &g, &b) == 3) { - ret[i*3 + 0] = r / 255.0; - ret[i*3 + 1] = g / 255.0; - ret[i*3 + 2] = b / 255.0; + ret[i*3 + 0] = r / 255.0F; + ret[i*3 + 1] = g / 255.0F; + ret[i*3 + 2] = b / 255.0F; } } } @@ -923,6 +973,7 @@ int midend_num_presets(midend *me) me->ourgame->encode_params(preset, TRUE); me->npresets++; } + sfree(e); } } @@ -1258,11 +1309,7 @@ char *midend_solve(midend *me) * Now enter the solved state as the next move. */ midend_stop_anim(me); - while (me->nstates > me->statepos) { - me->ourgame->free_game(me->states[--me->nstates].state); - if (me->states[me->nstates].movestr) - sfree(me->states[me->nstates].movestr); - } + midend_purge_states(me); ensure(me); me->states[me->nstates].state = s; me->states[me->nstates].movestr = movestr; @@ -1284,11 +1331,29 @@ char *midend_solve(midend *me) me->anim_time = 0.0; midend_finish_move(me); } - midend_redraw(me); + if (me->drawing) + midend_redraw(me); midend_set_timer(me); return NULL; } +int midend_status(midend *me) +{ + /* + * We should probably never be called when the state stack has no + * states on it at all - ideally, midends should never be left in + * that state for long enough to get put down and forgotten about. + * But if we are, I think we return _true_ - pedantically speaking + * a midend in that state is 'vacuously solved', and more + * practically, a user whose midend has been left in that state + * probably _does_ want the 'new game' option to be prominent. + */ + if (me->statepos == 0) + return +1; + + return me->ourgame->status(me->states[me->statepos-1].state); +} + char *midend_rewrite_statusbar(midend *me, char *text) { /* @@ -1304,7 +1369,7 @@ char *midend_rewrite_statusbar(midend *me, char *text) char timebuf[100], *ret; int min, sec; - sec = me->elapsed; + sec = (int)me->elapsed; min = sec / 60; sec %= 60; sprintf(timebuf, "[%d:%02d] ", min, sec); @@ -1608,7 +1673,7 @@ char *midend_deserialise(midend *me, uistr = val; val = NULL; } else if (!strcmp(key, "TIME")) { - elapsed = atof(val); + elapsed = (float)atof(val); } else if (!strcmp(key, "NSTATES")) { nstates = atoi(val); if (nstates <= 0) {