Fix outdated comment
[sgt/puzzles] / solo.c
diff --git a/solo.c b/solo.c
index 87f1e74..eb35e00 100644 (file)
--- a/solo.c
+++ b/solo.c
@@ -107,7 +107,7 @@ struct game_state {
     int c, r;
     digit *grid;
     unsigned char *immutable;         /* marks which digits are clues */
-    int completed;
+    int completed, cheated;
 };
 
 static game_params *default_params(void)
@@ -1116,7 +1116,7 @@ static int nsolve(int c, int r, digit *grid)
 #ifdef STANDALONE_SOLVER
                                           , "intersectional analysis,"
                                           " row %d vs block (%d,%d)",
-                                          1+YUNTRANS(y), 1+x, 1+y%r
+                                          1+YUNTRANS(y), 1+x/r, 1+y%r
 #endif
                                           ) ||
                          nsolve_intersect(usage, cubepos(x,y%r,n), r*cr,
@@ -1124,7 +1124,7 @@ static int nsolve(int c, int r, digit *grid)
 #ifdef STANDALONE_SOLVER
                                           , "intersectional analysis,"
                                           " block (%d,%d) vs row %d",
-                                          1+x, 1+y%r, 1+YUNTRANS(y)
+                                          1+x/r, 1+y%r, 1+YUNTRANS(y)
 #endif
                                           ))) {
                         diff = max(diff, DIFF_INTERSECT);
@@ -1351,7 +1351,13 @@ static int symmetries(game_params *params, int x, int y, int *output, int s)
     return i;
 }
 
