A user points out that Loopy's solver relies on elements of the
[sgt/puzzles] / loopy.c
diff --git a/loopy.c b/loopy.c
index 777e6f8..10619af 100644 (file)
--- a/loopy.c
+++ b/loopy.c
@@ -58,7 +58,7 @@ struct game_state {
     int w, h;
     
     /* Put -1 in a square that doesn't get a clue */
-    char *clues;
+    signed char *clues;
     
     /* Arrays of line states, stored left-to-right, top-to-bottom */
     char *hl, *vl;
@@ -120,7 +120,7 @@ typedef struct solver_state {
 #define CONFIG(upper,title,lower,fn) ":" #title
 #define SOLVER_FN_DECL(upper,title,lower,fn) static int fn(solver_state *);
 #define SOLVER_FN(upper,title,lower,fn) &fn,
-enum diff { DIFFLIST(ENUM) DIFF_MAX };
+enum { DIFFLIST(ENUM) DIFF_MAX };
 static char const *const diffnames[] = { DIFFLIST(TITLE) };
 static char const diffchars[] = DIFFLIST(ENCODE);
 #define DIFFCONFIG DIFFLIST(CONFIG)
@@ -129,7 +129,7 @@ static int (*(solver_fns[]))(solver_state *) = { DIFFLIST(SOLVER_FN) };
 
 struct game_params {
     int w, h;
-    enum diff diff;
+    int diff;
     int rec;
 };
 
@@ -159,7 +159,7 @@ static int get_line_status_from_point(const game_state *state,
 static int dot_order(const game_state* state, int i, int j, char line_type);
 static int square_order(const game_state* state, int i, int j, char line_type);
 static solver_state *solve_game_rec(const solver_state *sstate,
-                                    enum diff diff);
+                                    int diff);
 
 #ifdef DEBUG_CACHES
 static void check_caches(const solver_state* sstate);
@@ -299,7 +299,7 @@ static game_state *dup_game(game_state *state)
     ret->solved = state->solved;
     ret->cheated = state->cheated;
 
-    ret->clues = snewn(SQUARE_COUNT(state), char);
+    ret->clues = snewn(SQUARE_COUNT(state), signed char);
     memcpy(ret->clues, state->clues, SQUARE_COUNT(state));
 
     ret->hl = snewn(HL_COUNT(state), char);
@@ -323,7 +323,7 @@ static void free_game(game_state *state)
     }
 }
 
-static solver_state *new_solver_state(const game_state *state, enum diff diff) {
+static solver_state *new_solver_state(const game_state *state, int diff) {
     int i, j;
     solver_state *ret = snew(solver_state);
 
@@ -512,22 +512,25 @@ static const game_params presets[] = {
     { 15, 15, DIFF_EASY, 0 },
     { 15, 15, DIFF_NORMAL, 0 },
     { 15, 15, DIFF_HARD, 0 },
+#ifndef SMALL_SCREEN
     { 30, 20, DIFF_EASY, 0 },
     { 30, 20, DIFF_NORMAL, 0 },
     { 30, 20, DIFF_HARD, 0 }
 #endif
+#endif
 };
 
 static int game_fetch_preset(int i, char **name, game_params **params)
 {
-    const game_params *tmppar;
+    game_params *tmppar;
     char buf[80];
 
     if (i < 0 || i >= lenof(presets))
         return FALSE;
 
-    tmppar = &presets[i];
-    *params = dup_params((game_params *)tmppar);
+    tmppar = snew(game_params);
+    *tmppar = presets[i];
+    *params = tmppar;
     sprintf(buf, "%dx%d %s", tmppar->h, tmppar->w, diffnames[tmppar->diff]);
     *name = dupstr(buf);
 
@@ -630,7 +633,7 @@ static char *validate_params(game_params *params, int full)
      * and custom_params will never generate anything that isn't
      * within range.
      */
-    assert(params->diff >= 0 && params->diff < DIFF_MAX);
+    assert(params->diff < DIFF_MAX);
 
     return NULL;
 }
@@ -656,12 +659,12 @@ static char *state_to_text(const game_state *state)
                 dp += sprintf(dp, "%c", (int)(empty_count + 'a' - 1));
                 empty_count = 0;
             }
-            dp += sprintf(dp, "%c", CLUE2CHAR(CLUE_AT(state, i, j)));
+            dp += sprintf(dp, "%c", (int)CLUE2CHAR(CLUE_AT(state, i, j)));
         }
     }
 
     if (empty_count)
