mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 16:05:44 -07:00
Run the final solution-reduction pass in both directions, since
Gareth managed to find an example (10x8#458168771440033 in r6289) where running it in only one direction failed to eliminate an obviously redundant piece of path. [originally from svn r6290] [r6289 == b25fcc3f2621b0b41f3ae7cdabe57ed07f62d2c2]
This commit is contained in:
274
inertia.c
274
inertia.c
@ -1160,7 +1160,7 @@ static char *solve_game(game_state *state, game_state *currstate,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TSP_DIAGNOSTICS
|
#ifndef TSP_DIAGNOSTICS
|
||||||
printf("before reduction, moves are ");
|
printf("before reduction, moves are ");
|
||||||
x = nodes[circuit[0]] / DP1 % w;
|
x = nodes[circuit[0]] / DP1 % w;
|
||||||
y = nodes[circuit[0]] / DP1 / w;
|
y = nodes[circuit[0]] / DP1 / w;
|
||||||
@ -1198,159 +1198,179 @@ static char *solve_game(game_state *state, game_state *currstate,
|
|||||||
*/
|
*/
|
||||||
while (1) {
|
while (1) {
|
||||||
int oldlen = circuitlen;
|
int oldlen = circuitlen;
|
||||||
|
int dir;
|
||||||
|
|
||||||
for (i = 0; i < wh; i++)
|
for (dir = +1; dir >= -1; dir -= 2) {
|
||||||
unvisited[i] = 0;
|
|
||||||
for (i = 0; i < circuitlen; i++) {
|
|
||||||
int xy = nodes[circuit[i]] / DP1;
|
|
||||||
if (currstate->grid[xy] == GEM)
|
|
||||||
unvisited[xy]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
for (i = 0; i < wh; i++)
|
||||||
* If there's any gem we didn't end up visiting at all,
|
unvisited[i] = 0;
|
||||||
* give up.
|
for (i = 0; i < circuitlen; i++) {
|
||||||
*/
|
int xy = nodes[circuit[i]] / DP1;
|
||||||
for (i = 0; i < wh; i++) {
|
if (currstate->grid[xy] == GEM)
|
||||||
if (currstate->grid[i] == GEM && unvisited[i] == 0) {
|
unvisited[xy]++;
|
||||||
err = "Unable to find a solution from this starting point";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (i < wh)
|
|
||||||
break;
|
|
||||||
|
|
||||||
for (i = j = 0; i < circuitlen; i++) {
|
/*
|
||||||
int xy = nodes[circuit[i]] / DP1;
|
* If there's any gem we didn't end up visiting at all,
|
||||||
if (currstate->grid[xy] == GEM && unvisited[xy] > 1) {
|
* give up.
|
||||||
unvisited[xy]--;
|
*/
|
||||||
} else if (currstate->grid[xy] == GEM || i == circuitlen-1) {
|
for (i = 0; i < wh; i++) {
|
||||||
/*
|
if (currstate->grid[i] == GEM && unvisited[i] == 0) {
|
||||||
* circuit[i] collects a gem for the only time, or is
|
err = "Unable to find a solution from this starting point";
|
||||||
* the last node in the circuit. Therefore it cannot be
|
break;
|
||||||
* removed; so we now want to replace the path from
|
}
|
||||||
* circuit[j] to circuit[i] with a bfs-shortest path.
|
}
|
||||||
*/
|
if (i < wh)
|
||||||
int k, dest, ni, ti, thisdist;
|
break;
|
||||||
|
|
||||||
#ifdef TSP_DIAGNOSTICS
|
for (i = j = (dir > 0 ? 0 : circuitlen-1);
|
||||||
printf("optimising section from %d - %d\n", j, i);
|
i < circuitlen && i >= 0;
|
||||||
|
i += dir) {
|
||||||
|
int xy = nodes[circuit[i]] / DP1;
|
||||||
|
if (currstate->grid[xy] == GEM && unvisited[xy] > 1) {
|
||||||
|
unvisited[xy]--;
|
||||||
|
} else if (currstate->grid[xy] == GEM || i == circuitlen-1) {
|
||||||
|
/*
|
||||||
|
* circuit[i] collects a gem for the only time,
|
||||||
|
* or is the last node in the circuit.
|
||||||
|
* Therefore it cannot be removed; so we now
|
||||||
|
* want to replace the path from circuit[j] to
|
||||||
|
* circuit[i] with a bfs-shortest path.
|
||||||
|
*/
|
||||||
|
int p, q, k, dest, ni, ti, thisdist;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up the upper and lower bounds of the
|
||||||
|
* reduced section.
|
||||||
|
*/
|
||||||
|
p = min(i, j);
|
||||||
|
q = max(i, j);
|
||||||
|
|
||||||
|
#ifndef TSP_DIAGNOSTICS
|
||||||
|
printf("optimising section from %d - %d\n", p, q);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (k = 0; k < n; k++)
|
for (k = 0; k < n; k++)
|
||||||
dist[k] = -1;
|
dist[k] = -1;
|
||||||
head = tail = 0;
|
head = tail = 0;
|
||||||
|
|
||||||
dist[circuit[j]] = 0;
|
dist[circuit[p]] = 0;
|
||||||
list[tail++] = circuit[j];
|
list[tail++] = circuit[p];
|
||||||
|
|
||||||
while (head < tail && dist[circuit[i]] < 0) {
|
while (head < tail && dist[circuit[q]] < 0) {
|
||||||
int ni = list[head++];
|
int ni = list[head++];
|
||||||
for (k = edgei[ni]; k < edgei[ni+1]; k++) {
|
for (k = edgei[ni]; k < edgei[ni+1]; k++) {
|
||||||
int ti = edges[k];
|
int ti = edges[k];
|
||||||
if (ti >= 0 && dist[ti] < 0) {
|
if (ti >= 0 && dist[ti] < 0) {
|
||||||
dist[ti] = dist[ni] + 1;
|
dist[ti] = dist[ni] + 1;
|
||||||
list[tail++] = ti;
|
list[tail++] = ti;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
thisdist = dist[circuit[i]];
|
thisdist = dist[circuit[q]];
|
||||||
assert(thisdist >= 0 && thisdist <= i-j);
|
assert(thisdist >= 0 && thisdist <= q-p);
|
||||||
|
|
||||||
memmove(circuit+j+thisdist, circuit+i,
|
memmove(circuit+p+thisdist, circuit+q,
|
||||||
(circuitlen - i) * sizeof(int));
|
(circuitlen - q) * sizeof(int));
|
||||||
circuitlen -= i-j;
|
circuitlen -= q-p;
|
||||||
i = j + thisdist;
|
q = p + thisdist;
|
||||||
circuitlen += i-j;
|
circuitlen += q-p;
|
||||||
|
|
||||||
#ifdef TSP_DIAGNOSTICS
|
if (dir > 0)
|
||||||
printf("new section runs from %d - %d\n", j, i);
|
i = q; /* resume loop from the right place */
|
||||||
|
|
||||||
|
#ifndef TSP_DIAGNOSTICS
|
||||||
|
printf("new section runs from %d - %d\n", p, q);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dest = i;
|
dest = q;
|
||||||
assert(dest >= 0);
|
assert(dest >= 0);
|
||||||
ni = circuit[i];
|
ni = circuit[q];
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
/* printf("dest=%d circuitlen=%d ni=%d dist[ni]=%d\n", dest, circuitlen, ni, dist[ni]); */
|
/* printf("dest=%d circuitlen=%d ni=%d dist[ni]=%d\n", dest, circuitlen, ni, dist[ni]); */
|
||||||
circuit[dest] = ni;
|
circuit[dest] = ni;
|
||||||
if (dist[ni] == 0)
|
if (dist[ni] == 0)
|
||||||
break;
|
|
||||||
dest--;
|
|
||||||
ti = -1;
|
|
||||||
for (k = backedgei[ni]; k < backedgei[ni+1]; k++) {
|
|
||||||
ti = backedges[k];
|
|
||||||
if (ti >= 0 && dist[ti] == dist[ni] - 1)
|
|
||||||
break;
|
break;
|
||||||
|
dest--;
|
||||||
|
ti = -1;
|
||||||
|
for (k = backedgei[ni]; k < backedgei[ni+1]; k++) {
|
||||||
|
ti = backedges[k];
|
||||||
|
if (ti >= 0 && dist[ti] == dist[ni] - 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert(k < backedgei[ni+1] && ti >= 0);
|
||||||
|
ni = ti;
|
||||||
}
|
}
|
||||||
assert(k < backedgei[ni+1] && ti >= 0);
|
|
||||||
ni = ti;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now re-increment the visit counts for the new
|
* Now re-increment the visit counts for the
|
||||||
* path.
|
* new path.
|
||||||
*/
|
*/
|
||||||
while (++j < i) {
|
while (++p < q) {
|
||||||
int xy = nodes[circuit[j]] / DP1;
|
int xy = nodes[circuit[p]] / DP1;
|
||||||
if (currstate->grid[xy] == GEM)
|
if (currstate->grid[xy] == GEM)
|
||||||
unvisited[xy]++;
|
unvisited[xy]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TSP_DIAGNOSTICS
|
j = i;
|
||||||
printf("during reduction, circuit is");
|
|
||||||
for (k = 0; k < circuitlen; k++) {
|
#ifndef TSP_DIAGNOSTICS
|
||||||
int nc = nodes[circuit[k]];
|
printf("during reduction, circuit is");
|
||||||
printf(" (%d,%d,%d)", nc/DP1%w, nc/(DP1*w), nc%DP1);
|
for (k = 0; k < circuitlen; k++) {
|
||||||
}
|
int nc = nodes[circuit[k]];
|
||||||
printf("\n");
|
printf(" (%d,%d,%d)", nc/DP1%w, nc/(DP1*w), nc%DP1);
|
||||||
printf("moves are ");
|
}
|
||||||
x = nodes[circuit[0]] / DP1 % w;
|
printf("\n");
|
||||||
y = nodes[circuit[0]] / DP1 / w;
|
printf("moves are ");
|
||||||
for (k = 1; k < circuitlen; k++) {
|
x = nodes[circuit[0]] / DP1 % w;
|
||||||
int x2, y2, dx, dy;
|
y = nodes[circuit[0]] / DP1 / w;
|
||||||
if (nodes[circuit[k]] % DP1 != DIRECTIONS)
|
for (k = 1; k < circuitlen; k++) {
|
||||||
continue;
|
int x2, y2, dx, dy;
|
||||||
x2 = nodes[circuit[k]] / DP1 % w;
|
if (nodes[circuit[k]] % DP1 != DIRECTIONS)
|
||||||
y2 = nodes[circuit[k]] / DP1 / w;
|
continue;
|
||||||
dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
|
x2 = nodes[circuit[k]] / DP1 % w;
|
||||||
dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
|
y2 = nodes[circuit[k]] / DP1 / w;
|
||||||
for (d = 0; d < DIRECTIONS; d++)
|
dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
|
||||||
if (DX(d) == dx && DY(d) == dy)
|
dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
|
||||||
printf("%c", "89632147"[d]);
|
for (d = 0; d < DIRECTIONS; d++)
|
||||||
x = x2;
|
if (DX(d) == dx && DY(d) == dy)
|
||||||
y = y2;
|
printf("%c", "89632147"[d]);
|
||||||
}
|
x = x2;
|
||||||
printf("\n");
|
y = y2;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TSP_DIAGNOSTICS
|
#ifndef TSP_DIAGNOSTICS
|
||||||
printf("after reduction, moves are ");
|
printf("after reduction, moves are ");
|
||||||
x = nodes[circuit[0]] / DP1 % w;
|
x = nodes[circuit[0]] / DP1 % w;
|
||||||
y = nodes[circuit[0]] / DP1 / w;
|
y = nodes[circuit[0]] / DP1 / w;
|
||||||
for (i = 1; i < circuitlen; i++) {
|
for (i = 1; i < circuitlen; i++) {
|
||||||
int x2, y2, dx, dy;
|
int x2, y2, dx, dy;
|
||||||
if (nodes[circuit[i]] % DP1 != DIRECTIONS)
|
if (nodes[circuit[i]] % DP1 != DIRECTIONS)
|
||||||
continue;
|
continue;
|
||||||
x2 = nodes[circuit[i]] / DP1 % w;
|
x2 = nodes[circuit[i]] / DP1 % w;
|
||||||
y2 = nodes[circuit[i]] / DP1 / w;
|
y2 = nodes[circuit[i]] / DP1 / w;
|
||||||
dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
|
dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
|
||||||
dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
|
dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
|
||||||
for (d = 0; d < DIRECTIONS; d++)
|
for (d = 0; d < DIRECTIONS; d++)
|
||||||
if (DX(d) == dx && DY(d) == dy)
|
if (DX(d) == dx && DY(d) == dy)
|
||||||
printf("%c", "89632147"[d]);
|
printf("%c", "89632147"[d]);
|
||||||
x = x2;
|
x = x2;
|
||||||
y = y2;
|
y = y2;
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we've managed an entire reduction pass and not made
|
* If we've managed an entire reduction pass in each
|
||||||
* the solution any shorter, we're _really_ done.
|
* direction and not made the solution any shorter, we're
|
||||||
|
* _really_ done.
|
||||||
*/
|
*/
|
||||||
if (circuitlen == oldlen)
|
if (circuitlen == oldlen)
|
||||||
break;
|
break;
|
||||||
|
Reference in New Issue
Block a user