Arrgh! Revert r9395,r9396,r9397,r9398, all of which I just committed
[sgt/puzzles] / pattern.c
index 808b0a8..043c1de 100644 (file)
--- a/pattern.c
+++ b/pattern.c
@@ -18,6 +18,7 @@ enum {
     COL_TEXT,
     COL_UNKNOWN,
     COL_GRID,
+    COL_CURSOR,
     NCOLOURS
 };
 
@@ -338,6 +339,10 @@ static int compute_rowdata(int *ret, unsigned char *start, int len, int step)
 #define DOT 2
 #define STILL_UNKNOWN 3
 
+#ifdef STANDALONE_SOLVER
+int verbose = FALSE;
+#endif
+
 static void do_recurse(unsigned char *known, unsigned char *deduced,
                        unsigned char *row, int *data, int len,
                        int freespace, int ndone, int lowest)
@@ -366,7 +371,11 @@ static void do_recurse(unsigned char *known, unsigned char *deduced,
 
 static int do_row(unsigned char *known, unsigned char *deduced,
                   unsigned char *row,
-                  unsigned char *start, int len, int step, int *data)
+                  unsigned char *start, int len, int step, int *data
+#ifdef STANDALONE_SOLVER
+                 , const char *rowcol, int index, int cluewid
+#endif
+                 )
 {
     int rowlen, i, freespace, done_any;
 
@@ -386,6 +395,27 @@ static int do_row(unsigned char *known, unsigned char *deduced,
            start[i*step] = deduced[i];
            done_any = TRUE;
        }
+#ifdef STANDALONE_SOLVER
+    if (verbose && done_any) {
+       char buf[80];
+       int thiscluewid;
+       printf("%s %2d: [", rowcol, index);
+       for (thiscluewid = -1, i = 0; data[i]; i++)
+           thiscluewid += sprintf(buf, " %d", data[i]);
+       printf("%*s", cluewid - thiscluewid, "");
+       for (i = 0; data[i]; i++)
+           printf(" %d", data[i]);
+       printf(" ] ");
+       for (i = 0; i < len; i++)
+           putchar(known[i] == BLOCK ? '#' :
+                   known[i] == DOT ? '.' : '?');
+       printf(" -> ");
+       for (i = 0; i < len; i++)
+           putchar(start[i*step] == BLOCK ? '#' :
+                   start[i*step] == DOT ? '.' : '?');
+       putchar('\n');
+    }
+#endif
     return done_any;
 }
 
@@ -443,12 +473,20 @@ static unsigned char *generate_soluble(random_state *rs, int w, int h)
             for (i=0; i<h; i++) {
                 rowdata[compute_rowdata(rowdata, grid+i*w, w, 1)] = 0;
                 done_any |= do_row(workspace, workspace+max, workspace+2*max,
-                                   matrix+i*w, w, 1, rowdata);
+                                   matrix+i*w, w, 1, rowdata
+#ifdef STANDALONE_SOLVER
+                                  , NULL, 0, 0 /* never do diagnostics here */
+#endif
+                                  );
             }
             for (i=0; i<w; i++) {
                 rowdata[compute_rowdata(rowdata, grid+i, h, w)] = 0;
                 done_any |= do_row(workspace, workspace+max, workspace+2*max,
-                                   matrix+i, h, w, rowdata);
+                                   matrix+i, h, w, rowdata
+#ifdef STANDALONE_SOLVER
+                                  , NULL, 0, 0 /* never do diagnostics here */
+#endif
+                                  );
             }
         } while (done_any);
 
