Update doc for recent changes in Restart behaviour.
[sgt/puzzles] / rect.c
diff --git a/rect.c b/rect.c
index 0a1a522..78c9e08 100644 (file)
--- a/rect.c
+++ b/rect.c
@@ -82,7 +82,7 @@ struct game_state {
     int *grid;                        /* contains the numbers */
     unsigned char *vedge;             /* (w+1) x h */
     unsigned char *hedge;             /* w x (h+1) */
-    int completed;
+    int completed, cheated;
 };
 
 static game_params *default_params(void)
@@ -130,12 +130,9 @@ static game_params *dup_params(game_params *params)
     return ret;
 }
 
-static game_params *decode_params(char const *string)
+static void decode_params(game_params *ret, char const *string)
 {
-    game_params *ret = default_params();
-
     ret->w = ret->h = atoi(string);
-    ret->expandfactor = 0.0F;
     while (*string && isdigit((unsigned char)*string)) string++;
     if (*string == 'x') {
         string++;
@@ -146,15 +143,15 @@ static game_params *decode_params(char const *string)
        string++;
        ret->expandfactor = atof(string);
     }
-
-    return ret;
 }
 
-static char *encode_params(game_params *params)
+static char *encode_params(game_params *params, int full)
 {
     char data[256];
 
     sprintf(data, "%dx%d", params->w, params->h);
+    if (full)
+        sprintf(data + strlen(data), "e%g", params->expandfactor);
 
     return dupstr(data);
 }
@@ -386,12 +383,19 @@ static void display_grid(game_params *params, int *grid, int *numbers, int all)
 }
 #endif
 
-static char *new_game_seed(game_params *params, random_state *rs)
+struct game_aux_info {
+    int w, h;
+    unsigned char *vedge;             /* (w+1) x h */
+    unsigned char *hedge;             /* w x (h+1) */
+};
+
+static char *new_game_desc(game_params *params, random_state *rs,
+                          game_aux_info **aux)
 {
     int *grid, *numbers;
     struct rectlist *list;
     int x, y, y2, y2last, yx, run, i;
-    char *seed, *p;
+    char *desc, *p;
     game_params params2real, *params2 = &params2real;
 
     /*
@@ -828,6 +832,31 @@ static char *new_game_seed(game_params *params, random_state *rs)
     }
 
     /*
+     * Store the rectangle data in the game_aux_info.
+     */
+    {
+       game_aux_info *ai = snew(game_aux_info);
+
+       ai->w = params->w;
+       ai->h = params->h;
+       ai->vedge = snewn(ai->w * ai->h, unsigned char);
+       ai->hedge = snewn(ai->w * ai->h, unsigned char);
+
+       for (y = 0; y < params->h; y++)
+           for (x = 1; x < params->w; x++) {
+               vedge(ai, x, y) =
+                   index(params, grid, x, y) != index(params, grid, x-1, y);
+           }
+       for (y = 1; y < params->h; y++)
+           for (x = 0; x < params->w; x++) {
+               hedge(ai, x, y) =
+                   index(params, grid, x, y) != index(params, grid, x, y-1);
+           }
+
+       *aux = ai;
+    }
+
+    /*
      * Place numbers.
      */
     numbers = snewn(params->w * params->h, int);
@@ -859,8 +888,8 @@ static char *new_game_seed(game_params *params, random_state *rs)
     display_grid(params, grid, numbers, FALSE);
 #endif
 
-    seed = snewn(11 * params->w * params->h, char);
-    p = seed;
+    desc = snewn(11 * params->w * params->h, char);
+    p = desc;
     run = 0;
     for (i = 0; i <= params->w * params->h; i++) {
         int n = (i < params->w * params->h ? numbers[i] : -1);
@@ -882,7 +911,7 @@ static char *new_game_seed(game_params *params, random_state *rs)
                  * bottom right, there's no point putting an
                  * unnecessary _ before or after it.
                  */
-                if (p > seed && n > 0)
+                if (p > desc && n > 0)
                     *p++ = '_';
             }
             if (n > 0)
@@ -895,26 +924,33 @@ static char *new_game_seed(game_params *params, random_state *rs)
     sfree(grid);
     sfree(numbers);
 
-    return seed;
+    return desc;
+}
+
+static void game_free_aux_info(game_aux_info *ai)
+{
+    sfree(ai->vedge);
+    sfree(ai->hedge);
+    sfree(ai);
 }
 
