mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-20 23:51:29 -07:00
Prevent starting in a solved state in Fifteen & Flood
(cherry picked from Android port, commit cb38abdc71780bd9b393b90514396c338306fa69)
This commit is contained in:
141
fifteen.c
141
fifteen.c
@ -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;
|
||||||
|
6
flood.c
6
flood.c
@ -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.
|
||||||
|
Reference in New Issue
Block a user