@@ -568,7 +606,7 @@ static char *validate_desc(game_params *params, char *desc)
         if (*desc && isdigit((unsigned char)*desc)) {
             do {
                 p = desc;
-                while (desc && isdigit((unsigned char)*desc)) desc++;
+                while (*desc && isdigit((unsigned char)*desc)) desc++;
                 n = atoi(p);
                 rowspace -= n+1;
 
@@ -619,7 +657,7 @@ static game_state *new_game(midend *me, game_params *params, char *desc)
         if (*desc && isdigit((unsigned char)*desc)) {
             do {
                 p = desc;
-                while (desc && isdigit((unsigned char)*desc)) desc++;
+                while (*desc && isdigit((unsigned char)*desc)) desc++;
                 state->rowdata[state->rowsize * i + state->rowlen[i]++] =
                     atoi(p);
             } while (*desc++ == '.');
@@ -694,13 +732,21 @@ static char *solve_game(game_state *state, game_state *currstate,
                    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);
+                               matrix+i*w, w, 1, rowdata
+#ifdef STANDALONE_SOLVER
+                              , NULL, 0, 0 /* never do diagnostics here */
+#endif
+                              );
         }
         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);
+                               matrix+i, h, w, rowdata
+#ifdef STANDALONE_SOLVER
+                              , NULL, 0, 0 /* never do diagnostics here */
+#endif
+                              );
         }
     } while (done_any);
 
@@ -728,6 +774,11 @@ static char *solve_game(game_state *state, game_state *currstate,
     return ret;
 }
 
+static int game_can_format_as_text_now(game_params *params)
+{
+    return TRUE;
+}
+
 static char *game_text_format(game_state *state)
 {
     return NULL;
@@ -740,6 +791,7 @@ struct game_ui {
     int drag_end_x;
     int drag_end_y;
     int drag, release, state;
+    int cur_x, cur_y, cur_visible;
 };
 
 static game_ui *new_ui(game_state *state)
@@ -748,6 +800,7 @@ static game_ui *new_ui(game_state *state)
 
     ret = snew(game_ui);
     ret->dragging = FALSE;
+    ret->cur_x = ret->cur_y = ret->cur_visible = 0;
 
     return ret;
 }
@@ -776,6 +829,7 @@ struct game_drawstate {
     int w, h;
     int tilesize;
     unsigned char *visible;
+    int cur_x, cur_y;
 };
 
 static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
@@ -789,17 +843,28 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
     if (x >= 0 && x < state->w && y >= 0 && y < state->h &&
         (button == LEFT_BUTTON || button == RIGHT_BUTTON ||
          button == MIDDLE_BUTTON)) {
+#ifdef STYLUS_BASED
+        int currstate = state->grid[y * state->w + x];
+#endif
 
         ui->dragging = TRUE;
 
         if (button == LEFT_BUTTON) {
             ui->drag = LEFT_DRAG;
             ui->release = LEFT_RELEASE;
+#ifdef STYLUS_BASED
+            ui->state = (currstate + 2) % 3; /* FULL -> EMPTY -> UNKNOWN */
+#else
             ui->state = GRID_FULL;
+#endif
         } else if (button == RIGHT_BUTTON) {
             ui->drag = RIGHT_DRAG;
             ui->release = RIGHT_RELEASE;
+#ifdef STYLUS_BASED
+            ui->state = (currstate + 1) % 3; /* EMPTY -> FULL -> UNKNOWN */
+#else
             ui->state = GRID_EMPTY;
+#endif
         } else /* if (button == MIDDLE_BUTTON) */ {
             ui->drag = MIDDLE_DRAG;
             ui->release = MIDDLE_RELEASE;
@@ -808,6 +873,7 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
 
         ui->drag_start_x = ui->drag_end_x = x;
         ui->drag_start_y = ui->drag_end_y = y;
+        ui->cur_visible = 0;
 
         return "";                    /* UI activity occurred */
     }
@@ -868,6 +934,35 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
             return "";                /* UI activity occurred */
     }
 
