chiark / gitweb /
Fix completion checking in Killer Solo.
[sgt-puzzles.git] / dominosa.c
index b0f11e11b8a81a31bbd4838de883e57c11e81b54..dc7c2c7439536984f00e0a1d3c5bc482200920bf 100644 (file)
@@ -64,6 +64,8 @@ enum {
     COL_DOMINOCLASH,
     COL_DOMINOTEXT,
     COL_EDGE,
+    COL_HIGHLIGHT_1,
+    COL_HIGHLIGHT_2,
     NCOLOURS
 };
 
@@ -944,16 +946,78 @@ static char *solve_game(const game_state *state, const game_state *currstate,
 
 static int game_can_format_as_text_now(const game_params *params)
 {
-    return TRUE;
+    return params->n < 1000;
+}
+
+static void draw_domino(char *board, int start, char corner,
+                       int dshort, int nshort, char cshort,
+                       int dlong, int nlong, char clong)
+{
+    int go_short = nshort*dshort, go_long = nlong*dlong, i;
+
+    board[start] = corner;
+    board[start + go_short] = corner;
+    board[start + go_long] = corner;
+    board[start + go_short + go_long] = corner;
+
+    for (i = 1; i < nshort; ++i) {
+       int j = start + i*dshort, k = start + i*dshort + go_long;
+       if (board[j] != corner) board[j] = cshort;
+       if (board[k] != corner) board[k] = cshort;
+    }
+
+    for (i = 1; i < nlong; ++i) {
+       int j = start + i*dlong, k = start + i*dlong + go_short;
+       if (board[j] != corner) board[j] = clong;
+       if (board[k] != corner) board[k] = clong;
+    }
 }
 
 static char *game_text_format(const game_state *state)
 {
-    return NULL;
+    int w = state->w, h = state->h, r, c;
+    int cw = 4, ch = 2, gw = cw*w + 2, gh = ch * h + 1, len = gw * gh;
+    char *board = snewn(len + 1, char);
+
+    memset(board, ' ', len);
+
+    for (r = 0; r < h; ++r) {
+       for (c = 0; c < w; ++c) {
+           int cell = r*ch*gw + cw*c, center = cell + gw*ch/2 + cw/2;
+           int i = r*w + c, num = state->numbers->numbers[i];
+
+           if (num < 100) {
+               board[center] = '0' + num % 10;
+               if (num >= 10) board[center - 1] = '0' + num / 10;
+           } else {
+               board[center+1] = '0' + num % 10;
+               board[center] = '0' + num / 10 % 10;
+               board[center-1] = '0' + num / 100;
+           }
+
+           if (state->edges[i] & EDGE_L) board[center - cw/2] = '|';
+           if (state->edges[i] & EDGE_R) board[center + cw/2] = '|';
+           if (state->edges[i] & EDGE_T) board[center - gw] = '-';
+           if (state->edges[i] & EDGE_B) board[center + gw] = '-';
+
+           if (state->grid[i] == i) continue; /* no domino pairing */
+           if (state->grid[i] < i) continue; /* already done */
+           assert (state->grid[i] == i + 1 || state->grid[i] == i + w);
+           if (state->grid[i] == i + 1)
+               draw_domino(board, cell, '+', gw, ch, '|', +1, 2*cw, '-');
+           else if (state->grid[i] == i + w)
+               draw_domino(board, cell, '+', +1, cw, '-', gw, 2*ch, '|');
+       }
+       board[r*ch*gw + gw - 1] = '\n';
+       board[r*ch*gw + gw + gw - 1] = '\n';
+    }
+    board[len - 1] = '\n';
+    board[len] = '\0';
+    return board;
 }
 
 struct game_ui {
-    int cur_x, cur_y, cur_visible;
+    int cur_x, cur_y, cur_visible, highlight_1, highlight_2;
 };
 
 static game_ui *new_ui(const game_state *state)
@@ -961,6 +1025,7 @@ static game_ui *new_ui(const game_state *state)
     game_ui *ui = snew(game_ui);
     ui->cur_x = ui->cur_y = 0;
     ui->cur_visible = 0;
+    ui->highlight_1 = ui->highlight_2 = -1;
     return ui;
 }
 
@@ -1072,6 +1137,22 @@ static char *interpret_move(const game_state *state, game_ui *ui,
 
         sprintf(buf, "%c%d,%d", (int)(button == CURSOR_SELECT2 ? 'E' : 'D'), d1, d2);
         return dupstr(buf);
+    } else if (isdigit(button)) {
+        int n = state->params.n, num = button - '0';
+        if (num > n) {
+            return NULL;
+        } else if (ui->highlight_1 == num) {
+            ui->highlight_1 = -1;
+        } else if (ui->highlight_2 == num) {
+            ui->highlight_2 = -1;
+        } else if (ui->highlight_1 == -1) {
+            ui->highlight_1 = num;
+        } else if (ui->highlight_2 == -1) {
+            ui->highlight_2 = num;
+        } else {
+            return NULL;
+        }
+        return "";
     }
 
     return NULL;
