shithub: puzzles

Download patch

ref: 12b64a1db1a2cb94b938295875e5583237dbe168
parent: d5b53853aad6c3bbfe255c063c045e7986de33ad
author: Simon Tatham <anakin@pobox.com>
date: Sun May 23 06:04:47 EDT 2021

Build a lot of conditioned-out test and helper programs.

Most of these aren't especially useful, but if we're going to have
them in the code base at all, we should at least ensure they compile:
bit-rotted conditioned-out code is of no value.

One of the new programs is 'galaxieseditor', which borrows most of the
Galaxies code but changes the UI so that you can create and remove
_dots_ instead of edges, and then run the solver to see whether it can
solve the puzzle you've designed. Unlike the rest, this is a GUI
helper tool, using the 'guiprogram' cmake function introduced in the
previous commit.

The programs are:
 - 'combi', a test program for the utility module that generates all
   combinations of n things
 - 'divvy', a test program for the module that divides a rectangle at
   random into equally-sized polyominoes
 - 'penrose-test', a test program for the Penrose-tiling generator
   used in Loopy, which outputs an SVG of a piece of tiling
 - 'penrose-vector', a much smaller test program for the vector
   arithmetic subroutines in that code
 - 'sort-test', a test of this code base's local array sorting routine
 - 'tree234-test', the exhaustive test code that's been in tree234.c
   all along.

Not all of them compiled first time. Most of the fixes were the usual
kind of thing: fixing compiler warnings by removing unused
variables/functions, bringing uses of internal APIs up to date. A
notable one was that galaxieseditor's interpret_move() modified the
input game state, which was an error all along and is now detected by
me having made it a const pointer; I had to replace that with an extra
wrinkle in the move-string format, so that now execute_move() makes
the modification.

The one I'm _least_ proud of is squelching a huge number of
format-string warnings in tree234-test by interposing a variadic
function without __attribute__((printf)).

--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -65,6 +65,8 @@
 solver(galaxies)
 cliprogram(galaxiespicture galaxies.c
   COMPILE_DEFINITIONS STANDALONE_PICTURE_GENERATOR)