-        dp += sprintf(dp, "%c", (empty_count + 'a' - 1));
+        dp += sprintf(dp, "%c", (int)(empty_count + 'a' - 1));
 
     retval = dupstr(description);
     sfree(description);
@@ -909,7 +912,7 @@ static char *game_text_format(game_state *state)
         rp += sprintf(rp, " \n");
         for (i = 0; i < state->w; ++i) {
             DRAW_VL;
-            rp += sprintf(rp, "%c", CLUE2CHAR(CLUE_AT(state, i, j)));
+            rp += sprintf(rp, "%c", (int)CLUE2CHAR(CLUE_AT(state, i, j)));
         }
         DRAW_VL;
         rp += sprintf(rp, "\n");
@@ -1422,7 +1425,7 @@ enum { SQUARE_LIT, SQUARE_UNLIT };
  * the dimensions provided by said game_state) */
 static void add_full_clues(game_state *state, random_state *rs)
 {
-    char *clues;
+    signed char *clues;
     char *board;
     int i, j, a, b, c;
     int board_area = SQUARE_COUNT(state);
@@ -1646,7 +1649,7 @@ static void add_full_clues(game_state *state, random_state *rs)
     sfree(board);
 }
 
-static int game_has_unique_soln(const game_state *state, enum diff diff)
+static int game_has_unique_soln(const game_state *state, int diff)
 {
     int ret;
     solver_state *sstate_new;
@@ -1665,7 +1668,7 @@ static int game_has_unique_soln(const game_state *state, enum diff diff)
 
 /* Remove clues one at a time at random. */
 static game_state *remove_clues(game_state *state, random_state *rs, 
-                                enum diff diff)
+                                int diff)
 {
     int *square_list, squares;
     game_state *ret = dup_game(state), *saved_ret;
@@ -1719,7 +1722,7 @@ static char *new_game_desc(game_params *params, random_state *rs,
     state->h = params->h;
     state->w = params->w;
 
-    state->clues = snewn(SQUARE_COUNT(params), char);
+    state->clues = snewn(SQUARE_COUNT(params), signed char);
     state->hl = snewn(HL_COUNT(params), char);
     state->vl = snewn(VL_COUNT(params), char);
 
@@ -1743,7 +1746,9 @@ newboard_please:
     state = state_new;
 
     if (params->diff > 0 && game_has_unique_soln(state, params->diff-1)) {
+#ifdef SHOW_WORKING
         fprintf(stderr, "Rejecting board, it is too easy\n");
+#endif
         goto newboard_please;
     }
 
@@ -1769,7 +1774,7 @@ static game_state *new_game(midend *me, game_params *params, char *desc)
     state->h = params->h;
     state->w = params->w;
 
-    state->clues = snewn(SQUARE_COUNT(params), char);
+    state->clues = snewn(SQUARE_COUNT(params), signed char);
     state->hl = snewn(HL_COUNT(params), char);
     state->vl = snewn(VL_COUNT(params), char);
 
@@ -1873,26 +1878,21 @@ const static struct dline dlines[] =  {
      (d==DLINE_DR) ? "DLINE_DR": \
      "oops")
 
-static const struct dline *get_dline(enum dline_desc desc)
-{
-    return &dlines[desc];
-}
+#define CHECK_DLINE_SENSIBLE(d) assert(dlines[(d)].dx != -1 && dlines[(d)].dy != -1)
 
 /* This will fail an assertion if the directions handed to it are the same, as
  * no dline corresponds to that */
 static enum dline_desc dline_desc_from_dirs(enum direction dir1, 
                                             enum direction dir2)
 {
-    const struct dline *dl;
     int i;
 
     assert (dir1 != dir2);
 
     for (i = 0; i < lenof(dlines); ++i) {
-        dl = &dlines[i];
-        if ((dir1 == dl->dir1 && dir2 == dl->dir2) ||
-            (dir1 == dl->dir2 && dir2 == dl->dir1)) {
-            return dl->desc;
+        if ((dir1 == dlines[i].dir1 && dir2 == dlines[i].dir2) ||
+            (dir1 == dlines[i].dir2 && dir2 == dlines[i].dir1)) {
+            return dlines[i].desc;
         }
     }
 
@@ -1904,7 +1904,7 @@ static enum dline_desc dline_desc_from_dirs(enum direction dir1,
  * dline corresponding to the dot or square at [i,j].  You'll get an assertion
  * failure if you talk about a dline that doesn't exist, ie if you ask about
  * non-touching lines around a square. */
-static inline int get_dot_dline(const game_state *state, const char *dline_array,
+static int get_dot_dline(const game_state *state, const char *dline_array,
                          int i, int j, enum dline_desc desc)
 {
 /*    fprintf(stderr, "get_dot_dline %p [%d,%d] %s\n", dline_array, i, j, DL2STR(desc)); */
@@ -1931,10 +1931,9 @@ static int set_dot_dline(game_state *state, char *dline_array,
 static int get_square_dline(game_state *state, char *dline_array,
                             int i, int j, enum dline_desc desc)
 {
-    const struct dline *dl = get_dline(desc);
-    assert(dl->dx != -1 && dl->dy != -1);
+    CHECK_DLINE_SENSIBLE(desc);
 /*    fprintf(stderr, "get_square_dline %p [%d,%d] %s\n", dline_array, i, j, DL2STR(desc)); */
-    return BIT_SET(dline_array[(i+dl->dx) + (state->w + 1) * (j+dl->dy)], 
+    return BIT_SET(dline_array[(i+dlines[desc].dx) + (state->w + 1) * (j+dlines[desc].dy)], 
                    desc);
 }
 
@@ -1945,10 +1944,9 @@ static int set_square_dline(game_state *state, char *dline_array,
 #endif
                             )
 {
-    const struct dline *dl = get_dline(desc);
     int ret;
-    assert(dl->dx != -1 && dl->dy != -1);
-    ret = SET_BIT(dline_array[(i+dl->dx) + (state->w + 1) * (j+dl->dy)], desc);
+    CHECK_DLINE_SENSIBLE(desc);
+    ret = SET_BIT(dline_array[(i+dlines[desc].dx) + (state->w + 1) * (j+dlines[desc].dy)], desc);
 #ifdef SHOW_WORKING
     if (ret)
         fprintf(stderr, "set_square_dline %p [%d,%d] %s (%s)\n", dline_array, i, j, DL2STR(desc), reason);
@@ -1979,10 +1977,9 @@ static int set_square_opp_dline(game_state *state, char *dline_array,
 static int dline_both_unknown(const game_state *state, int i, int j,
                               enum dline_desc desc)
 {
-    const struct dline *dl = get_dline(desc);
     return 
-        (get_line_status_from_point(state, i, j, dl->dir1) == LINE_UNKNOWN) &&
-        (get_line_status_from_point(state, i, j, dl->dir2) == LINE_UNKNOWN);
+        (get_line_status_from_point(state, i, j, dlines[desc].dir1) == LINE_UNKNOWN) &&
+        (get_line_status_from_point(state, i, j, dlines[desc].dir2) == LINE_UNKNOWN);
 }
 
 #define SQUARE_DLINES \
@@ -2064,7 +2061,7 @@ static int square_setall_identical(solver_state *sstate, int x, int y,
 #define SQUARE_LINE(dx, dy, linedir, dir_dot, sqdir) \
     can[sqdir] = \
         edsf_canonify(sstate->hard->linedsf, \
-                      LINEDSF_INDEX(sstate->state, x+dx, y+dy, linedir), \
+                      LINEDSF_INDEX(sstate->state, x+(dx), y+(dy), linedir), \
                       &inv[sqdir]);
     
     SQUARE_LINES;
@@ -2083,7 +2080,7 @@ static int square_setall_identical(solver_state *sstate, int x, int y,
                  * consider {i,j} in the opposite order. */
 #define SQUARE_LINE(dx, dy, dir, c, sqdir) \
                 if (j == sqdir) { \
-                    retval = set_line_bydot(sstate, x+dx, y+dy, dir, line_new); \
+                    retval = set_line_bydot(sstate, x+(dx), y+(dy), dir, line_new); \
                     if (retval) { \
                         break; \
                     } \
@@ -2142,14 +2139,14 @@ static int square_setboth_in_dline(solver_state *sstate, enum dline_desc dd,
                                    int i, int j, enum line_state line_new)
 {
     int retval = FALSE;
-    const struct dline *dl = get_dline(dd);
+    const struct dline dll = dlines[dd], *dl = &dll;
     
 #if 0
     fprintf(stderr, "square_setboth_in_dline %s [%d,%d] to %d\n",
                     DL2STR(dd), i, j, line_new);
 #endif
 
-    assert(dl->dx != -1 && dl->dy != -1);
+    CHECK_DLINE_SENSIBLE(dd);
     
     retval |=
         set_line_bydot(sstate, i+dl->dx, j+dl->dy, dl->dir1, line_new);
@@ -2341,7 +2338,7 @@ static int easy_mode_deductions(solver_state *sstate)
 {
     int i, j, h, w, current_yes, current_no;
     game_state *state;
-    enum diff diff = DIFF_MAX;
+    int diff = DIFF_MAX;
 
     state = sstate->state;
     h = state->h;
@@ -2461,7 +2458,7 @@ static int normal_mode_deductions(solver_state *sstate)
     int i, j;
     game_state *state = sstate->state;
     enum dline_desc dd;
-    enum diff diff = DIFF_MAX;
+    int diff = DIFF_MAX;
 
     FORALL_SQUARES(state, i, j) {
         if (sstate->square_solved[SQUARE_INDEX(state, i, j)])
@@ -2649,8 +2646,7 @@ static int hard_mode_deductions(solver_state *sstate)
     const int h=state->h, w=state->w;
     enum direction dir1, dir2;
     int can1, can2, inv1, inv2;
-    enum diff diff = DIFF_MAX;
-    const struct dline *dl;
+    int diff = DIFF_MAX;
     enum dline_desc dd;
 
     FORALL_SQUARES(state, i, j) {
@@ -2773,7 +2769,7 @@ static int hard_mode_deductions(solver_state *sstate)
             continue;
 
         FORALL_DOT_DLINES(dd) {
-            dl = get_dline(dd);
+            const struct dline dll = dlines[dd], *dl = &dll;
             if (i == 0 && (dl->dir1 == LEFT || dl->dir2 == LEFT))
                 continue;
             if (i == w && (dl->dir1 == RIGHT || dl->dir2 == RIGHT))
@@ -3054,7 +3050,7 @@ finished_loop_deductionsing:
 /* This will return a dynamically allocated solver_state containing the (more)
  * solved grid */
 static solver_state *solve_game_rec(const solver_state *sstate_start, 
-                                    enum diff diff)
+                                    int diff)
 {
     int i, j;
     int w, h;
@@ -3790,14 +3786,14 @@ static void game_print(drawing *dr, game_state *state, int tilesize)
     /*
      * Lines. (At the moment, I'm not bothering with crosses.)
      */
-    FORALL_VL(state, x, y) {
+    FORALL_HL(state, x, y) {
         if (RIGHTOF_DOT(state, x, y) == LINE_YES)
         draw_rect(dr, BORDER + x * TILE_SIZE,
                   BORDER + y * TILE_SIZE - LINEWIDTH/2,
                   TILE_SIZE, (LINEWIDTH/2) * 2 + 1, ink);
     }
 
-    FORALL_HL(state, x, y) {
+    FORALL_VL(state, x, y) {
         if (BELOW_DOT(state, x, y) == LINE_YES)
         draw_rect(dr, BORDER + x * TILE_SIZE - LINEWIDTH/2,
                   BORDER + y * TILE_SIZE,
@@ -3810,7 +3806,7 @@ static void game_print(drawing *dr, game_state *state, int tilesize)
 #endif
 
 const struct game thegame = {
-    "Loopy", "games.loopy",
+    "Loopy", "games.loopy", "loopy",
     default_params,
     game_fetch_preset,
     decode_params,