Fix a couple of robustness issues.
[sgt/puzzles] / mines.c
diff --git a/mines.c b/mines.c
index 881cad0..62af8cb 100644 (file)
--- a/mines.c
+++ b/mines.c
@@ -71,7 +71,7 @@ struct mine_layout {
 struct game_state {
     int w, h, n, dead, won;
     struct mine_layout *layout;               /* real mine positions */
-    char *grid;                               /* player knowledge */
+    signed char *grid;                        /* player knowledge */
     /*
      * Each item in the `grid' array is one of the following values:
      * 
@@ -255,6 +255,8 @@ static char *validate_params(game_params *params)
        return "Width must be greater than zero";
     if (params->h <= 0)
        return "Height must be greater than zero";
+    if (params->n > params->w * params->h - 9)
+       return "Too many mines for grid size";
 
     /*
      * FIXME: Need more constraints here. Not sure what the
@@ -558,7 +560,8 @@ static void std_add(struct squaretodo *std, int i)
     std->next[i] = -1;
 }
 
-static void known_squares(int w, int h, struct squaretodo *std, char *grid,
+static void known_squares(int w, int h, struct squaretodo *std,
+                         signed char *grid,
                          int (*open)(void *ctx, int x, int y), void *openctx,
                          int x, int y, int mask, int mine)
 {
@@ -625,9 +628,10 @@ struct perturbations {
  *    steps were required; the exact return value is the number of
  *    perturb calls.
  */
-static int minesolve(int w, int h, int n, char *grid,
+static int minesolve(int w, int h, int n, signed char *grid,
                     int (*open)(void *ctx, int x, int y),
-                    struct perturbations *(*perturb)(void *ctx, char *grid,
+                    struct perturbations *(*perturb)(void *ctx,
+                                                     signed char *grid,
                                                      int x, int y, int mask),
                     void *ctx, random_state *rs)
 {
@@ -1276,7 +1280,7 @@ static int minesolve(int w, int h, int n, char *grid,
  */
 
 struct minectx {
-    char *grid;
+    signed char *grid;
     int w, h;
     int sx, sy;
     random_state *rs;
@@ -1335,7 +1339,7 @@ static int squarecmp(const void *av, const void *bv)
     return 0;
 }
 
-static struct perturbations *mineperturb(void *vctx, char *grid,
+static struct perturbations *mineperturb(void *vctx, signed char *grid,
                                         int setx, int sety, int mask)
 {
     struct minectx *ctx = (struct minectx *)vctx;
@@ -1655,7 +1659,7 @@ static char *minegen(int w, int h, int n, int x, int y, int unique,
         * We bypass this bit if we're not after a unique grid.
          */
        if (unique) {
-           char *solvegrid = snewn(w*h, char);
+           signed char *solvegrid = snewn(w*h, char);
            struct minectx actx, *ctx = &actx;
            int solveret, prevret = -2;
 
@@ -1801,7 +1805,7 @@ static void obfuscate_bitmap(unsigned char *bmp, int bits, int decode)
 static char *new_mine_layout(int w, int h, int n, int x, int y, int unique,
                             random_state *rs, char **game_desc)
 {
-    char *grid, *ret, *p;
+    signed char *grid, *ret, *p;
     unsigned char *bmp;
     int i, area;
 
@@ -1845,24 +1849,30 @@ static char *new_mine_layout(int w, int h, int n, int x, int y, int unique,
 }
 
 static char *new_game_desc(game_params *params, random_state *rs,
-                          game_aux_info **aux)
+                          game_aux_info **aux, int interactive)
 {
-#ifdef PREOPENED
-    int x = random_upto(rs, params->w);
-    int y = random_upto(rs, params->h);
-    char *grid, *desc;
+    if (!interactive) {
+       /*
+        * For batch-generated grids, pre-open one square.
+        */
+       int x = random_upto(rs, params->w);
+       int y = random_upto(rs, params->h);
+       signed char *grid;
+       char *desc;
 
-    grid = new_mine_layout(params->w, params->h, params->n,
-                          x, y, params->unique, rs);
-#else
-    char *rsdesc, *desc;
+       grid = new_mine_layout(params->w, params->h, params->n,
+                              x, y, params->unique, rs, &desc);
+       sfree(grid);
+       return desc;
+    } else {
+       char *rsdesc, *desc;
 
-    rsdesc = random_state_encode(rs);
-    desc = snewn(strlen(rsdesc) + 100, char);
-    sprintf(desc, "r%d,%c,%s", params->n, params->unique ? 'u' : 'a', rsdesc);
-    sfree(rsdesc);
-    return desc;
-#endif
+       rsdesc = random_state_encode(rs);
+       desc = snewn(strlen(rsdesc) + 100, char);
+       sprintf(desc, "r%d,%c,%s", params->n, params->unique ? 'u' : 'a', rsdesc);
+       sfree(rsdesc);
+       return desc;
+    }
 }
 
 static void game_free_aux_info(game_aux_info *aux)
@@ -2079,6 +2089,8 @@ static game_state *new_game(midend_data *me, game_params *params, char *desc)
        state->layout->me = me;
 
     } else {
+       state->layout->rs = NULL;
+       state->layout->me = NULL;
 
        state->layout->mines = snewn(wh, char);
        x = atoi(desc);
@@ -2172,7 +2184,30 @@ static game_state *solve_game(game_state *state, game_aux_info *aux,
 
 static char *game_text_format(game_state *state)
 {
-    return NULL;
+    char *ret;
+    int x, y;
+
+    ret = snewn((state->w + 1) * state->h + 1, char);
+    for (y = 0; y < state->h; y++) {
+       for (x = 0; x < state->w; x++) {
+           int v = state->grid[y*state->w+x];
+           if (v == 0)
+               v = '-';
+           else if (v >= 1 && v <= 8)
+               v = '0' + v;
+           else if (v == -1)
+               v = '*';
+           else if (v == -2 || v == -3)
+               v = '?';
+           else if (v >= 64)
+               v = '!';
+           ret[y * (state->w+1) + x] = v;
+       }
+       ret[y * (state->w+1) + state->w] = '\n';
+    }
+    ret[(state->w + 1) * state->h] = '\0';
+
+    return ret;
 }
 
 struct game_ui {
@@ -2306,7 +2341,7 @@ static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
 
 struct game_drawstate {
     int w, h, started;
-    char *grid;
+    signed char *grid;
     /*
      * Items in this `grid' array have all the same values as in
      * the game_state grid, and in addition:
@@ -2726,7 +2761,7 @@ const struct game thegame = {
     dup_game,
     free_game,
     FALSE, solve_game,
-    FALSE, game_text_format,
+    TRUE, game_text_format,
     new_ui,
     free_ui,
     make_move,