+guiprogram(galaxieseditor galaxies.c
+  COMPILE_DEFINITIONS EDITOR)
 
 puzzle(guess
   DISPLAYNAME "Guess"
@@ -266,5 +268,11 @@
 cliprogram(obfusc obfusc.c)
 cliprogram(latincheck latin.c COMPILE_DEFINITIONS STANDALONE_LATIN_TEST)
 cliprogram(matching matching.c COMPILE_DEFINITIONS STANDALONE_MATCHING_TEST)
+cliprogram(combi combi.c COMPILE_DEFINITIONS STANDALONE_COMBI_TEST)
+cliprogram(divvy divvy.c COMPILE_DEFINITIONS TESTMODE)
+cliprogram(penrose-test penrose.c COMPILE_DEFINITIONS TEST_PENROSE)
+cliprogram(penrose-vector-test penrose.c COMPILE_DEFINITIONS TEST_VECTORS)
+cliprogram(sort-test sort.c COMPILE_DEFINITIONS SORT_TEST)
+cliprogram(tree234-test tree234.c COMPILE_DEFINITIONS TEST)
 
 build_platform_extras()
--- a/combi.c
+++ b/combi.c
@@ -79,11 +79,6 @@
 
 #include <stdio.h>
 
-void fatal(const char *fmt, ...)
-{
-    abort();
-}
-
 int main(int argc, char *argv[])
 {
     combi_ctx *c;
--- a/divvy.c
+++ b/divvy.c
@@ -709,8 +709,8 @@
 
 	for (y = 0; y <= 2*h; y++) {
 	    for (x = 0; x <= 2*w; x++) {
-		int miny = y/2 - 1, maxy = y/2;
-		int minx = x/2 - 1, maxx = x/2;
+		int miny = y/2 - 1 /*, maxy = y/2 */;
+		int minx = x/2 - 1 /*, maxx = x/2 */;
 		int classes[4], tx, ty;
 		for (ty = 0; ty < 2; ty++)
 		    for (tx = 0; tx < 2; tx++) {
--- a/galaxies.c
+++ b/galaxies.c
@@ -372,6 +372,7 @@
     return toret;
 }
 
+#ifndef EDITOR
 static bool ok_to_add_assoc_with_opposite(
     const game_state *state, space *tile, space *dot)
 {
@@ -378,14 +379,14 @@
     space *opposite = space_opposite_dot(state, tile, dot);
     return ok_to_add_assoc_with_opposite_internal(state, tile, opposite);
 }
+#endif
 
 static void add_assoc_with_opposite(game_state *state, space *tile, space *dot) {
     space *opposite = space_opposite_dot(state, tile, dot);
 
-    if(opposite)
+    if(opposite && ok_to_add_assoc_with_opposite_internal(
+           state, tile, opposite))
     {
-        assert(ok_to_add_assoc_with_opposite_internal(state, tile, opposite));
-
         remove_assoc_with_opposite(state, tile);
         add_assoc(state, tile, dot);
         remove_assoc_with_opposite(state, opposite);
@@ -684,7 +685,7 @@
 /* Returns a move string for use by 'solve', including the initial
  * 'S' if issolve is true. */
 static char *diff_game(const game_state *src, const game_state *dest,
-                       bool issolve)
+                       bool issolve, int set_cdiff)
 {
     int movelen = 0, movesize = 256, x, y, len;
     char *move = snewn(movesize, char), buf[80];
@@ -698,6 +699,26 @@
         move[movelen++] = 'S';
         sep = ";";
     }
+#ifdef EDITOR
+    if (set_cdiff >= 0) {
+        switch (set_cdiff) {
+          case DIFF_IMPOSSIBLE:
+            movelen += sprintf(move+movelen, "%sII", sep);
+            break;
+          case DIFF_AMBIGUOUS:
+            movelen += sprintf(move+movelen, "%sIA", sep);
+            break;
+          case DIFF_UNFINISHED:
+            movelen += sprintf(move+movelen, "%sIU", sep);
+            break;
+          default:
+            movelen += sprintf(move+movelen, "%si%c",
+                               sep, galaxies_diffchars[set_cdiff]);
+            break;
+        }
+        sep = ";";
+    }
+#endif
     move[movelen] = '\0';
     for (x = 0; x < src->sx; x++) {
         for (y = 0; y < src->sy; y++) {
@@ -747,7 +768,8 @@
 
 /* Returns true if a dot here would not be too close to any other dots
  * (and would avoid other game furniture). */
-static bool dot_is_possible(game_state *state, space *sp, bool allow_assoc)
+static bool dot_is_possible(const game_state *state, space *sp,
+                            bool allow_assoc)
 {
     int bx = 0, by = 0, dx, dy;
     space *adj;
@@ -2309,7 +2331,7 @@
      */
     for (i = 0; i < tosolve->sx*tosolve->sy; i++)
         tosolve->grid[i].flags &= ~F_TILE_ASSOC;
-    ret = diff_game(currstate, tosolve, true);
+    ret = diff_game(currstate, tosolve, true, -1);
     free_game(tosolve);
     return ret;
 }
@@ -2448,15 +2470,13 @@
     px = 2*FROMCOORD((float)x) + 0.5;
     py = 2*FROMCOORD((float)y) + 0.5;
 
-    state->cdiff = -1;
-
     if (button == 'C' || button == 'c') return dupstr("C");
 
     if (button == 'S' || button == 's') {
         char *ret;
         game_state *tmp = dup_game(state);
-        state->cdiff = solver_state(tmp, DIFF_UNREASONABLE-1);
-        ret = diff_game(state, tmp, 0);
+        int cdiff = solver_state(tmp, DIFF_UNREASONABLE-1);
+        ret = diff_game(state, tmp, 0, cdiff);
         free_game(tmp);
         return ret;
     }
@@ -2514,7 +2534,7 @@
         char *ret;
         game_state *tmp = dup_game(state);
         solver_obvious(tmp);
-        ret = diff_game(state, tmp, false);
+        ret = diff_game(state, tmp, false, -1);
         free_game(tmp);
         return ret;
     }
@@ -2973,6 +2993,35 @@
         } else if (c == 'C') {
             move++;
             clear_game(ret, true);
+        } else if (c == 'i') {
+            int diff;
+            move++;
+            for (diff = 0; diff <= DIFF_UNREASONABLE; diff++)
+                if (*move == galaxies_diffchars[diff])
+                    break;
+            if (diff > DIFF_UNREASONABLE)
+                goto badmove;
+
+            ret->cdiff = diff;
+            move++;
+        } else if (c == 'I') {
+            int diff;
+            move++;
+            switch (*move) {
+              case 'A':
+                diff = DIFF_AMBIGUOUS;
+                break;
+              case 'I':
+                diff = DIFF_IMPOSSIBLE;
+                break;
+              case 'U':
+                diff = DIFF_UNFINISHED;
+                break;
+              default:
+                goto badmove;
+            }
+            ret->cdiff = diff;
+            move++;
 #endif
         } else if (c == 'S') {
             move++;
--- a/pearl.c
+++ b/pearl.c
@@ -2711,7 +2711,7 @@
     sfree(clues);
 }
 
-int main(int argc, const char *argv[])
+int main(int argc, char *argv[])
 {
     game_params *p = NULL;
     random_state *rs = NULL;
--- a/penrose.c
+++ b/penrose.c
@@ -588,7 +588,7 @@
 xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n\n");
 
     printf("<g>\n");
-    penrose(&ps, which);
+    penrose(&ps, which, 0);
     printf("</g>\n");
 
     printf("<!-- %d tiles and %d leaf tiles total -->\n",
--- a/tree234.c
+++ b/tree234.c
@@ -34,7 +34,15 @@
 #include "puzzles.h"		       /* for smalloc/sfree */
 
 #ifdef TEST
-#define LOG(x) (printf x)
+#include <stdarg.h>
+static void logprintf(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vprintf(fmt, ap);
+    va_end(ap);
+}
+#define LOG(x) (logprintf x)
 #define smalloc malloc
 #define srealloc realloc
 #define sfree free
@@ -1486,7 +1494,7 @@
 /*
  * Error reporting function.
  */
-void error(char *fmt, ...) {
+void error(const char *fmt, ...) {
     va_list ap;
     printf("ERROR: ");
     va_start(ap, fmt);
@@ -1519,13 +1527,14 @@
 
 	if (n->elems[2])
 	    len = sprintf(ctx->levels[0]+xpos, " %s%s%s",
-			  n->elems[0], n->elems[1], n->elems[2]);
+			  (char *)n->elems[0], (char *)n->elems[1],
+                          (char *)n->elems[2]);
 	else if (n->elems[1])
 	    len = sprintf(ctx->levels[0]+xpos, " %s%s",
-			  n->elems[0], n->elems[1]);
+			  (char *)n->elems[0], (char *)n->elems[1]);
 	else
 	    len = sprintf(ctx->levels[0]+xpos, " %s",
-			  n->elems[0]);
+			  (char *)n->elems[0]);
 	return xpos + 1 + (len-1) / 2;
     } else {
 	int xpos[4], nkids;
@@ -1561,13 +1570,14 @@
 	    ctx->levels[level][x++] = '_';
 	if (nkids==4)
 	    x += sprintf(ctx->levels[level]+x, ".%s.%s.%s.",
-			 n->elems[0], n->elems[1], n->elems[2]);
+			 (char *)n->elems[0], (char *)n->elems[1],
+                         (char *)n->elems[2]);
 	else if (nkids==3)
 	    x += sprintf(ctx->levels[level]+x, ".%s.%s.",
-			 n->elems[0], n->elems[1]);
+			 (char *)n->elems[0], (char *)n->elems[1]);
 	else
 	    x += sprintf(ctx->levels[level]+x, ".%s.",
-			 n->elems[0]);
+			 (char *)n->elems[0]);
 	while (x < xpos[nkids-1])
 	    ctx->levels[level][x++] = '_';
 	ctx->levels[level][x] = '\0';
@@ -1895,7 +1905,7 @@
     return strcmp(a, b);
 }
 
-char *strings[] = {
+const char *const strings_init[] = {
     "0", "2", "3", "I", "K", "d", "H", "J", "Q", "N", "n", "q", "j", "i",
     "7", "G", "F", "D", "b", "x", "g", "B", "e", "v", "V", "T", "f", "E",
     "S", "8", "A", "k", "X", "p", "C", "R", "a", "o", "r", "O", "Z", "u",
@@ -1916,7 +1926,8 @@
 #endif
 };
 
-#define NSTR lenof(strings)
+#define NSTR lenof(strings_init)
+char *strings[NSTR];
 
 void findtest(void) {
     static const int rels[] = {
@@ -2028,9 +2039,11 @@
     int tworoot, tmplen;
     unsigned seed = 0;
     tree234 *tree2, *tree3, *tree4;
-    int c;
 
     setvbuf(stdout, NULL, _IOLBF, 0);
+
+    for (i = 0; i < (int)NSTR; i++)
+        strings[i] = dupstr(strings_init[i]);
 
     for (i = 0; i < (int)NSTR; i++) in[i] = 0;
     array = NULL;