chiark / gitweb /
Fix completion checking in Killer Solo.
[sgt-puzzles.git] / singles.c
index 319ab11f8700476763d76b9d2e80394557ee350a..a9b1d9d3b3005de5c5d487a04d980a8f3ec3817b 100644 (file)
--- a/singles.c
+++ b/singles.c
@@ -170,7 +170,7 @@ static void free_params(game_params *params)
     sfree(params);
 }
 
-static game_params *dup_params(game_params *params)
+static game_params *dup_params(const game_params *params)
 {
     game_params *ret = snew(game_params);
     *ret = *params;                   /* structure copy */
@@ -200,7 +200,7 @@ static void decode_params(game_params *ret, char const *string)
     }
 }
 
-static char *encode_params(game_params *params, int full)
+static char *encode_params(const game_params *params, int full)
 {
     char data[256];
 
@@ -212,7 +212,7 @@ static char *encode_params(game_params *params, int full)
     return dupstr(data);
 }
 
-static config_item *game_configure(game_params *params)
+static config_item *game_configure(const game_params *params)
 {
     config_item *ret;
     char buf[80];
@@ -244,7 +244,7 @@ static config_item *game_configure(game_params *params)
     return ret;
 }
 
-static game_params *custom_params(config_item *cfg)
+static game_params *custom_params(const config_item *cfg)
 {
     game_params *ret = snew(game_params);
 
@@ -255,7 +255,7 @@ static game_params *custom_params(config_item *cfg)
     return ret;
 }
 
-static char *validate_params(game_params *params, int full)
+static char *validate_params(const game_params *params, int full)
 {
     if (params->w < 2 || params->h < 2)
        return "Width and neight must be at least two";
@@ -292,7 +292,7 @@ static game_state *blank_game(int w, int h)
     return state;
 }
 