+    if (IS_CURSOR_MOVE(button)) {
+        move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, 0);
+        ui->cur_visible = 1;
+        return "";
+    }
+    if (IS_CURSOR_SELECT(button)) {
+        int currstate = state->grid[ui->cur_y * state->w + ui->cur_x];
+        int newstate;
+        char buf[80];
+
+        if (!ui->cur_visible) {
+            ui->cur_visible = 1;
+            return "";
+        }
+
+        if (button == CURSOR_SELECT2)
+            newstate = currstate == GRID_UNKNOWN ? GRID_EMPTY :
+                currstate == GRID_EMPTY ? GRID_FULL : GRID_UNKNOWN;
+        else
+            newstate = currstate == GRID_UNKNOWN ? GRID_FULL :
+                currstate == GRID_FULL ? GRID_EMPTY : GRID_UNKNOWN;
+
+        sprintf(buf, "%c%d,%d,%d,%d",
+                (char)(newstate == GRID_FULL ? 'F' :
+                      newstate == GRID_EMPTY ? 'E' : 'U'),
+                ui->cur_x, ui->cur_y, 1, 1);
+        return dupstr(buf);
+    }
+
     return NULL;
 }
 
@@ -963,31 +1058,23 @@ static void game_set_size(drawing *dr, game_drawstate *ds,
     ds->tilesize = tilesize;
 }
 
-static float *game_colours(frontend *fe, game_state *state, int *ncolours)
+static float *game_colours(frontend *fe, int *ncolours)
 {
     float *ret = snewn(3 * NCOLOURS, float);
+    int i;
 
     frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
 
-    ret[COL_GRID * 3 + 0] = 0.3F;
-    ret[COL_GRID * 3 + 1] = 0.3F;
-    ret[COL_GRID * 3 + 2] = 0.3F;
-
-    ret[COL_UNKNOWN * 3 + 0] = 0.5F;
-    ret[COL_UNKNOWN * 3 + 1] = 0.5F;
-    ret[COL_UNKNOWN * 3 + 2] = 0.5F;
-
-    ret[COL_TEXT * 3 + 0] = 0.0F;
-    ret[COL_TEXT * 3 + 1] = 0.0F;
-    ret[COL_TEXT * 3 + 2] = 0.0F;
-
-    ret[COL_FULL * 3 + 0] = 0.0F;
-    ret[COL_FULL * 3 + 1] = 0.0F;
-    ret[COL_FULL * 3 + 2] = 0.0F;
-
-    ret[COL_EMPTY * 3 + 0] = 1.0F;
-    ret[COL_EMPTY * 3 + 1] = 1.0F;
-    ret[COL_EMPTY * 3 + 2] = 1.0F;
+    for (i = 0; i < 3; i++) {
+        ret[COL_GRID    * 3 + i] = 0.3F;
+        ret[COL_UNKNOWN * 3 + i] = 0.5F;
+        ret[COL_TEXT    * 3 + i] = 0.0F;
+        ret[COL_FULL    * 3 + i] = 0.0F;
+        ret[COL_EMPTY   * 3 + i] = 1.0F;
+    }
+    ret[COL_CURSOR * 3 + 0] = 1.0F;
+    ret[COL_CURSOR * 3 + 1] = 0.25F;
+    ret[COL_CURSOR * 3 + 2] = 0.25F;
 
     *ncolours = NCOLOURS;
     return ret;
@@ -1003,6 +1090,7 @@ static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
     ds->visible = snewn(ds->w * ds->h, unsigned char);
     ds->tilesize = 0;                  /* not decided yet */
     memset(ds->visible, 255, ds->w * ds->h);
+    ds->cur_x = ds->cur_y = 0;
 
     return ds;
 }
