Added "dual" option to grid generators
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 2 Feb 2012 07:13:14 +0000 (07:13 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 2 Feb 2012 07:13:14 +0000 (07:13 +0000)
It is now possible to produce duals of all grids.

git-svn-id: svn://svn.tartarus.org/sgt/puzzles@9396 cda61777-01e9-0310-a592-d414129be87e

grid.c
grid.h
loopy.c
pearl.c

diff --git a/grid.c b/grid.c
index 14f2dc8..24380d9 100644 (file)
--- a/grid.c
+++ b/grid.c
@@ -518,7 +518,7 @@ static void grid_make_consistent(grid *g)
      * We use "-1", not "-2" here, because Euler's formula includes the
      * infinite face, which we don't count. */
     g->num_edges = g->num_faces + g->num_dots - 1;
-    assert(g->num_edges > 2);
+    debug(("allocating room for %d edges\n", g->num_edges));
     g->edges = snewn(g->num_edges, grid_edge);
     next_new_edge = g->edges;
 
@@ -533,6 +533,7 @@ static void grid_make_consistent(grid *g)
     for (i = 0; i < g->num_faces; i++) {
         grid_face *f = g->faces + i;
         int j;
+        assert(f->order > 2);
         for (j = 0; j < f->order; j++) {
             grid_edge e; /* fake edge for searching */
             grid_edge *edge_found;
@@ -1380,7 +1381,7 @@ void grid_find_incentre(grid_face *f)
 static grid *grid_dual(grid *g)
 {
     grid *new_g;
-    int i, j;
+    int i, j, k;
     tree234* points;
 
     new_g = grid_empty();
@@ -1411,16 +1412,17 @@ static grid *grid_dual(grid *g)
         if (order>2)
         {
             grid_face_add_new(new_g, order);
-            for (j=0;j<d->order;j++)
+            for (j=0,k=0;j<d->order;j++)
             {
                 grid_dot *new_d;
                 if (d->faces[j])
                 {
                     new_d = grid_get_dot(new_g, points,
                             d->faces[j]->ix, d->faces[j]->iy);
-                    grid_face_set_dot(new_g, new_d, j);
+                    grid_face_set_dot(new_g, new_d, k++);
                 }
             }
+            assert(k==order);
         }
     }
 
@@ -2104,30 +2106,6 @@ static grid *grid_new_octagonal(int width, int height, char *desc)
     return g;
 }
 
-#define DUAL_OCTAGONAL_TILESIZE OCTAGONAL_TILESIZE
-/* b/a approx sqrt(2) */
-#define DUAL_OCTAGONAL_A OCTAGONAL_A
-#define DUAL_OCTAGONAL_B OCTAGONAL_B
-
-static void grid_size_dual_octagonal(int width, int height,
-                          int *tilesize, int *xextent, int *yextent)
-{
-    grid_size_octagonal(width, height, tilesize, xextent, yextent);
-}
-
-static grid *grid_new_dual_octagonal(int width, int height, char *desc)
-{
-    grid *orig;
-    grid *g;
-
-    orig = grid_new_octagonal(width, height, desc);
-
-    g = grid_dual(orig);
-    grid_free(orig);
-
-    return g;
-}
-
 #define KITE_TILESIZE 40
 /* b/a approx sqrt(3) */
 #define KITE_A 15
@@ -2793,7 +2771,7 @@ static grid *grid_new_penrose_p3_thick(int width, int height, char *desc)
 static grid *(*(grid_news[]))(int, int, char*) = { GRIDGEN_LIST(FNNEW) };
 static void(*(grid_sizes[]))(int, int, int*, int*, int*) = { GRIDGEN_LIST(FNSZ) };
 
-char *grid_new_desc(grid_type type, int width, int height, random_state *rs)
+char *grid_new_desc(grid_type type, int width, int height, int dual, random_state *rs)
 {
     if (type != GRID_PENROSE_P2 && type != GRID_PENROSE_P3)
         return NULL;
@@ -2801,7 +2779,7 @@ char *grid_new_desc(grid_type type, int width, int height, random_state *rs)
     return grid_new_desc_penrose(type, width, height, rs);
 }
 
-char *grid_validate_desc(grid_type type, int width, int height, char *desc)
+char *grid_validate_desc(grid_type type, int width, int height, int dual, char *desc)
 {
     if (type != GRID_PENROSE_P2 && type != GRID_PENROSE_P3) {
         if (desc != NULL)
@@ -2812,12 +2790,25 @@ char *grid_validate_desc(grid_type type, int width, int height, char *desc)
     return grid_validate_desc_penrose(type, width, height, desc);
 }
 
-grid *grid_new(grid_type type, int width, int height, char *desc)
+grid *grid_new(grid_type type, int width, int height, int dual, char *desc)
 {
-    char *err = grid_validate_desc(type, width, height, desc);
+    char *err = grid_validate_desc(type, width, height, dual, desc);
     if (err) assert(!"Invalid grid description.");
 
-    return grid_news[type](width, height, desc);
+    if (!dual)
+    {
+        return grid_news[type](width, height, desc);
+    }
+    else
+    {
+        grid *temp;
+        grid *g;
+
+        temp = grid_news[type](width, height, desc);
+        g = grid_dual(temp);
+        grid_free(temp);
+        return g;
+    }
 }
 
 void grid_compute_size(grid_type type, int width, int height,
diff --git a/grid.h b/grid.h
index 00cd7c5..7cf4f59 100644 (file)
--- a/grid.h
+++ b/grid.h
@@ -101,7 +101,6 @@ typedef struct grid {
   A(CAIRO,cairo) \
   A(GREATHEXAGONAL,greathexagonal) \
   A(OCTAGONAL,octagonal) \
-  A(DUAL_OCTAGONAL,dual_octagonal) \
   A(KITE,kites) \
   A(FLORET,floret) \
   A(DODECAGONAL,dodecagonal) \
@@ -115,10 +114,10 @@ typedef enum grid_type { GRIDGEN_LIST(ENUM) GRID_TYPE_MAX } grid_type;
 
 /* Free directly after use if non-NULL. Will never contain an underscore
  * (so clients can safely use that as a separator). */
-char *grid_new_desc(grid_type type, int width, int height, random_state *rs);
-char *grid_validate_desc(grid_type type, int width, int height, char *desc);
+char *grid_new_desc(grid_type type, int width, int height, int dual, random_state *rs);
+char *grid_validate_desc(grid_type type, int width, int height, int dual, char *desc);
 
-grid *grid_new(grid_type type, int width, int height, char *desc);
+grid *grid_new(grid_type type, int width, int height, int dual, char *desc);
 
 void grid_free(grid *g);
 
diff --git a/loopy.c b/loopy.c
index 328a717..091b378 100644 (file)
--- a/loopy.c
+++ b/loopy.c
@@ -208,6 +208,7 @@ struct game_params {
     int w, h;
     int diff;
     int type;
+    int dual;
 };
 
 /* line_drawstate is the same as line_state, but with the extra ERROR
@@ -257,7 +258,6 @@ static void check_caches(const solver_state* sstate);
     A(Great-Dodecagonal,GRID_GREATDODECAGONAL,2,2) \
     A(Penrose (kite/dart),GRID_PENROSE_P2,3,3) \
     A(Penrose (rhombs),GRID_PENROSE_P3,3,3) \
-    A(Octagonal (dual),GRID_DUAL_OCTAGONAL,3,3)
 
 #define GRID_NAME(title,type,amin,omin) #title,
 #define GRID_CONFIG(title,type,amin,omin) ":" #title
@@ -267,6 +267,7 @@ static void check_caches(const solver_state* sstate);
      "Width and height for this grid type must both be at least " #amin, \
      "At least one of width and height for this grid type must be at least " #omin,},
 static char const *const gridnames[] = { GRIDLIST(GRID_NAME) };
+static char const *const dualnames[] = { "", "(dual) " };
 #define GRID_CONFIGS GRIDLIST(GRID_CONFIG)
 static grid_type grid_types[] = { GRIDLIST(GRID_TYPE) };
 #define NUM_GRID_TYPES (sizeof(grid_types) / sizeof(grid_types[0]))
@@ -280,7 +281,7 @@ static const struct {
  * generated. */
 static grid *loopy_generate_grid(game_params *params, char *grid_desc)
 {
-    return grid_new(grid_types[params->type], params->w, params->h, grid_desc);
+    return grid_new(grid_types[params->type], params->w, params->h, params->dual, grid_desc);
 }
 
 /* ----------------------------------------------------------------------
@@ -476,6 +477,7 @@ static game_params *default_params(void)
 #endif
     ret->diff = DIFF_EASY;
     ret->type = 0;
+    ret->dual = 0;
 
     return ret;
 }
@@ -490,40 +492,40 @@ static game_params *dup_params(game_params *params)
 
 static const game_params presets[] = {
 #ifdef SMALL_SCREEN
-    {  7,  7, DIFF_EASY, 0 },
-    {  7,  7, DIFF_NORMAL, 0 },
-    {  7,  7, DIFF_HARD, 0 },
-    {  7,  7, DIFF_HARD, 1 },
-    {  7,  7, DIFF_HARD, 2 },
-    {  5,  5, DIFF_HARD, 3 },
-    {  7,  7, DIFF_HARD, 4 },
-    {  5,  4, DIFF_HARD, 5 },
-    {  5,  5, DIFF_HARD, 6 },
-    {  5,  5, DIFF_HARD, 7 },
-    {  3,  3, DIFF_HARD, 8 },
-    {  3,  3, DIFF_HARD, 9 },
-    {  3,  3, DIFF_HARD, 10 },
-    {  6,  6, DIFF_HARD, 11 },
-    {  6,  6, DIFF_HARD, 12 },
+    {  7,  7, DIFF_EASY, 0, 0 },
+    {  7,  7, DIFF_NORMAL, 0, 0 },
+    {  7,  7, DIFF_HARD, 0, 0 },
+    {  7,  7, DIFF_HARD, 1, 0 },
+    {  7,  7, DIFF_HARD, 2, 0 },
+    {  5,  5, DIFF_HARD, 3, 0 },
+    {  7,  7, DIFF_HARD, 4, 0 },
+    {  5,  4, DIFF_HARD, 5, 0 },
+    {  5,  5, DIFF_HARD, 6, 0 },
+    {  5,  5, DIFF_HARD, 7, 0 },
+    {  3,  3, DIFF_HARD, 8, 0 },
+    {  3,  3, DIFF_HARD, 9, 0 },
+    {  3,  3, DIFF_HARD, 10, 0 },
+    {  6,  6, DIFF_HARD, 11, 0 },
+    {  6,  6, DIFF_HARD, 12, 0 },
 #else
-    {  7,  7, DIFF_EASY, 0 },
-    {  10,  10, DIFF_EASY, 0 },
-    {  7,  7, DIFF_NORMAL, 0 },
-    {  10,  10, DIFF_NORMAL, 0 },
-    {  7,  7, DIFF_HARD, 0 },
-    {  10,  10, DIFF_HARD, 0 },
-    {  10,  10, DIFF_HARD, 1 },
-    {  12,  10, DIFF_HARD, 2 },
-    {  7,  7, DIFF_HARD, 3 },
-    {  9,  9, DIFF_HARD, 4 },
-    {  5,  4, DIFF_HARD, 5 },
-    {  7,  7, DIFF_HARD, 6 },
-    {  5,  5, DIFF_HARD, 7 },
-    {  5,  5, DIFF_HARD, 8 },
-    {  5,  4, DIFF_HARD, 9 },
-    {  5,  4, DIFF_HARD, 10 },
-    {  10, 10, DIFF_HARD, 11 },
-    {  10, 10, DIFF_HARD, 12 }
+    {  7,  7, DIFF_EASY, 0, 0 },
+    {  10,  10, DIFF_EASY, 0, 0 },
+    {  7,  7, DIFF_NORMAL, 0, 0 },
+    {  10,  10, DIFF_NORMAL, 0, 0 },
+    {  7,  7, DIFF_HARD, 0, 0 },
+    {  10,  10, DIFF_HARD, 0, 0 },
+    {  10,  10, DIFF_HARD, 1, 0 },
+    {  12,  10, DIFF_HARD, 2, 0 },
+    {  7,  7, DIFF_HARD, 3, 0 },
+    {  9,  9, DIFF_HARD, 4, 0 },
+    {  5,  4, DIFF_HARD, 5, 0 },
+    {  7,  7, DIFF_HARD, 6, 0 },
+    {  5,  5, DIFF_HARD, 7, 0 },
+    {  5,  5, DIFF_HARD, 8, 0 },
+    {  5,  4, DIFF_HARD, 9, 0 },
+    {  5,  4, DIFF_HARD, 10, 0 },
+    {  10, 10, DIFF_HARD, 11, 0 },
+    {  10, 10, DIFF_HARD, 12, 0 }
 #endif
 };
 
@@ -538,8 +540,9 @@ static int game_fetch_preset(int i, char **name, game_params **params)
     tmppar = snew(game_params);
     *tmppar = presets[i];
     *params = tmppar;
-    sprintf(buf, "%dx%d %s - %s", tmppar->h, tmppar->w,
-            gridnames[tmppar->type], diffnames[tmppar->diff]);
+    sprintf(buf, "%dx%d %s %s- %s", tmppar->h, tmppar->w,
+            gridnames[tmppar->type], dualnames[tmppar->dual], 
+            diffnames[tmppar->diff]);
     *name = dupstr(buf);
 
     return TRUE;
@@ -554,12 +557,17 @@ static void decode_params(game_params *params, char const *string)
 {
     params->h = params->w = atoi(string);
     params->diff = DIFF_EASY;
+    params->dual = 0;
     while (*string && isdigit((unsigned char)*string)) string++;
     if (*string == 'x') {
         string++;
         params->h = atoi(string);
         while (*string && isdigit((unsigned char)*string)) string++;
     }
+    if (*string == 'l') {
+        string++;
+        params->dual = 1;
+    }
     if (*string == 't') {
         string++;
         params->type = atoi(string);
@@ -578,7 +586,8 @@ static void decode_params(game_params *params, char const *string)
 static char *encode_params(game_params *params, int full)
 {
     char str[80];
-    sprintf(str, "%dx%dt%d", params->w, params->h, params->type);
+    sprintf(str, "%dx%dt%d%s", params->w, params->h, params->type,
+            params->dual ? "l" : "");
     if (full)
         sprintf(str + strlen(str), "d%c", diffchars[params->diff]);
     return dupstr(str);
@@ -589,7 +598,7 @@ static config_item *game_configure(game_params *params)
     config_item *ret;
     char buf[80];
 
-    ret = snewn(5, config_item);
+    ret = snewn(6, config_item);
 
     ret[0].name = "Width";
     ret[0].type = C_STRING;
@@ -613,10 +622,15 @@ static config_item *game_configure(game_params *params)
     ret[3].sval = DIFFCONFIG;
     ret[3].ival = params->diff;
 
-    ret[4].name = NULL;
-    ret[4].type = C_END;
+    ret[4].name = "Dual";
+    ret[4].type = C_BOOLEAN;
     ret[4].sval = NULL;
-    ret[4].ival = 0;
+    ret[4].ival = params->dual;
+
+    ret[5].name = NULL;
+    ret[5].type = C_END;
+    ret[5].sval = NULL;
+    ret[5].ival = 0;
 
     return ret;
 }
@@ -629,6 +643,7 @@ static game_params *custom_params(config_item *cfg)
     ret->h = atoi(cfg[1].sval);
     ret->type = cfg[2].ival;
     ret->diff = cfg[3].ival;
+    ret->dual = cfg[4].ival;
 
     return ret;
 }
@@ -723,7 +738,7 @@ static char *validate_desc(game_params *params, char *desc)
     /* It's pretty inefficient to do this just for validation. All we need to
      * know is the precise number of faces. */
     grid_desc = extract_grid_desc(&desc);
-    ret = grid_validate_desc(grid_types[params->type], params->w, params->h, grid_desc);
+    ret = grid_validate_desc(grid_types[params->type], params->w, params->h, params->dual, grid_desc);
     if (ret) return ret;
 
     g = loopy_generate_grid(params, grid_desc);
@@ -1374,7 +1389,7 @@ static char *new_game_desc(game_params *params, random_state *rs,
     game_state *state = snew(game_state);
     game_state *state_new;
 
-    grid_desc = grid_new_desc(grid_types[params->type], params->w, params->h, rs);
+    grid_desc = grid_new_desc(grid_types[params->type], params->w, params->h, params->dual, rs);
     state->game_grid = g = loopy_generate_grid(params, grid_desc);
 
     state->clues = snewn(g->num_faces, signed char);
diff --git a/pearl.c b/pearl.c
index 248d64e..ef9fdc9 100644 (file)
--- a/pearl.c
+++ b/pearl.c
@@ -1048,7 +1048,7 @@ int pearl_loopgen_bias(void *vctx, char *board, int face)
 
 void pearl_loopgen(int w, int h, char *lines, random_state *rs)
 {
-    grid *g = grid_new(GRID_SQUARE, w-1, h-1, NULL);
+    grid *g = grid_new(GRID_SQUARE, w-1, h-1, 0, NULL);
     char *board = snewn(g->num_faces, char);
     int i, s = g->tilesize;
     struct pearl_loopgen_bias_ctx biasctx;