mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 08:01:30 -07:00
Stand-alone slidesolver.
[originally from svn r7558]
This commit is contained in:
@ -6,6 +6,9 @@ slide : [X] GTK COMMON SLIDE slide-icon|no-icon
|
|||||||
|
|
||||||
slide : [G] WINDOWS COMMON SLIDE slide.res|noicon.res
|
slide : [G] WINDOWS COMMON SLIDE slide.res|noicon.res
|
||||||
|
|
||||||
|
slidesolver : [U] slide[STANDALONE_SOLVER] dsf tree234 STANDALONE
|
||||||
|
slidesolver : [C] slide[STANDALONE_SOLVER] dsf tree234 STANDALONE
|
||||||
|
|
||||||
ALL += SLIDE
|
ALL += SLIDE
|
||||||
|
|
||||||
!begin gtk
|
!begin gtk
|
||||||
|
@ -400,13 +400,18 @@ static struct board *newboard(int w, int h, unsigned char *data)
|
|||||||
/*
|
/*
|
||||||
* The actual solver. Given a board, attempt to find the minimum
|
* The actual solver. Given a board, attempt to find the minimum
|
||||||
* length of move sequence which moves MAINANCHOR to (tx,ty), or
|
* length of move sequence which moves MAINANCHOR to (tx,ty), or
|
||||||
* -1 if no solution exists. Returns that minimum length, and
|
* -1 if no solution exists. Returns that minimum length.
|
||||||
* (FIXME) optionally also writes out the actual moves into an
|
*
|
||||||
* as-yet-unprovided parameter.
|
* Also, if `moveout' is provided, writes out the moves in the
|
||||||
|
* form of a sequence of pairs of integers indicating the source
|
||||||
|
* and destination points of the anchor of the moved piece in each
|
||||||
|
* move. Exactly twice as many integers are written as the number
|
||||||
|
* returned from solve_board(), and `moveout' receives an int *
|
||||||
|
* which is a pointer to a dynamically allocated array.
|
||||||
*/
|
*/
|
||||||
static int solve_board(int w, int h, unsigned char *board,
|
static int solve_board(int w, int h, unsigned char *board,
|
||||||
unsigned char *forcefield, int tx, int ty,
|
unsigned char *forcefield, int tx, int ty,
|
||||||
int movelimit)
|
int movelimit, int **moveout)
|
||||||
{
|
{
|
||||||
int wh = w*h;
|
int wh = w*h;
|
||||||
struct board *b, *b2, *b3;
|
struct board *b, *b2, *b3;
|
||||||
@ -571,10 +576,49 @@ static int solve_board(int w, int h, unsigned char *board,
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
if (b2)
|
if (b2) {
|
||||||
ret = b2->dist;
|
ret = b2->dist;
|
||||||
else
|
if (moveout) {
|
||||||
|
/*
|
||||||
|
* Now b2 represents the solved position. Backtrack to
|
||||||
|
* output the solution.
|
||||||
|
*/
|
||||||
|
*moveout = snewn(ret * 2, int);
|
||||||
|
j = ret * 2;
|
||||||
|
|
||||||
|
while (b2->prev) {
|
||||||
|
int from = -1, to = -1;
|
||||||
|
|
||||||
|
b = b2->prev;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan b and b2 to find out which piece has
|
||||||
|
* moved.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < wh; i++) {
|
||||||
|
if (ISANCHOR(b->data[i]) && !ISANCHOR(b2->data[i])) {
|
||||||
|
assert(from == -1);
|
||||||
|
from = i;
|
||||||
|
} else if (!ISANCHOR(b->data[i]) && ISANCHOR(b2->data[i])){
|
||||||
|
assert(to == -1);
|
||||||
|
to = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(from >= 0 && to >= 0);
|
||||||
|
assert(j >= 2);
|
||||||
|
(*moveout)[--j] = to;
|
||||||
|
(*moveout)[--j] = from;
|
||||||
|
|
||||||
|
b2 = b;
|
||||||
|
}
|
||||||
|
assert(j == 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
ret = -1; /* no solution */
|
ret = -1; /* no solution */
|
||||||
|
if (moveout)
|
||||||
|
*moveout = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
freetree234(queue);
|
freetree234(queue);
|
||||||
|
|
||||||
@ -653,7 +697,7 @@ static void generate_board(int w, int h, int *rtx, int *rty, int *minmoves,
|
|||||||
* See if the board is already soluble.
|
* See if the board is already soluble.
|
||||||
*/
|
*/
|
||||||
if ((moves = solve_board(w, h, board, forcefield,
|
if ((moves = solve_board(w, h, board, forcefield,
|
||||||
tx, ty, movelimit)) >= 0)
|
tx, ty, movelimit, NULL)) >= 0)
|
||||||
goto soluble;
|
goto soluble;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -753,7 +797,7 @@ static void generate_board(int w, int h, int *rtx, int *rty, int *minmoves,
|
|||||||
} while (p2 < wh && board[p2] != DIST(p2-i));
|
} while (p2 < wh && board[p2] != DIST(p2-i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
j = solve_board(w, h, board, forcefield, tx, ty, movelimit);
|
j = solve_board(w, h, board, forcefield, tx, ty, movelimit, NULL);
|
||||||
if (j < 0) {
|
if (j < 0) {
|
||||||
/*
|
/*
|
||||||
* Didn't work. Revert the merge.
|
* Didn't work. Revert the merge.
|
||||||
@ -1979,3 +2023,89 @@ const struct game thegame = {
|
|||||||
FALSE, game_timing_state,
|
FALSE, game_timing_state,
|
||||||
0, /* flags */
|
0, /* flags */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef STANDALONE_SOLVER
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
game_params *p;
|
||||||
|
game_state *s;
|
||||||
|
char *id = NULL, *desc, *err;
|
||||||
|
int count = FALSE;
|
||||||
|
int ret, really_verbose = FALSE;
|
||||||
|
int *moves;
|
||||||
|
|
||||||
|
while (--argc > 0) {
|
||||||
|
char *p = *++argv;
|
||||||
|
if (!strcmp(p, "-v")) {
|
||||||
|
really_verbose = TRUE;
|
||||||
|
} else if (!strcmp(p, "-c")) {
|
||||||
|
count = TRUE;
|
||||||
|
} else if (*p == '-') {
|
||||||
|
fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
id = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
fprintf(stderr, "usage: %s [-c | -v] <game_id>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc = strchr(id, ':');
|
||||||
|
if (!desc) {
|
||||||
|
fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*desc++ = '\0';
|
||||||
|
|
||||||
|
p = default_params();
|
||||||
|
decode_params(p, id);
|
||||||
|
err = validate_desc(p, desc);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr, "%s: %s\n", argv[0], err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
s = new_game(NULL, p, desc);
|
||||||
|
|
||||||
|
ret = solve_board(s->w, s->h, s->board, s->imm->forcefield,
|
||||||
|
s->tx, s->ty, -1, &moves);
|
||||||
|
if (ret < 0) {
|
||||||
|
printf("No solution found\n");
|
||||||
|
} else {
|
||||||
|
int index = 0;
|
||||||
|
if (count) {
|
||||||
|
printf("%d moves required\n", ret);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
int moveret;
|
||||||
|
char *text = board_text_format(s->w, s->h, s->board,
|
||||||
|
s->imm->forcefield);
|
||||||
|
game_state *s2;
|
||||||
|
|
||||||
|
printf("position %d:\n%s", index, text);
|
||||||
|
|
||||||
|
if (index >= ret)
|
||||||
|
break;
|
||||||
|
|
||||||
|
s2 = dup_game(s);
|
||||||
|
moveret = move_piece(s->w, s->h, s->board,
|
||||||
|
s2->board, s->imm->forcefield,
|
||||||
|
moves[index*2], moves[index*2+1]);
|
||||||
|
assert(moveret);
|
||||||
|
|
||||||
|
free_game(s);
|
||||||
|
s = s2;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
Reference in New Issue
Block a user