-static char *validate_seed(game_params *params, char *seed)
+static char *validate_desc(game_params *params, char *desc)
 {
     int area = params->w * params->h;
     int squares = 0;
 
-    while (*seed) {
-        int n = *seed++;
+    while (*desc) {
+        int n = *desc++;
         if (n >= 'a' && n <= 'z') {
             squares += n - 'a' + 1;
         } else if (n == '_') {
             /* do nothing */;
         } else if (n > '0' && n <= '9') {
             squares++;
-            while (*seed >= '0' && *seed <= '9')
-                seed++;
+            while (*desc >= '0' && *desc <= '9')
+                desc++;
         } else
-            return "Invalid character in game specification";
+            return "Invalid character in game description";
     }
 
     if (squares < area)
@@ -926,7 +962,7 @@ static char *validate_seed(game_params *params, char *seed)
     return NULL;
 }
 
-static game_state *new_game(game_params *params, char *seed)
+static game_state *new_game(game_params *params, char *desc)
 {
     game_state *state = snew(game_state);
     int x, y, i, area;
@@ -939,11 +975,11 @@ static game_state *new_game(game_params *params, char *seed)
     state->grid = snewn(area, int);
     state->vedge = snewn(area, unsigned char);
     state->hedge = snewn(area, unsigned char);
-    state->completed = FALSE;
+    state->completed = state->cheated = FALSE;
 
     i = 0;
-    while (*seed) {
-        int n = *seed++;
+    while (*desc) {
+        int n = *desc++;
         if (n >= 'a' && n <= 'z') {
             int run = n - 'a' + 1;
             assert(i + run <= area);
@@ -953,9 +989,9 @@ static game_state *new_game(game_params *params, char *seed)
             /* do nothing */;
         } else if (n > '0' && n <= '9') {
             assert(i < area);
-            state->grid[i++] = atoi(seed-1);
-            while (*seed >= '0' && *seed <= '9')
-                seed++;
+            state->grid[i++] = atoi(desc-1);
+            while (*desc >= '0' && *desc <= '9')
+                desc++;
         } else {
             assert(!"We can't get here");
         }
@@ -981,6 +1017,7 @@ static game_state *dup_game(game_state *state)
     ret->grid = snewn(state->w * state->h, int);
 
     ret->completed = state->completed;
+    ret->cheated = state->cheated;
 
     memcpy(ret->grid, state->grid, state->w * state->h * sizeof(int));
     memcpy(ret->vedge, state->vedge, state->w*state->h*sizeof(unsigned char));
@@ -997,6 +1034,27 @@ static void free_game(game_state *state)
     sfree(state);
 }
 
+static game_state *solve_game(game_state *state, game_aux_info *ai,
+                             char **error)
+{
+    game_state *ret;
+
+    if (!ai) {
+       *error = "Solution not known for this puzzle";
+       return NULL;
+    }
+
+    assert(state->w == ai->w);
+    assert(state->h == ai->h);
+
+    ret = dup_game(state);
+    memcpy(ret->vedge, ai->vedge, ai->w * ai->h * sizeof(unsigned char));
+    memcpy(ret->hedge, ai->hedge, ai->w * ai->h * sizeof(unsigned char));
+    ret->cheated = TRUE;
+
+    return ret;
+}
+
 static char *game_text_format(game_state *state)
 {
     char *ret, *p, buf[80];
@@ -1020,7 +1078,7 @@ static char *game_text_format(game_state *state)
      */
     maxlen = (2*state->h+1) * (state->w * (col+1) + 2);
 
-    ret = snewn(maxlen, char);
+    ret = snewn(maxlen+1, char);
     p = ret;
 
     for (y = 0; y <= 2*state->h; y++) {
@@ -1678,7 +1736,8 @@ static float game_anim_length(game_state *oldstate,
 static float game_flash_length(game_state *oldstate,
                               game_state *newstate, int dir)
 {
-    if (!oldstate->completed && newstate->completed)
+    if (!oldstate->completed && newstate->completed &&
+       !oldstate->cheated && !newstate->cheated)
         return FLASH_TIME;
     return 0.0F;
 }
@@ -1702,11 +1761,13 @@ const struct game thegame = {
     dup_params,
     TRUE, game_configure, custom_params,
     validate_params,
-    new_game_seed,
-    validate_seed,
+    new_game_desc,
+    game_free_aux_info,
+    validate_desc,
     new_game,
     dup_game,
     free_game,
+    TRUE, solve_game,
     TRUE, game_text_format,
     new_ui,
     free_ui,