Prevent starting in a solved state in Fifteen & Flood

(cherry picked from Android port, commit
cb38abdc71780bd9b393b90514396c338306fa69)
This commit is contained in:
Chris Boyle
2016-12-21 20:01:25 +00:00
committed by Ben Harris
parent 0d43753ff2
commit f967bfa87b
2 changed files with 78 additions and 69 deletions

141
fifteen.c
View File

@ -156,6 +156,14 @@ static int perm_parity(int *perm, int n)
return ret; return ret;
} }
static int is_completed(int *tiles, int n) {
int p;
for (p = 0; p < n; p++)
if (tiles[p] != (p < n-1 ? p+1 : 0))
return 0;
return 1;
}
static char *new_game_desc(const game_params *params, random_state *rs, static char *new_game_desc(const game_params *params, random_state *rs,
char **aux, bool interactive) char **aux, bool interactive)
{ {
@ -171,81 +179,83 @@ static char *new_game_desc(const game_params *params, random_state *rs,
tiles = snewn(n, int); tiles = snewn(n, int);
used = snewn(n, bool); used = snewn(n, bool);
for (i = 0; i < n; i++) { do {
tiles[i] = -1; for (i = 0; i < n; i++) {
used[i] = false; tiles[i] = -1;
} used[i] = false;
}
gap = random_upto(rs, n); gap = random_upto(rs, n);
tiles[gap] = 0; tiles[gap] = 0;
used[0] = true; used[0] = true;
/* /*
* Place everything else except the last two tiles. * Place everything else except the last two tiles.
*/ */
for (x = 0, i = n-1; i > 2; i--) { for (x = 0, i = n - 1; i > 2; i--) {
int k = random_upto(rs, i); int k = random_upto(rs, i);
int j; int j;
for (j = 0; j < n; j++) for (j = 0; j < n; j++)
if (!used[j] && (k-- == 0)) if (!used[j] && (k-- == 0))
break; break;
assert(j < n && !used[j]); assert(j < n && !used[j]);
used[j] = true; used[j] = true;
while (tiles[x] >= 0)
x++;
assert(x < n);
tiles[x] = j;
}
/*
* Find the last two locations, and the last two pieces.
*/
while (tiles[x] >= 0) while (tiles[x] >= 0)
x++; x++;
assert(x < n); assert(x < n);
tiles[x] = j; x1 = x;
}
/*
* Find the last two locations, and the last two pieces.
*/
while (tiles[x] >= 0)
x++; x++;
assert(x < n); while (tiles[x] >= 0)
x1 = x; x++;
x++; assert(x < n);
while (tiles[x] >= 0) x2 = x;
x++;
assert(x < n);
x2 = x;
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
if (!used[i]) if (!used[i])
break; break;
p1 = i; p1 = i;
for (i = p1+1; i < n; i++) for (i = p1 + 1; i < n; i++)
if (!used[i]) if (!used[i])
break; break;
p2 = i; p2 = i;
/* /*
* Determine the required parity of the overall permutation. * Determine the required parity of the overall permutation.
* This is the XOR of: * This is the XOR of:
* *
* - The chessboard parity ((x^y)&1) of the gap square. The * - The chessboard parity ((x^y)&1) of the gap square. The
* bottom right counts as even. * bottom right counts as even.
* *
* - The parity of n. (The target permutation is 1,...,n-1,0 * - The parity of n. (The target permutation is 1,...,n-1,0
* rather than 0,...,n-1; this is a cyclic permutation of * rather than 0,...,n-1; this is a cyclic permutation of
* the starting point and hence is odd iff n is even.) * the starting point and hence is odd iff n is even.)
*/ */
parity = PARITY_P(params, gap); parity = PARITY_P(params, gap);
/* /*
* Try the last two tiles one way round. If that fails, swap * Try the last two tiles one way round. If that fails, swap
* them. * them.
*/ */
tiles[x1] = p1; tiles[x1] = p1;
tiles[x2] = p2; tiles[x2] = p2;
if (perm_parity(tiles, n) != parity) { if (perm_parity(tiles, n) != parity) {
tiles[x1] = p2; tiles[x1] = p2;
tiles[x2] = p1; tiles[x2] = p1;
assert(perm_parity(tiles, n) == parity); assert(perm_parity(tiles, n) == parity);
} }
} while (is_completed(tiles, n));
/* /*
* Now construct the game description, by describing the tile * Now construct the game description, by describing the tile
@ -786,11 +796,8 @@ static game_state *execute_move(const game_state *from, const char *move)
/* /*
* See if the game has been completed. * See if the game has been completed.
*/ */
if (!ret->completed) { if (!ret->completed && is_completed(ret->tiles, ret->n)) {
ret->completed = ret->movecount; ret->completed = ret->movecount;
for (p = 0; p < ret->n; p++)
if (ret->tiles[p] != (p < ret->n-1 ? p+1 : 0))
ret->completed = 0;
} }
return ret; return ret;

View File

@ -552,8 +552,10 @@ static char *new_game_desc(const game_params *params, random_state *rs,
/* /*
* Invent a random grid. * Invent a random grid.
*/ */
for (i = 0; i < wh; i++) do {
scratch->grid[i] = random_upto(rs, params->colours); for (i = 0; i < wh; i++)
scratch->grid[i] = random_upto(rs, params->colours);
} while (completed(w, h, scratch->grid));
/* /*
* Run the solver, and count how many moves it uses. * Run the solver, and count how many moves it uses.