shithub: puzzles

Download patch

ref: 3d3d00991a728a5cb7a1cbb7ba4985057043beb9
parent: b25fcc3f2621b0b41f3ae7cdabe57ed07f62d2c2
author: Simon Tatham <anakin@pobox.com>
date: Sun Sep 11 10:22:32 EDT 2005

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]

--- a/inertia.c
+++ b/inertia.c
@@ -1160,7 +1160,7 @@
 	}
     }
 
-#ifdef TSP_DIAGNOSTICS
+#ifndef TSP_DIAGNOSTICS
     printf("before reduction, moves are ");
     x = nodes[circuit[0]] / DP1 % w;
     y = nodes[circuit[0]] / DP1 / w;
@@ -1198,159 +1198,179 @@
      */
     while (1) {
 	int oldlen = circuitlen;
+	int dir;
 
-	for (i = 0; i < wh; i++)
-	    unvisited[i] = 0;
-	for (i = 0; i < circuitlen; i++) {
-	    int xy = nodes[circuit[i]] / DP1;
-	    if (currstate->grid[xy] == GEM)
-		unvisited[xy]++;
-	}
+	for (dir = +1; dir >= -1; dir -= 2) {
 
-	/*
-	 * If there's any gem we didn't end up visiting at all,
-	 * give up.
-	 */
-	for (i = 0; i < wh; i++) {
-	    if (currstate->grid[i] == GEM && unvisited[i] == 0) {
-		err = "Unable to find a solution from this starting point";
-		break;
+	    for (i = 0; i < wh; i++)
+		unvisited[i] = 0;
+	    for (i = 0; i < circuitlen; i++) {
+		int xy = nodes[circuit[i]] / DP1;
+		if (currstate->grid[xy] == GEM)
+		    unvisited[xy]++;
 	    }
-	}
-	if (i < wh)
-	    break;
 
-	for (i = j = 0; i < circuitlen; i++) {
-	    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 k, dest, ni, ti, thisdist;
+	    /*
+	     * If there's any gem we didn't end up visiting at all,
+	     * give up.
+	     */
+	    for (i = 0; i < wh; i++) {
+		if (currstate->grid[i] == GEM && unvisited[i] == 0) {
+		    err = "Unable to find a solution from this starting point";
+		    break;
+		}
+	    }
+	    if (i < wh)
+		break;
 
-#ifdef TSP_DIAGNOSTICS
-		printf("optimising section from %d - %d\n", j, i);
+	    for (i = j = (dir > 0 ? 0 : circuitlen-1);
+		 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
 
-		for (k = 0; k < n; k++)
-		    dist[k] = -1;
-		head = tail = 0;
+		    for (k = 0; k < n; k++)
+			dist[k] = -1;
+		    head = tail = 0;
 
-		dist[circuit[j]] = 0;
-		list[tail++] = circuit[j];
+		    dist[circuit[p]] = 0;
+		    list[tail++] = circuit[p];
 
-		while (head < tail && dist[circuit[i]] < 0) {
-		    int ni = list[head++];
-		    for (k = edgei[ni]; k < edgei[ni+1]; k++) {
-			int ti = edges[k];
-			if (ti >= 0 && dist[ti] < 0) {
-			    dist[ti] = dist[ni] + 1;
-			    list[tail++] = ti;
+		    while (head < tail && dist[circuit[q]] < 0) {
+			int ni = list[head++];
+			for (k = edgei[ni]; k < edgei[ni+1]; k++) {
+			    int ti = edges[k];
+			    if (ti >= 0 && dist[ti] < 0) {
+				dist[ti] = dist[ni] + 1;
+				list[tail++] = ti;
+			    }
 			}
 		    }
-		}
 
-		thisdist = dist[circuit[i]];
-		assert(thisdist >= 0 && thisdist <= i-j);
+		    thisdist = dist[circuit[q]];
+		    assert(thisdist >= 0 && thisdist <= q-p);
 
-		memmove(circuit+j+thisdist, circuit+i,
-			(circuitlen - i) * sizeof(int));
-		circuitlen -= i-j;
-		i = j + thisdist;
-		circuitlen += i-j;
+		    memmove(circuit+p+thisdist, circuit+q,
+			    (circuitlen - q) * sizeof(int));
+		    circuitlen -= q-p;
+		    q = p + thisdist;
+		    circuitlen += q-p;
 
-#ifdef TSP_DIAGNOSTICS
-		printf("new section runs from %d - %d\n", j, i);
+		    if (dir > 0)
+			i = q;	       /* resume loop from the right place */
+
+#ifndef TSP_DIAGNOSTICS
+		    printf("new section runs from %d - %d\n", p, q);
 #endif
 
-		dest = i;
-		assert(dest >= 0);
-		ni = circuit[i];
+		    dest = q;
+		    assert(dest >= 0);
+		    ni = circuit[q];
 
-		while (1) {
-		    /* printf("dest=%d circuitlen=%d ni=%d dist[ni]=%d\n", dest, circuitlen, ni, dist[ni]); */
-		    circuit[dest] = ni;
-		    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)
+		    while (1) {
+			/* printf("dest=%d circuitlen=%d ni=%d dist[ni]=%d\n", dest, circuitlen, ni, dist[ni]); */
+			circuit[dest] = ni;
+			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;
+			}
+			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
-		 * path.
-		 */
-		while (++j < i) {
-		    int xy = nodes[circuit[j]] / DP1;
-		    if (currstate->grid[xy] == GEM)
-			unvisited[xy]++;
-		}
+		    /*
+		     * Now re-increment the visit counts for the
+		     * new path.
+		     */
+		    while (++p < q) {
+			int xy = nodes[circuit[p]] / DP1;
+			if (currstate->grid[xy] == GEM)
+			    unvisited[xy]++;
+		    }
 
-#ifdef TSP_DIAGNOSTICS
-		printf("during reduction, circuit is");
-		for (k = 0; k < circuitlen; k++) {
-		    int nc = nodes[circuit[k]];
-		    printf(" (%d,%d,%d)", nc/DP1%w, nc/(DP1*w), nc%DP1);
-		}
-		printf("\n");
-		printf("moves are ");
-		x = nodes[circuit[0]] / DP1 % w;
-		y = nodes[circuit[0]] / DP1 / w;
-		for (k = 1; k < circuitlen; k++) {
-		    int x2, y2, dx, dy;
-		    if (nodes[circuit[k]] % DP1 != DIRECTIONS)
-			continue;
-		    x2 = nodes[circuit[k]] / DP1 % w;
-		    y2 = nodes[circuit[k]] / DP1 / w;
-		    dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
-		    dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
-		    for (d = 0; d < DIRECTIONS; d++)
-			if (DX(d) == dx && DY(d) == dy)
-			    printf("%c", "89632147"[d]);
-		    x = x2;
-		    y = y2;
-		}
-		printf("\n");
+		    j = i;
+
+#ifndef TSP_DIAGNOSTICS
+		    printf("during reduction, circuit is");
+		    for (k = 0; k < circuitlen; k++) {
+			int nc = nodes[circuit[k]];
+			printf(" (%d,%d,%d)", nc/DP1%w, nc/(DP1*w), nc%DP1);
+		    }
+		    printf("\n");
+		    printf("moves are ");
+		    x = nodes[circuit[0]] / DP1 % w;
+		    y = nodes[circuit[0]] / DP1 / w;
+		    for (k = 1; k < circuitlen; k++) {
+			int x2, y2, dx, dy;
+			if (nodes[circuit[k]] % DP1 != DIRECTIONS)
+			    continue;
+			x2 = nodes[circuit[k]] / DP1 % w;
+			y2 = nodes[circuit[k]] / DP1 / w;
+			dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
+			dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
+			for (d = 0; d < DIRECTIONS; d++)
+			    if (DX(d) == dx && DY(d) == dy)
+				printf("%c", "89632147"[d]);
+			x = x2;
+			y = y2;
+		    }
+		    printf("\n");
 #endif
+		}
 	    }
-	}
 
-#ifdef TSP_DIAGNOSTICS
-	printf("after reduction, moves are ");
-	x = nodes[circuit[0]] / DP1 % w;
-	y = nodes[circuit[0]] / DP1 / w;
-	for (i = 1; i < circuitlen; i++) {
-	    int x2, y2, dx, dy;
-	    if (nodes[circuit[i]] % DP1 != DIRECTIONS)
-		continue;
-	    x2 = nodes[circuit[i]] / DP1 % w;
-	    y2 = nodes[circuit[i]] / DP1 / w;
-	    dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
-	    dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
-	    for (d = 0; d < DIRECTIONS; d++)
-		if (DX(d) == dx && DY(d) == dy)
-		    printf("%c", "89632147"[d]);
-	    x = x2;
-	    y = y2;
-	}
-	printf("\n");
+#ifndef TSP_DIAGNOSTICS
+	    printf("after reduction, moves are ");
+	    x = nodes[circuit[0]] / DP1 % w;
+	    y = nodes[circuit[0]] / DP1 / w;
+	    for (i = 1; i < circuitlen; i++) {
+		int x2, y2, dx, dy;
+		if (nodes[circuit[i]] % DP1 != DIRECTIONS)
+		    continue;
+		x2 = nodes[circuit[i]] / DP1 % w;
+		y2 = nodes[circuit[i]] / DP1 / w;
+		dx = (x2 > x ? +1 : x2 < x ? -1 : 0);
+		dy = (y2 > y ? +1 : y2 < y ? -1 : 0);
+		for (d = 0; d < DIRECTIONS; d++)
+		    if (DX(d) == dx && DY(d) == dy)
+			printf("%c", "89632147"[d]);
+		x = x2;
+		y = y2;
+	    }
+	    printf("\n");
 #endif
+	}
 
 	/*
-	 * If we've managed an entire reduction pass and not made
-	 * the solution any shorter, we're _really_ done.
+	 * If we've managed an entire reduction pass in each
+	 * direction and not made the solution any shorter, we're
+	 * _really_ done.
 	 */
 	if (circuitlen == oldlen)
 	    break;