Slight solver speedup by tracking more carefully which block merges
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 7 May 2007 17:51:37 +0000 (17:51 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 7 May 2007 17:51:37 +0000 (17:51 +0000)
we've already tried, and not trying them again.

git-svn-id: svn://svn.tartarus.org/sgt/puzzles@7553 cda61777-01e9-0310-a592-d414129be87e

unfinished/slide.c

index c9afe41..130c7b9 100644 (file)
  *    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 @@ static void generate_board(int w, int h, int *rtx, int *rty, int *minmoves,
 {
     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 @@ static void generate_board(int w, int h, int *rtx, int *rty, int *minmoves,
     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 @@ static void generate_board(int w, int h, int *rtx, int *rty, int *minmoves,
     /*
      * 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 @@ static void generate_board(int w, int h, int *rtx, int *rty, int *minmoves,
        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 @@ static void generate_board(int w, int h, int *rtx, int *rty, int *minmoves,
             * 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 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
        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);