shithub: puzzles

Download patch

ref: f7d2c94138427a70cf8795d5c9e02287127602d7
parent: 2d30316b768fb0ce806df9fda8cd21335b66446a
author: Simon Tatham <anakin@pobox.com>
date: Mon May 7 15:08:52 EDT 2007

Add an optional move limit during game generation.

[originally from svn r7554]

--- a/unfinished/slide.c
+++ b/unfinished/slide.c
@@ -23,17 +23,8 @@
  * 	 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!
+ *     * the move limit tends to make the game _slower_ to
+ * 	 generate, which is odd. Perhaps investigate why.
  * 
  *  - Improve the graphics.
  *     * All the colours are a bit wishy-washy. _Some_ dark
@@ -140,6 +131,7 @@
 
 struct game_params {
     int w, h;
+    int maxmoves;
 };
 
 struct game_immutable_state {
@@ -162,17 +154,17 @@
 {
     game_params *ret = snew(game_params);
 
-    ret->w = 8;
+    ret->w = 7;
     ret->h = 6;
+    ret->maxmoves = 40;
 
     return ret;
 }
 
 static const struct game_params slide_presets[] = {
-    {6, 5},
-    {7, 5},
-    {7, 6},
-    {8, 6},
+    {7, 6, 25},
+    {7, 6, -1},
+    {8, 6, -1},
 };
 
 static int game_fetch_preset(int i, char **name, game_params **params)
@@ -187,6 +179,10 @@
     *ret = slide_presets[i];
 
     sprintf(str, "%dx%d", ret->w, ret->h);
+    if (ret->maxmoves >= 0)
+	sprintf(str + strlen(str), ", max %d moves", ret->maxmoves);
+    else
+	sprintf(str + strlen(str), ", no move limit");
 
     *name = dupstr(str);
     *params = ret;
@@ -212,7 +208,16 @@
     if (*string == 'x') {
         string++;
         params->h = atoi(string);
+	while (*string && isdigit((unsigned char)*string)) string++;
     }
+    if (*string == 'm') {
+        string++;
+        params->maxmoves = atoi(string);
+	while (*string && isdigit((unsigned char)*string)) string++;
+    } else if (*string == 'u') {
+	string++;
+	params->maxmoves = -1;
+    }
 }
 
 static char *encode_params(game_params *params, int full)
@@ -220,6 +225,10 @@
     char data[256];
 
     sprintf(data, "%dx%d", params->w, params->h);
+    if (params->maxmoves >= 0)
+	sprintf(data + strlen(data), "m%d", params->maxmoves);
+    else
+	sprintf(data + strlen(data), "u");
 
     return dupstr(data);
 }
@@ -229,7 +238,7 @@
     config_item *ret;
     char buf[80];
 
-    ret = snewn(3, config_item);
+    ret = snewn(4, config_item);
 
     ret[0].name = "Width";
     ret[0].type = C_STRING;
@@ -243,11 +252,17 @@
     ret[1].sval = dupstr(buf);
     ret[1].ival = 0;
 
-    ret[2].name = NULL;
-    ret[2].type = C_END;
-    ret[2].sval = NULL;
+    ret[2].name = "Solution length limit";
+    ret[2].type = C_STRING;
+    sprintf(buf, "%d", params->maxmoves);
+    ret[2].sval = dupstr(buf);
     ret[2].ival = 0;
 
+    ret[3].name = NULL;
+    ret[3].type = C_END;
+    ret[3].sval = NULL;
+    ret[3].ival = 0;
+
     return ret;
 }
 
@@ -257,6 +272,7 @@
 
     ret->w = atoi(cfg[0].sval);
     ret->h = atoi(cfg[1].sval);
+    ret->maxmoves = atoi(cfg[2].sval);
 
     return ret;
 }
@@ -389,7 +405,8 @@
  * as-yet-unprovided parameter.
  */
 static int solve_board(int w, int h, unsigned char *board,
-		       unsigned char *forcefield, int tx, int ty)
+		       unsigned char *forcefield, int tx, int ty,
+		       int movelimit)
 {
     int wh = w*h;
     struct board *b, *b2, *b3;
@@ -443,6 +460,14 @@
 
     while ((b = delpos234(queue, 0)) != NULL) {
 	qlen--;
+	if (movelimit >= 0 && b->dist >= movelimit) {
+	    /*
+	     * The problem is not soluble in under `movelimit'
+	     * moves, so we can quit right now.
+	     */
+	    b2 = NULL;
+	    goto done;
+	}
 	if (b->dist != lastdist) {
 #ifdef SOLVER_DIAGNOSTICS
 	    printf("dist %d (%d)\n", b->dist, count234(sorted));
@@ -572,7 +597,7 @@
 
 static void generate_board(int w, int h, int *rtx, int *rty, int *minmoves,
 			   random_state *rs, unsigned char **rboard,
-			   unsigned char **rforcefield)
+			   unsigned char **rforcefield, int movelimit)
 {
     int wh = w*h;
     unsigned char *board, *board2, *forcefield;
@@ -628,7 +653,7 @@
 		 * See if the board is already soluble.
 		 */
 		if ((moves = solve_board(w, h, board, forcefield,
-					 tx, ty)) >= 0)
+					 tx, ty, movelimit)) >= 0)
 		    goto soluble;
 
 		/*
@@ -678,9 +703,7 @@
 	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
@@ -730,7 +753,7 @@
 		} while (p2 < wh && board[p2] != DIST(p2-i));
 	    }
 	}
-	j = solve_board(w, h, board, forcefield, tx, ty);
+	j = solve_board(w, h, board, forcefield, tx, ty, movelimit);
 	if (j < 0) {
 	    /*
 	     * Didn't work. Revert the merge.
@@ -776,7 +799,7 @@
     int i;
 
     generate_board(params->w, params->h, &tx, &ty, &minmoves, rs,
-		   &board, &forcefield);
+		   &board, &forcefield, params->maxmoves);
 #ifdef GENERATOR_DIAGNOSTICS
     {
 	char *t = board_text_format(params->w, params->h, board);