@@ -1014,9 +1102,9 @@ static void game_free_drawstate(drawing *dr, game_drawstate *ds)
 }
 
 static void grid_square(drawing *dr, game_drawstate *ds,
-                        int y, int x, int state)
+                        int y, int x, int state, int cur)
 {
-    int xl, xr, yt, yb;
+    int xl, xr, yt, yb, dx, dy, dw, dh;
 
     draw_rect(dr, TOCOORD(ds->w, x), TOCOORD(ds->h, y),
               TILE_SIZE, TILE_SIZE, COL_GRID);
@@ -1026,10 +1114,18 @@ static void grid_square(drawing *dr, game_drawstate *ds,
     xr = (x % 5 == 4 || x == ds->w-1 ? 1 : 0);
     yb = (y % 5 == 4 || y == ds->h-1 ? 1 : 0);
 
-    draw_rect(dr, TOCOORD(ds->w, x) + 1 + xl, TOCOORD(ds->h, y) + 1 + yt,
-              TILE_SIZE - xl - xr - 1, TILE_SIZE - yt - yb - 1,
+    dx = TOCOORD(ds->w, x) + 1 + xl;
+    dy = TOCOORD(ds->h, y) + 1 + yt;
+    dw = TILE_SIZE - xl - xr - 1;
+    dh = TILE_SIZE - yt - yb - 1;
+
+    draw_rect(dr, dx, dy, dw, dh,
               (state == GRID_FULL ? COL_FULL :
                state == GRID_EMPTY ? COL_EMPTY : COL_UNKNOWN));
+    if (cur) {
+        draw_rect_outline(dr, dx, dy, dw, dh, COL_CURSOR);
+        draw_rect_outline(dr, dx+1, dy+1, dw-2, dh-2, COL_CURSOR);
+    }
 
     draw_update(dr, TOCOORD(ds->w, x), TOCOORD(ds->h, y),
                 TILE_SIZE, TILE_SIZE);
@@ -1084,6 +1180,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
 {
     int i, j;
     int x1, x2, y1, y2;
+    int cx, cy, cmoved;
 
     if (!ds->started) {
         /*
@@ -1120,13 +1217,20 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
         x1 = x2 = y1 = y2 = -1;        /* placate gcc warnings */
     }
 
+    if (ui->cur_visible) {
+        cx = ui->cur_x; cy = ui->cur_y;
+    } else {
+        cx = cy = -1;
+    }
+    cmoved = (cx != ds->cur_x || cy != ds->cur_y);
+
     /*
      * Now draw any grid squares which have changed since last
      * redraw.
      */
     for (i = 0; i < ds->h; i++) {
         for (j = 0; j < ds->w; j++) {
-            int val;
+            int val, cc = 0;
 
             /*
              * Work out what state this square should be drawn in,
@@ -1137,6 +1241,13 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
             else
                 val = state->grid[i * state->w + j];
 
+            if (cmoved) {
+                /* the cursor has moved; if we were the old or
+                 * the new cursor position we need to redraw. */
+                if (j == cx && i == cy) cc = 1;
+                if (j == ds->cur_x && i == ds->cur_y) cc = 1;
+            }
+
             /*
              * Briefly invert everything twice during a completion
              * flash.
@@ -1146,12 +1257,14 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
                 val != GRID_UNKNOWN)
                 val = (GRID_FULL ^ GRID_EMPTY) ^ val;
 
-            if (ds->visible[i * ds->w + j] != val) {
-                grid_square(dr, ds, i, j, val);
+            if (ds->visible[i * ds->w + j] != val || cc) {
+                grid_square(dr, ds, i, j, val,
+                            (j == cx && i == cy));
                 ds->visible[i * ds->w + j] = val;
             }
         }
     }
+    ds->cur_x = cx; ds->cur_y = cy;
 }
 
 static float game_anim_length(game_state *oldstate,
@@ -1169,9 +1282,9 @@ static float game_flash_length(game_state *oldstate,
     return 0.0F;
 }
 
-static int game_wants_statusbar(void)
+static int game_status(game_state *state)
 {
-    return FALSE;
+    return state->completed ? +1 : 0;
 }
 
 static int game_timing_state(game_state *state, game_ui *ui)
@@ -1187,8 +1300,8 @@ static void game_print_size(game_params *params, float *x, float *y)
      * I'll use 5mm squares by default.
      */
     game_compute_size(params, 500, &pw, &ph);
-    *x = pw / 100.0;
-    *y = ph / 100.0;
+    *x = pw / 100.0F;
+    *y = ph / 100.0F;
 }
 
 static void game_print(drawing *dr, game_state *state, int tilesize)
@@ -1199,7 +1312,7 @@ static void game_print(drawing *dr, game_state *state, int tilesize)
 
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     game_drawstate ads, *ds = &ads;
-    ads.tilesize = tilesize;
+    game_set_size(dr, ds, NULL, tilesize);
 
     /*
      * Border.
@@ -1248,7 +1361,7 @@ static void game_print(drawing *dr, game_state *state, int tilesize)
 #endif
 
 const struct game thegame = {
-    "Pattern", "games.pattern",
+    "Pattern", "games.pattern", "pattern",
     default_params,
     game_fetch_preset,
     decode_params,
@@ -1263,7 +1376,7 @@ const struct game thegame = {
     dup_game,
     free_game,
     TRUE, solve_game,
-    FALSE, game_text_format,
+    FALSE, game_can_format_as_text_now, game_text_format,
     new_ui,
     free_ui,
     encode_ui,
@@ -1278,10 +1391,11 @@ const struct game thegame = {
     game_redraw,
     game_anim_length,
     game_flash_length,
+    game_status,
     TRUE, FALSE, game_print_size, game_print,
-    game_wants_statusbar,
+    FALSE,                            /* wants_statusbar */
     FALSE, game_timing_state,
-    0,                                /* mouse_priorities */
+    REQUIRE_RBUTTON,                  /* flags */
 };
 
 #ifdef STANDALONE_SOLVER
@@ -1295,8 +1409,12 @@ int main(int argc, char **argv)
     while (--argc > 0) {
         char *p = *++argv;
        if (*p == '-') {
-            fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
-            return 1;
+           if (!strcmp(p, "-v")) {
+               verbose = TRUE;
+           } else {
+               fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
+               return 1;
+           }
         } else {
             id = p;
         }
@@ -1324,7 +1442,7 @@ int main(int argc, char **argv)
     s = new_game(NULL, p, desc);
 
     {
-       int w = p->w, h = p->h, i, j, done_any, max;
+       int w = p->w, h = p->h, i, j, done_any, max, cluewid = 0;
        unsigned char *matrix, *workspace;
        int *rowdata;
 
@@ -1335,6 +1453,22 @@ int main(int argc, char **argv)
 
         memset(matrix, 0, w*h);
 
+       if (verbose) {
+           int thiswid;
+           /*
+            * Work out the maximum text width of the clue numbers
+            * in a row or column, so we can print the solver's
+            * working in a nicely lined up way.
+            */
+           for (i = 0; i < (w+h); i++) {
+               char buf[80];
+               for (thiswid = -1, j = 0; j < s->rowlen[i]; j++)
+                   thiswid += sprintf(buf, " %d", s->rowdata[s->rowsize*i+j]);
+               if (cluewid < thiswid)
+                   cluewid = thiswid;
+           }
+       }
+
         do {
             done_any = 0;
             for (i=0; i<h; i++) {
@@ -1342,13 +1476,21 @@ int main(int argc, char **argv)
                       max*sizeof(int));
                rowdata[s->rowlen[w+i]] = 0;
                 done_any |= do_row(workspace, workspace+max, workspace+2*max,
-                                   matrix+i*w, w, 1, rowdata);
+                                   matrix+i*w, w, 1, rowdata
+#ifdef STANDALONE_SOLVER
+                                  , "row", i+1, cluewid
+#endif
+                                  );
             }
             for (i=0; i<w; i++) {
                memcpy(rowdata, s->rowdata + s->rowsize*i, max*sizeof(int));
                rowdata[s->rowlen[i]] = 0;
                 done_any |= do_row(workspace, workspace+max, workspace+2*max,
-                                   matrix+i, h, w, rowdata);
+                                   matrix+i, h, w, rowdata
+#ifdef STANDALONE_SOLVER
+                                  , "col", i+1, cluewid
+#endif
+                                  );
             }
         } while (done_any);
 
@@ -1368,3 +1510,5 @@ int main(int argc, char **argv)
 }
 
 #endif
+
+/* vim: set shiftwidth=4 tabstop=8: */