Пример #1
0
/* Unapply the last move on the undo list, reversing what was done in
 * domove() and adding the move to the redo list.
 */
int undomove(void)
{
    dyx	move;
    yx	j;

    if (!state.undo.count)
	return FALSE;

    move = state.undo.list[--state.undo.count];
    addtomovelist(&state.redo, move);
    if (move.box) {
	j = state.player + move.yx;
	state.map[j] &= ~BOX;
	state.map[state.player] |= BOX;
	if (state.map[j] & GOAL)
	    --state.storecount;
	if (state.map[state.player] & GOAL)
	    ++state.storecount;
	--state.pushcount;
    }
    state.map[state.player] &= ~PLAYER;
    state.player -= move.yx;
    state.map[state.player] |= PLAYER;
    --state.movecount;
    if (recording && macro->count) {
	if (--macro->count == 0)
	    recording = FALSE;
    }
    return TRUE;
}
Пример #2
0
/* Apply a legal move to the current state, adding it to the undo list.
 */
static void domove(action move)
{
    move.door = moveblock(move.id, move.dir);
    state.currblock = move.id;
    state.ycurrpos = state.xcurrpos = 0;
    ++state.movecount;
    if (!state.undo.count ||
		move.id != state.undo.list[state.undo.count - 1].id)
	++state.stepcount;
    addtomovelist(&state.undo, move);
}
Пример #3
0
/* Apply a legal move to the current state, adding it to the undo list
 * and any macro being recorded. (This function contains the actual
 * sokoban game logic. Everything else in this program is just
 * housekeeping.)
 */
static void domove(dyx move)
{
    yx	j;

    state.map[state.player] &= ~PLAYER;
    state.player += move.yx;
    state.map[state.player] |= PLAYER;
    ++state.movecount;
    if (move.box) {
	j = state.player + move.yx;
	state.map[state.player] &= ~BOX;
	state.map[j] |= BOX;
	if (state.map[state.player] & GOAL)
	    --state.storecount;
	if (state.map[j] & GOAL)
	    ++state.storecount;
	++state.pushcount;
    }

    addtomovelist(&state.undo, move);
    if (recording)
	addtomovelist(macro, move);
}
Пример #4
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 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;
}
Пример #5
0
/* Unapply the last move on the undo list, reversing what was done in
 * domove() and adding the move to the redo list.
 */
int undomove(void)
{
    action	move;

    if (!state.undo.count)
	return FALSE;

    move = state.undo.list[--state.undo.count];
    addtomovelist(&state.redo, move);
    moveblock(move.id, backwards(move.dir));
    state.currblock = move.id;
    state.ycurrpos = state.xcurrpos = 0;
    --state.movecount;
    if (!state.undo.count ||
		move.id != state.undo.list[state.undo.count - 1].id)
	--state.stepcount;
    if (move.door)
	resetdoors();

    return TRUE;
}
Пример #6
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;
}
Пример #7
0
/* 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;
	}