shithub: puzzles

Download patch

ref: 2d30316b768fb0ce806df9fda8cd21335b66446a
parent: ab80d0b7fdd07bfc9037a44df97d862ce5e986ea
author: Simon Tatham <anakin@pobox.com>
date: Mon May 7 13:51:37 EDT 2007

Slight solver speedup by tracking more carefully which block merges
we've already tried, and not trying them again.

[originally from svn r7553]

--- a/unfinished/slide.c
+++ b/unfinished/slide.c
@@ -17,11 +17,31 @@
  *    cases.
  * 
  *  - Improve the generator.
+ *     * actually, we seem to be mostly sensible already now. I
+ * 	 want more choice over the type of main block and location
+ * 	 of the exit/target, and I think I probably ought to give
+ * 	 up on compactness and just bite the bullet and have the
+ * 	 target area right outside the main wall, but mostly I
+ * 	 think it's OK.
+ *     * but adjust the presets, because 8x6 is _slow_ to
+ * 	 generate.
+ *     * also, introduce a difficulty scheme, in the form of
+ * 	 limiting the minimum move count. This is obviously
+ * 	 sensible, because it also speeds up generation since the
+ * 	 solver can bomb out once it hits that ceiling!
+ * 	  + I was going to say I'd need to work out a minimum move
+ * 	    count for each grid size, but actually I think not: if
+ * 	    you ask for too few moves, it just has to remove still
+ * 	    more singletons, until at move count 1 you end up with
+ * 	    nothing in your way at all and it SERVES YOU RIGHT!
  * 
- *  - All the colours are a bit wishy-washy. _Some_ dark colours
- *    would surely not be excessive? Probably darken the tiles,
- *    the walls and the main block, and leave the target marker
- *    pale.
+ *  - Improve the graphics.
+ *     * All the colours are a bit wishy-washy. _Some_ dark
+ * 	 colours would surely not be excessive? Probably darken
+ * 	 the tiles, the walls and the main block, and leave the
+ * 	 target marker pale.
+ *     * The cattle grid effect is still disgusting. Think of
+ * 	 something completely different.
  */
 
 #include <stdio.h>
@@ -556,6 +576,8 @@
 {
     int wh = w*h;
     unsigned char *board, *board2, *forcefield;
+    unsigned char *tried_merge;
+    int *dsf;
     int *list, nlist, pos;
     int tx, ty;
     int i, j;
@@ -575,6 +597,10 @@
     for (i = 0; i < h; i++)
 	board[i*w] = board[i*w+(w-1)] = WALL;
 
+    tried_merge = snewn(wh * wh, unsigned char);
+    memset(tried_merge, 0, wh*wh);
+    dsf = snew_dsf(wh);
+
     /*
      * Invent a main piece at one extreme. (FIXME: vary the
      * extreme, and the piece.)
@@ -628,19 +654,11 @@
     /*
      * Now go through that list in random order, trying to merge
      * the blocks on each side of each edge.
-     * 
-     * FIXME: this seems to produce unpleasantly unbalanced
-     * results. Perhaps we'd do better if we always tried to
-     * combine the _smallest_ block with something?
-     * 
-     * FIXME: also one reason it's slow might be because we aren't
-     * tracking which blocks we've already tried to merge, when
-     * another edge ends up linking the same ones.
      */
     shuffle(list, nlist, sizeof(*list), rs);
     while (nlist > 0) {
-	int x1, y1, p1;
-	int x2, y2, p2;
+	int x1, y1, p1, c1;
+	int x2, y2, p2, c2;
 
 	pos = list[--nlist];
 	y1 = y2 = pos / (w*2);
@@ -653,6 +671,18 @@
 	p2 = y2*w+x2;
 
 	/*
+	 * Immediately abandon the attempt if we've already tried
+	 * to merge the same pair of blocks along a different
+	 * edge.
+	 */
+	c1 = dsf_canonify(dsf, p1);
+	c2 = dsf_canonify(dsf, p2);
+	if (tried_merge[c1 * wh + c2])
+{printf("aha\n");
+	    continue;
+}
+
+	/*
 	 * In order to be mergeable, these two squares must each
 	 * either be, or belong to, a non-main anchor, and their
 	 * anchors must also be distinct.
@@ -706,8 +736,20 @@
 	     * Didn't work. Revert the merge.
 	     */
 	    memcpy(board, board2, wh);
+	    tried_merge[c1 * wh + c2] = tried_merge[c2 * wh + c1] = TRUE;
 	} else {
+	    int c;
+
 	    moves = j;
+
+	    dsf_merge(dsf, c1, c2);
+	    c = dsf_canonify(dsf, c1);
+	    for (i = 0; i < wh; i++)
+		tried_merge[c*wh+i] = (tried_merge[c1*wh+i] |
+				       tried_merge[c2*wh+i]);
+	    for (i = 0; i < wh; i++)
+		tried_merge[i*wh+c] = (tried_merge[i*wh+c1] |
+				       tried_merge[i*wh+c2]);
 	}
     }
 
@@ -1835,7 +1877,7 @@
 	sprintf(statusbuf, "%sMoves: %d",
 		(state->completed >= 0 ? "COMPLETED! " : ""),
 		(state->completed >= 0 ? state->completed : state->movecount));
-	if (state->minmoves)
+	if (state->minmoves >= 0)
 	    sprintf(statusbuf+strlen(statusbuf), " (min %d)",
 		    state->minmoves);