-static char *new_game_seed(game_params *params, random_state *rs)
+struct game_aux_info {
+    int c, r;
+    digit *grid;
+};
+
+static char *new_game_seed(game_params *params, random_state *rs,
+                          game_aux_info **aux)
 {
     int c = params->c, r = params->r, cr = c*r;
     int area = cr*cr;
@@ -1393,6 +1399,18 @@ static char *new_game_seed(game_params *params, random_state *rs)
         assert(ret == 1);
         assert(check_valid(c, r, grid));
 
+       /*
+        * Save the solved grid in the aux_info.
+        */
+       {
+           game_aux_info *ai = snew(game_aux_info);
+           ai->c = c;
+           ai->r = r;
+           ai->grid = snewn(cr * cr, digit);
+           memcpy(ai->grid, grid, cr * cr * sizeof(digit));
+           *aux = ai;
+       }
+
         /*
          * Now we have a solved grid, start removing things from it
          * while preserving solubility.
@@ -1513,6 +1531,12 @@ static char *new_game_seed(game_params *params, random_state *rs)
     return seed;
 }
 
+static void game_free_aux_info(game_aux_info *aux)
+{
+    sfree(aux->grid);
+    sfree(aux);
+}
+
 static char *validate_seed(game_params *params, char *seed)
 {
     int area = params->r * params->r * params->c * params->c;
@@ -1554,7 +1578,7 @@ static game_state *new_game(game_params *params, char *seed)
     state->immutable = snewn(area, unsigned char);
     memset(state->immutable, FALSE, area);
 
-    state->completed = FALSE;
+    state->completed = state->cheated = FALSE;
 
     i = 0;
     while (*seed) {
@@ -1596,6 +1620,7 @@ static game_state *dup_game(game_state *state)
     memcpy(ret->immutable, state->immutable, area);
 
     ret->completed = state->completed;
+    ret->cheated = state->cheated;
 
     return ret;
 }
@@ -1607,6 +1632,104 @@ 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;
+    int c = state->c, r = state->r, cr = c*r;
+    int rsolve_ret;
+
+    ret = dup_game(state);
+    ret->completed = ret->cheated = TRUE;
+
+    /*
+     * If we already have the solution in the aux_info, save
+     * ourselves some time.
+     */
+    if (ai) {
+
+       assert(c == ai->c);
+       assert(r == ai->r);
+       memcpy(ret->grid, ai->grid, cr * cr * sizeof(digit));
+
+    } else {
+       rsolve_ret = rsolve(c, r, ret->grid, NULL, 2);
+
+       if (rsolve_ret != 1) {
+           free_game(ret);
+           if (rsolve_ret == 0)
+               *error = "No solution exists for this puzzle";
+           else
+               *error = "Multiple solutions exist for this puzzle";
+           return NULL;
+       }
+    }
+
+    return ret;
+}
+
+static char *grid_text_format(int c, int r, digit *grid)
+{
+    int cr = c*r;
+    int x, y;
+    int maxlen;
+    char *ret, *p;
+
+    /*
+     * There are cr lines of digits, plus r-1 lines of block
+     * separators. Each line contains cr digits, cr-1 separating
+     * spaces, and c-1 two-character block separators. Thus, the
+     * total length of a line is 2*cr+2*c-3 (not counting the
+     * newline), and there are cr+r-1 of them.
+     */
+    maxlen = (cr+r-1) * (2*cr+2*c-2);
+    ret = snewn(maxlen+1, char);
+    p = ret;
+
+    for (y = 0; y < cr; y++) {
+        for (x = 0; x < cr; x++) {
+            int ch = grid[y * cr + x];
+            if (ch == 0)
+                ch = ' ';
+            else if (ch <= 9)
+                ch = '0' + ch;
+            else
+                ch = 'a' + ch-10;
+            *p++ = ch;
+            if (x+1 < cr) {
+               *p++ = ' ';
+                if ((x+1) % r == 0) {
+                    *p++ = '|';
+                   *p++ = ' ';
+               }
+            }
+        }
+       *p++ = '\n';
+        if (y+1 < cr && (y+1) % c == 0) {
+            for (x = 0; x < cr; x++) {
+                *p++ = '-';
+                if (x+1 < cr) {
+                   *p++ = '-';
+                    if ((x+1) % r == 0) {
+                       *p++ = '+';
+                       *p++ = '-';
+                   }
+                }
+            }
+           *p++ = '\n';
+        }
+    }
+
+    assert(p - ret == maxlen);
+    *p = '\0';
+    return ret;
+}
+
+static char *game_text_format(game_state *state)
+{
+    return grid_text_format(state->c, state->r, state->grid);
+}
+
 struct game_ui {
     /*
      * These are the coordinates of the currently highlighted
@@ -1872,7 +1995,8 @@ static float game_anim_length(game_state *oldstate, game_state *newstate,
 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;
 }
@@ -1887,21 +2011,23 @@ static int game_wants_statusbar(void)
 #endif
 
 const struct game thegame = {
-    "Solo", "games.solo", TRUE,
+    "Solo", "games.solo",
     default_params,
     game_fetch_preset,
     decode_params,
     encode_params,
     free_params,
     dup_params,
-    game_configure,
-    custom_params,
+    TRUE, game_configure, custom_params,
     validate_params,
     new_game_seed,
+    game_free_aux_info,
     validate_seed,
     new_game,
     dup_game,
     free_game,
+    TRUE, solve_game,
+    TRUE, game_text_format,
     new_ui,
     free_ui,
     make_move,
@@ -2035,38 +2161,7 @@ int main(int argc, char **argv)
         }
     }
 
-    for (y = 0; y < p->c * p->r; y++) {
-        for (x = 0; x < p->c * p->r; x++) {
-            int c = s->grid[y * p->c * p->r + x];
-            if (c == 0)
-                c = ' ';
-            else if (c <= 9)
-                c = '0' + c;
-            else
-                c = 'a' + c-10;
-            printf("%c", c);
-            if (x+1 < p->c * p->r) {
-                if ((x+1) % p->r)
-                    printf(" ");
-                else
-                    printf(" | ");
-            }
-        }
-        printf("\n");
-        if (y+1 < p->c * p->r && (y+1) % p->c == 0) {
-            for (x = 0; x < p->c * p->r; x++) {
-                printf("-");
-                if (x+1 < p->c * p->r) {
-                    if ((x+1) % p->r)
-                        printf("-");
-                    else
-                        printf("-+-");
-                }
-            }
-            printf("\n");
-        }
-    }
-    printf("\n");
+    printf("%s\n", grid_text_format(p->c, p->r, s->grid));
 
     return 0;
 }