Enhancements to mkfiles.pl and Recipe to arrange for the auxiliary
[sgt/puzzles] / pattern.c
index c6e2cda..e9b6f98 100644 (file)
--- a/pattern.c
+++ b/pattern.c
@@ -30,7 +30,7 @@ enum {
         ( ((x) - (BORDER + GUTTER + TILE_SIZE * TLBORDER(d))) / TILE_SIZE )
 
 #define SIZE(d) (2*BORDER + GUTTER + TILE_SIZE * (TLBORDER(d) + (d)))
-#define GETTILESIZE(d, w) (w / (2 + TLBORDER(d) + (d)))
+#define GETTILESIZE(d, w) ((double)w / (2.0 + (double)TLBORDER(d) + (double)(d)))
 
 #define TOCOORD(d, x) (BORDER + GUTTER + TILE_SIZE * (TLBORDER(d) + (x)))
 
@@ -466,13 +466,8 @@ static unsigned char *generate_soluble(random_state *rs, int w, int h)
     return grid;
 }
 
-struct game_aux_info {
-    int w, h;
-    unsigned char *grid;
-};
-
 static char *new_game_desc(game_params *params, random_state *rs,
-                          game_aux_info **aux, int interactive)
+                          char **aux, int interactive)
 {
     unsigned char *grid;
     int i, j, max, rowlen, *rowdata;
@@ -484,14 +479,22 @@ static char *new_game_desc(game_params *params, random_state *rs,
     rowdata = snewn(max, int);
 
     /*
-     * Save the solved game in an aux_info.
+     * Save the solved game in aux.
      */
     {
-       game_aux_info *ai = snew(game_aux_info);
+       char *ai = snewn(params->w * params->h + 2, char);
+
+        /*
+         * String format is exactly the same as a solve move, so we
+         * can just dupstr this in solve_game().
+         */
+
+        ai[0] = 'S';
 
-       ai->w = params->w;
-       ai->h = params->h;
-        ai->grid = grid;
+        for (i = 0; i < params->w * params->h; i++)
+            ai[i+1] = grid[i] ? '1' : '0';
+
+        ai[params->w * params->h + 1] = '\0';
 
        *aux = ai;
     }
@@ -546,15 +549,10 @@ static char *new_game_desc(game_params *params, random_state *rs,
     assert(desc[desclen-1] == '/');
     desc[desclen-1] = '\0';
     sfree(rowdata);
+    sfree(grid);
     return desc;
 }
 
-static void game_free_aux_info(game_aux_info *aux)
-{
-    sfree(aux->grid);
-    sfree(aux);
-}
-
 static char *validate_desc(game_params *params, char *desc)
 {
     int i, n, rowspace;
@@ -665,81 +663,66 @@ static void free_game(game_state *state)
 }
 
 static char *solve_game(game_state *state, game_state *currstate,
-                       game_aux_info *ai, char **error)
+                       char *ai, char **error)
 {
     unsigned char *matrix;
-    int matrix_needs_freeing;
-    int full, empty;
     int w = state->w, h = state->h;
     int i;
     char *ret;
+    int done_any, max;
+    unsigned char *workspace;
+    int *rowdata;
 
     /*
-     * If we already have the solved state in an aux_info, copy it
-     * out.
+     * If we already have the solved state in ai, copy it out.
      */
-    if (ai) {
-       assert(ai->w == w && ai->h == h);
+    if (ai)
+        return dupstr(ai);
 
-       matrix = ai->grid;
-       matrix_needs_freeing = FALSE;
-       full = GRID_FULL;
-       empty = GRID_EMPTY;
-    } else {
-       int done_any, max;
-       unsigned char *workspace;
-       int *rowdata;
-
-       matrix = snewn(w*h, unsigned char);
-       max = max(w, h);
-       workspace = snewn(max*3, unsigned char);
-       rowdata = snewn(max+1, int);
-
-        memset(matrix, 0, w*h);
+    matrix = snewn(w*h, unsigned char);
+    max = max(w, h);
+    workspace = snewn(max*3, unsigned char);
+    rowdata = snewn(max+1, int);
 
-        do {
-            done_any = 0;
-            for (i=0; i<h; i++) {
-               memcpy(rowdata, state->rowdata + state->rowsize*(w+i),
-                      max*sizeof(int));
-               rowdata[state->rowlen[w+i]] = 0;
-                done_any |= do_row(workspace, workspace+max, workspace+2*max,
-                                   matrix+i*w, w, 1, rowdata);
-            }
-            for (i=0; i<w; i++) {
-               memcpy(rowdata, state->rowdata + state->rowsize*i, max*sizeof(int));
-               rowdata[state->rowlen[i]] = 0;
-                done_any |= do_row(workspace, workspace+max, workspace+2*max,
-                                   matrix+i, h, w, rowdata);
-            }
-        } while (done_any);
+    memset(matrix, 0, w*h);
 
-       sfree(workspace);
-       sfree(rowdata);
+    do {
+        done_any = 0;
+        for (i=0; i<h; i++) {
+            memcpy(rowdata, state->rowdata + state->rowsize*(w+i),
+                   max*sizeof(int));
+            rowdata[state->rowlen[w+i]] = 0;
+            done_any |= do_row(workspace, workspace+max, workspace+2*max,
+                               matrix+i*w, w, 1, rowdata);
+        }
+        for (i=0; i<w; i++) {
+            memcpy(rowdata, state->rowdata + state->rowsize*i, max*sizeof(int));
+            rowdata[state->rowlen[i]] = 0;
+            done_any |= do_row(workspace, workspace+max, workspace+2*max,
+                               matrix+i, h, w, rowdata);
+        }
+    } while (done_any);
 
-       for (i = 0; i < w*h; i++) {
-           if (matrix[i] != BLOCK && matrix[i] != DOT) {
-               sfree(matrix);
-               *error = "Solving algorithm cannot complete this puzzle";
-               return NULL;
-           }
-       }
+    sfree(workspace);
+    sfree(rowdata);
 
-       matrix_needs_freeing = TRUE;
-       full = BLOCK;
-       empty = DOT;
+    for (i = 0; i < w*h; i++) {
+        if (matrix[i] != BLOCK && matrix[i] != DOT) {
+            sfree(matrix);
+            *error = "Solving algorithm cannot complete this puzzle";
+            return NULL;
+        }
     }
 
     ret = snewn(w*h+2, char);
     ret[0] = 'S';
     for (i = 0; i < w*h; i++) {
-       assert(matrix[i] == full || matrix[i] == empty);
-       ret[i+1] = (matrix[i] == full ? '1' : '0');
+       assert(matrix[i] == BLOCK || matrix[i] == DOT);
+       ret[i+1] = (matrix[i] == BLOCK ? '1' : '0');
     }
     ret[w*h+1] = '\0';
 
-    if (matrix_needs_freeing)
-       sfree(matrix);
+    sfree(matrix);
 
     return ret;
 }
@@ -773,6 +756,15 @@ static void free_ui(game_ui *ui)
     sfree(ui);
 }
 
+static char *encode_ui(game_ui *ui)
+{
+    return NULL;
+}
+
+static void decode_ui(game_ui *ui, char *encoding)
+{
+}
+
 static void game_changed_state(game_ui *ui, game_state *oldstate,
                                game_state *newstate)
 {
@@ -867,8 +859,8 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
         if (move_needed) {
            char buf[80];
            sprintf(buf, "%c%d,%d,%d,%d",
-                   (ui->state == GRID_FULL ? 'F' :
-                    ui->state == GRID_EMPTY ? 'E' : 'U'),
+                   (char)(ui->state == GRID_FULL ? 'F' :
+                          ui->state == GRID_EMPTY ? 'E' : 'U'),
                    x1, y1, x2-x1+1, y2-y1+1);
            return dupstr(buf);
         } else
@@ -953,21 +945,23 @@ static game_state *execute_move(game_state *from, char *move)
  * Drawing routines.
  */
 
-static void game_size(game_params *params, game_drawstate *ds,
-                      int *x, int *y, int expand)
+static void game_compute_size(game_params *params, int tilesize,
+                             int *x, int *y)
 {
-    int ts;
-
-    ts = min(GETTILESIZE(params->w, *x), GETTILESIZE(params->h, *y));
-    if (expand)
-        ds->tilesize = ts;
-    else
-        ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
+    /* Ick: fake up `ds->tilesize' for macro expansion purposes */
+    struct { int tilesize; } ads, *ds = &ads;
+    ads.tilesize = tilesize;
 
     *x = SIZE(params->w);
     *y = SIZE(params->h);
 }
 
+static void game_set_size(game_drawstate *ds, game_params *params,
+                         int tilesize)
+{
+    ds->tilesize = tilesize;
+}
+
 static float *game_colours(frontend *fe, game_state *state, int *ncolours)
 {
     float *ret = snewn(3 * NCOLOURS, float);
@@ -1185,7 +1179,6 @@ const struct game thegame = {
     TRUE, game_configure, custom_params,
     validate_params,
     new_game_desc,
-    game_free_aux_info,
     validate_desc,
     new_game,
     dup_game,
@@ -1194,10 +1187,12 @@ const struct game thegame = {
     FALSE, game_text_format,
     new_ui,
     free_ui,
+    encode_ui,
+    decode_ui,
     game_changed_state,
     interpret_move,
     execute_move,
-    game_size,
+    PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
     game_colours,
     game_new_drawstate,
     game_free_drawstate,
@@ -1222,8 +1217,6 @@ void draw_text(frontend *fe, int x, int y, int fonttype, int fontsize,
                int align, int colour, char *text) {}
 void draw_rect(frontend *fe, int x, int y, int w, int h, int colour) {}
 void draw_line(frontend *fe, int x1, int y1, int x2, int y2, int colour) {}
-void draw_polygon(frontend *fe, int *coords, int npoints,
-                  int fill, int colour) {}
 void clip(frontend *fe, int x, int y, int w, int h) {}
 void unclip(frontend *fe) {}
 void start_draw(frontend *fe) {}
@@ -1250,15 +1243,12 @@ int main(int argc, char **argv)
 {
     game_params *p;
     game_state *s;
-    int recurse = TRUE;
     char *id = NULL, *desc, *err;
-    int y, x;
-    int grade = FALSE;
 
     while (--argc > 0) {
         char *p = *++argv;
        if (*p == '-') {
-            fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0]);
+            fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
             return 1;
         } else {
             id = p;