@@ -1277,6 +1358,14 @@ static float *game_colours(frontend *fe, int *ncolours)
     ret[COL_EDGE * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2 / 3;
     ret[COL_EDGE * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2 / 3;
 
+    ret[COL_HIGHLIGHT_1 * 3 + 0] = 0.85;
+    ret[COL_HIGHLIGHT_1 * 3 + 1] = 0.20;
+    ret[COL_HIGHLIGHT_1 * 3 + 2] = 0.20;
+
+    ret[COL_HIGHLIGHT_2 * 3 + 0] = 0.30;
+    ret[COL_HIGHLIGHT_2 * 3 + 1] = 0.85;
+    ret[COL_HIGHLIGHT_2 * 3 + 2] = 0.20;
+
     *ncolours = NCOLOURS;
     return ret;
 }
@@ -1317,6 +1406,8 @@ enum {
    * EDGE_*                     [0x100 -- 0xF00]
  * and must fit into an unsigned long (32 bits).
  */
+#define DF_HIGHLIGHT_1  0x10
+#define DF_HIGHLIGHT_2  0x20
 #define DF_FLASH        0x40
 #define DF_CLASH        0x80
 
@@ -1331,7 +1422,7 @@ enum {
 #define IS_EMPTY(s,x,y) ((s)->grid[(y)*(s)->w+(x)] == ((y)*(s)->w+(x)))
 
 static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state,
-                      int x, int y, int type)
+                      int x, int y, int type, int highlight_1, int highlight_2)
 {
     int w = state->w /*, h = state->h */;
     int cx = COORD(x), cy = COORD(y);
@@ -1427,6 +1518,12 @@ static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state,
            draw_rect_corners(dr, ox, oy, CURSOR_RADIUS+1, nc);
     }
 
+    if (flags & DF_HIGHLIGHT_1) {
+        nc = COL_HIGHLIGHT_1;
+    } else if (flags & DF_HIGHLIGHT_2) {
+        nc = COL_HIGHLIGHT_2;
+    }
+
     sprintf(str, "%d", state->numbers->numbers[y*w+x]);
     draw_text(dr, cx+TILESIZE/2, cy+TILESIZE/2, FONT_VARIABLE, TILESIZE/2,
               ALIGN_HCENTRE | ALIGN_VCENTRE, nc, str);
@@ -1489,8 +1586,8 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
             else
                 c = TYPE_BLANK;
 
+            n1 = state->numbers->numbers[n];
             if (c != TYPE_BLANK) {
-                n1 = state->numbers->numbers[n];
                 n2 = state->numbers->numbers[state->grid[n]];
                 di = DINDEX(n1, n2);
                 if (used[di] > 1)
@@ -1499,6 +1596,11 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
                 c |= state->edges[n];
             }
 
+            if (n1 == ui->highlight_1)
+                c |= DF_HIGHLIGHT_1;
+            if (n1 == ui->highlight_2)
+                c |= DF_HIGHLIGHT_2;
+
             if (flashtime != 0)
                 c |= DF_FLASH;             /* we're flashing */
 
@@ -1515,7 +1617,8 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
             }
 
            if (ds->visible[n] != c) {
-               draw_tile(dr, ds, state, x, y, c);
+               draw_tile(dr, ds, state, x, y, c,
+                          ui->highlight_1, ui->highlight_2);
                 ds->visible[n] = c;
            }
        }
@@ -1534,7 +1637,10 @@ static float game_flash_length(const game_state *oldstate,
 {
     if (!oldstate->completed && newstate->completed &&
        !oldstate->cheated && !newstate->cheated)
+    {
+        ui->highlight_1 = ui->highlight_2 = -1;
         return FLASH_TIME;
+    }
     return 0.0F;
 }
 
@@ -1592,7 +1698,7 @@ static void game_print(drawing *dr, const game_state *state, int tilesize)
             else
                 c = TYPE_BLANK;
 
-           draw_tile(dr, ds, state, x, y, c);
+           draw_tile(dr, ds, state, x, y, c, -1, -1);
        }
 }
 
@@ -1616,7 +1722,7 @@ const struct game thegame = {
     dup_game,
     free_game,
     TRUE, solve_game,
-    FALSE, game_can_format_as_text_now, game_text_format,
+    TRUE, game_can_format_as_text_now, game_text_format,
     new_ui,
     free_ui,
     encode_ui,