/* Make to an independent copy of from. */ void copymovelist(actlist *to, actlist const *from) { to->list = NULL; initmovelist(to); setmovelist(to, from->count); memcpy(to->list, from->list, from->count * sizeof *from->list); }
/* Initialize the current state to the starting position of the * current puzzle, and reset the macro array and the stack. */ void initgamestate(void) { memcpy(state.map, state.game->map, sizeof state.map); state.currblock = state.game->equivs[KEYID] ? KEYID : FIRSTID; state.ycurrpos = state.xcurrpos = 0; initmovelist(&state.undo); copymovelist(&state.redo, &state.game->answer); state.movecount = 0; state.stepcount = 0; }
/* Toggle macro recording on and off. */ void setmacro(void) { if (recording) { recording = FALSE; return; } macro = ¯os[state.player]; initmovelist(macro); recording = TRUE; }
/* Compare the solution currently sitting in the undo list with the * user's best solutions (if any). If this solution beats what's * there, replace them. If this solution has the save number of moves * as the least-moves solution, but fewer pushes, then the replacement * will be done, and likewise for the least-pushes solution. Note that * the undo list contains the moves in backwards order, so the list * needs to be reversed when it is copied. TRUE is returned if any * solution was replaced. */ int replaceanswers(int saveinc) { int i, n; if (saveinc && (state.game->movebestcount || state.game->pushbestcount)) return FALSE; n = 0; if (!state.game->movebestcount || state.movecount < state.game->movebestcount || (state.movecount == state.game->movebestcount && state.pushcount < state.game->movebestpushcount)) { initmovelist(&state.game->moveanswer); i = state.undo.count; while (i--) addtomovelist(&state.game->moveanswer, state.undo.list[i]); if (!saveinc) state.game->movebestcount = state.movecount; state.game->movebestpushcount = state.pushcount; ++n; } if (!state.game->pushbestcount || state.pushcount < state.game->pushbestcount || (state.pushcount == state.game->pushbestcount && state.movecount < state.game->pushbestmovecount)) { initmovelist(&state.game->pushanswer); i = state.undo.count; while (i--) addtomovelist(&state.game->pushanswer, state.undo.list[i]); state.game->pushbestcount = state.pushcount; if (!saveinc) state.game->pushbestmovecount = state.movecount; ++n; } return n > 0; }
/* Initialize the current state to the starting position of the * current puzzle, and reset the macro array and the stack. */ void initgamestate(int usemoves) { int i; memcpy(state.map, state.game->map, sizeof state.map); state.player = state.game->start; initmovelist(&state.undo); if (!state.game->moveanswer.count) copymovelist(&state.redo, &state.game->pushanswer); else if (!state.game->pushanswer.count || usemoves) copymovelist(&state.redo, &state.game->moveanswer); else copymovelist(&state.redo, &state.game->pushanswer); state.movecount = 0; state.pushcount = 0; state.storecount = state.game->storecount; recording = FALSE; for (i = 0 ; i < (int)(sizeof macros / sizeof *macros) ; ++i) if (macros[i].count) macros[i].count = 0; }
/* Compare the solution currently sitting in the undo list with the * user's best solutions (if any). If this solution beats what's * there, replace them. If this solution has the same number of moves * as the least-moves solution, but fewer steps, then the replacement * will be done, and likewise for the least-steps solution. Note that * the undo list contains the moves in backwards order, so the list * needs to be reversed when it is copied. TRUE is returned if any * solution was replaced. */ int replaceanswer(int saveinc) { int i; if (state.game->beststepcount) { if (saveinc) return FALSE; if (state.stepcount > state.game->beststepcount || (state.stepcount == state.game->beststepcount && state.movecount >= state.game->answer.count)) return FALSE; state.game->beststepcount = state.stepcount; } else { if (!saveinc) state.game->beststepcount = state.stepcount; } initmovelist(&state.game->answer); i = state.undo.count; while (i--) addtomovelist(&state.game->answer, state.undo.list[i]); return TRUE; }
/* Expand a level's solution data into an actual list of moves. */ int expandsolution(solutioninfo *solution, gamesetup const *game) { unsigned char const *dataend; unsigned char const *p; action act; int n; if (game->solutionsize <= 16) return FALSE; solution->flags = game->solutiondata[6]; solution->rndslidedir = indextodir(game->solutiondata[7] & 7); solution->stepping = (game->solutiondata[7] >> 3) & 7; solution->rndseed = game->solutiondata[8] | (game->solutiondata[9] << 8) | (game->solutiondata[10] << 16) | (game->solutiondata[11] << 24); initmovelist(&solution->moves); act.when = -1; p = game->solutiondata + 16; dataend = game->solutiondata + game->solutionsize; while (p < dataend) { switch (*p & 0x03) { case 0: act.dir = indextodir((*p >> 2) & 0x03); act.when += 4; addtomovelist(&solution->moves, act); act.dir = indextodir((*p >> 4) & 0x03); act.when += 4; addtomovelist(&solution->moves, act); act.dir = indextodir((*p >> 6) & 0x03); act.when += 4; addtomovelist(&solution->moves, act); ++p; break; case 1: act.dir = indextodir((*p >> 2) & 0x07); act.when += ((*p >> 5) & 0x07) + 1; addtomovelist(&solution->moves, act); ++p; break; case 2: if (p + 2 > dataend) goto truncated; act.dir = indextodir((*p >> 2) & 0x07); act.when += ((p[0] >> 5) & 0x07) + ((unsigned long)p[1] << 3) + 1; addtomovelist(&solution->moves, act); p += 2; break; case 3: if (*p & 0x10) { n = (*p >> 2) & 0x03; if (p + 2 + n > dataend) goto truncated; act.dir = ((p[0] >> 5) & 0x07) | ((p[1] & 0x3F) << 3); act.when += (p[1] >> 6) & 0x03; while (n--) act.when += (unsigned long)p[2 + n] << (2 + n * 8); ++act.when; p += 2 + ((*p >> 2) & 0x03); } else { if (p + 4 > dataend) goto truncated; act.dir = indextodir((*p >> 2) & 0x03); act.when += ((p[0] >> 5) & 0x07) | ((unsigned long)p[1] << 3) | ((unsigned long)p[2] << 11) | ((unsigned long)p[3] << 19); ++act.when; p += 4; } addtomovelist(&solution->moves, act); break; }