-static game_state *dup_game(game_state *state)
+static game_state *dup_game(const game_state *state)
 {
     game_state *ret = blank_game(state->w, state->h);
 
@@ -333,7 +333,7 @@ static int c2n(char c) {
     return -1;
 }
 
-static void unpick_desc(const game_params *params, char *desc,
+static void unpick_desc(const game_params *params, const char *desc,
                         game_state **sout, char **mout)
 {
     game_state *state = blank_game(params->w, params->h);
@@ -378,12 +378,12 @@ static char *generate_desc(game_state *state, int issolve)
 
 /* --- Useful game functions (completion, etc.) --- */
 
-static int game_can_format_as_text_now(game_params *params)
+static int game_can_format_as_text_now(const game_params *params)
 {
     return TRUE;
 }
 
-static char *game_text_format(game_state *state)
+static char *game_text_format(const game_state *state)
 {
     int len, x, y, i;
     char *ret, *p;
@@ -535,16 +535,28 @@ static int check_complete(game_state *state, unsigned flags)
     for (y = 0; y < h; y++) /* check rows from (0,y) */
         error += check_rowcol(state, y*w, 1, w, flags);
 
-    /* mark (all) white regions as an error if there is more than one.
-     * may want to make this less in-your-face (by only marking
-     * the smallest region as an error, for example -- but what if we
-     * have two regions of identical size?) */
-    for (i = 0; i < state->n; i++) {
-        if (!(state->flags[i] & F_BLACK) &&
-            dsf_size(dsf, i) < nwhite) {
-            error += 1;
-            if (flags & CC_MARK_ERRORS)
-                state->flags[i] |= F_ERROR;
+    /* If there's more than one white region, pick the largest one to
+     * be the canonical one (arbitrarily tie-breaking towards lower
+     * array indices), and mark all the others as erroneous. */
+    {
+        int largest = 0, canonical = -1;
+        for (i = 0; i < state->n; i++)
+            if (!(state->flags[i] & F_BLACK)) {
+                int size = dsf_size(dsf, i);
+                if (largest < size) {
+                    largest = size;
+                    canonical = i;
+                }
+            }
+
+        if (largest < nwhite) {
+            for (i = 0; i < state->n; i++)
+                if (!(state->flags[i] & F_BLACK) &&
+                    dsf_canonify(dsf, i) != canonical) {
+                    error += 1;
+                    if (flags & CC_MARK_ERRORS)
+                        state->flags[i] |= F_ERROR;
+                }
         }
     }
 
@@ -552,7 +564,8 @@ static int check_complete(game_state *state, unsigned flags)
     return (error > 0) ? 0 : 1;
 }
 
-static char *game_state_diff(game_state *src, game_state *dst, int issolve)
+static char *game_state_diff(const game_state *src, const game_state *dst,
+                             int issolve)
 {
     char *ret = NULL, buf[80], c;
     int retlen = 0, x, y, i, k;
@@ -1171,8 +1184,8 @@ static int solve_specific(game_state *state, int diff, int sneaky)
     return state->impossible ? -1 : check_complete(state, CC_MUST_FILL);
 }
 
-static char *solve_game(game_state *state, game_state *currstate,
-                       char *aux, char **error)
+static char *solve_game(const game_state *state, const game_state *currstate,
+                        const char *aux, char **error)
 {
     game_state *solved = dup_game(currstate);
     char *move = NULL;
@@ -1401,7 +1414,7 @@ randomise:
     return ret;
 }
 
-static char *validate_desc(const game_params *params, char *desc)
+static char *validate_desc(const game_params *params, const char *desc)
 {
     char *ret = NULL;
 
@@ -1409,7 +1422,8 @@ static char *validate_desc(const game_params *params, char *desc)
     return ret;
 }
 
-static game_state *new_game(midend *me, game_params *params, char *desc)
+static game_state *new_game(midend *me, const game_params *params,
+                            const char *desc)
 {
     game_state *state = NULL;
 
@@ -1425,7 +1439,7 @@ struct game_ui {
     int show_black_nums;
 };
 
-static game_ui *new_ui(game_state *state)
+static game_ui *new_ui(const game_state *state)
 {
     game_ui *ui = snew(game_ui);
 
@@ -1440,17 +1454,17 @@ static void free_ui(game_ui *ui)
     sfree(ui);
 }
 
-static char *encode_ui(game_ui *ui)
+static char *encode_ui(const game_ui *ui)
 {
     return NULL;
 }
 
-static void decode_ui(game_ui *ui, char *encoding)
+static void decode_ui(game_ui *ui, const char *encoding)
 {
 }
 
-static void game_changed_state(game_ui *ui, game_state *oldstate,
-                               game_state *newstate)
+static void game_changed_state(game_ui *ui, const game_state *oldstate,
+                               const game_state *newstate)
 {
     if (!oldstate->completed && newstate->completed)
         ui->cshow = 0;
@@ -1471,8 +1485,9 @@ struct game_drawstate {
     unsigned int *flags;
 };
 
-static char *interpret_move(game_state *state, game_ui *ui, const game_drawstate *ds,
-                           int mx, int my, int button)
+static char *interpret_move(const game_state *state, game_ui *ui,
+                            const game_drawstate *ds,
+                            int mx, int my, int button)
 {
     char buf[80], c;
     int i, x = FROMCOORD(mx), y = FROMCOORD(my);
@@ -1522,7 +1537,7 @@ static char *interpret_move(game_state *state, game_ui *ui, const game_drawstate
     return NULL;
 }
 
-static game_state *execute_move(game_state *state, char *move)
+static game_state *execute_move(const game_state *state, const char *move)
 {
     game_state *ret = dup_game(state);
     int x, y, i, n;
@@ -1567,8 +1582,8 @@ badmove:
  * Drawing routines.
  */
 
-static void game_compute_size(game_params *params, int tilesize,
-                             int *x, int *y)
+static void game_compute_size(const game_params *params, int tilesize,
+                              int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -1579,7 +1594,7 @@ static void game_compute_size(game_params *params, int tilesize,
 }
 
 static void game_set_size(drawing *dr, game_drawstate *ds,
-                         game_params *params, int tilesize)
+                          const game_params *params, int tilesize)
 {
     ds->tilesize = tilesize;
 }
@@ -1608,7 +1623,7 @@ static float *game_colours(frontend *fe, int *ncolours)
     return ret;
 }
 
-static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
+static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
 {
     struct game_drawstate *ds = snew(struct game_drawstate);
 
@@ -1673,9 +1688,10 @@ static void tile_redraw(drawing *dr, game_drawstate *ds, int x, int y,
     draw_update(dr, x, y, TILE_SIZE, TILE_SIZE);
 }
 
-static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
-                       game_state *state, int dir, game_ui *ui,
-                       float animtime, float flashtime)
+static void game_redraw(drawing *dr, game_drawstate *ds,
+                        const game_state *oldstate, const game_state *state,
+                        int dir, const game_ui *ui,
+                        float animtime, float flashtime)
 {
     int x, y, i, flash;
     unsigned int f;
@@ -1720,14 +1736,14 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
     ds->started = 1;
 }
 
-static float game_anim_length(game_state *oldstate, game_state *newstate,
-                             int dir, game_ui *ui)
+static float game_anim_length(const game_state *oldstate,
+                              const game_state *newstate, int dir, game_ui *ui)
 {
     return 0.0F;
 }
 
-static float game_flash_length(game_state *oldstate, game_state *newstate,
-                              int dir, game_ui *ui)
+static float game_flash_length(const game_state *oldstate,
+                               const game_state *newstate, int dir, game_ui *ui)
 {
     if (!oldstate->completed &&
         newstate->completed && !newstate->used_solve)
@@ -1735,17 +1751,17 @@ static float game_flash_length(game_state *oldstate, game_state *newstate,
     return 0.0F;
 }
 
-static int game_status(game_state *state)
+static int game_status(const game_state *state)
 {
     return state->completed ? +1 : 0;
 }
 
-static int game_timing_state(game_state *state, game_ui *ui)
+static int game_timing_state(const game_state *state, game_ui *ui)
 {
     return TRUE;
 }
 
-static void game_print_size(game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, float *x, float *y)
 {
     int pw, ph;
 
@@ -1755,7 +1771,7 @@ static void game_print_size(game_params *params, float *x, float *y)
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, int tilesize)
 {
     int ink = print_mono_colour(dr, 0);
     int paper = print_mono_colour(dr, 1);