shithub: puzzles

Download patch

ref: cf880225edb1b6a5cb27dec01ba54c61822788f2
parent: f05c25347d66821d928668a7e87dffbf3ffed027
author: Simon Tatham <anakin@pobox.com>
date: Sat Aug 5 13:20:29 EDT 2006

I'm sick of repeatedly adding and removing local changes to Recipe
when testing a new game, so here's a new architecture for the Recipe
file. mkfiles.pl now supports several new features:

 - an `!include' directive, which accepts wildcards
 - += to append to an existing object group definition
 - the ability to divert output to an arbitrary file.

So now each puzzle has a `.R' file containing a fragment of Recipe
code describing that puzzle, and the central Recipe does `!include
*.R' to construct the Makefiles. That way, I can keep as many
experimental half-finished puzzles lying around my working directory
as I like, and I won't have to keep reverting Recipe when I check in
any other changes.

As part of this change, list.c is no longer a version-controlled
file; it's now constructed by mkfiles.pl, so that it too can take
advantage of this mechanism.

[originally from svn r6781]

--- a/CHECKLST.txt
+++ b/CHECKLST.txt
@@ -6,20 +6,25 @@
 
 Write the source file for the new puzzle (duhh).
 
-Add it to Recipe in _four_ places:
- - the `ALL' definition, to ensure it is compiled into the OS X binary
- - as a GTK build target
- - as a Windows build target
- - in the Unix `make install' section at the bottom.
+Create a .R file for it which:
+ - defines a Recipe symbol for it if it requires auxiliary object
+   files
+ - adds it to the `ALL' definition, to ensure it is compiled into
+   the OS X binary
+ - adds it as a GTK build target
+ - adds it as a Windows build target
+ - adds auxiliary solver binaries if any
+ - adds it to $(GAMES) in the GTK makefile, for `make install'
+ - adds it to list.c for the OS X binary.
 
 If the puzzle is by a new author, modify the copyright notice in
 LICENCE and in puzzles.but. (Also in index.html, but that's listed
 below under website changes.)
 
-Add it to list.c so that the OS X binary will be able to select it
-from the menus. (Also, double-check that the game structure name in
-the source file has been renamed from `nullgame'. Actually compiling
-it on OS X would be a good way to check this, if convenient.)
+Double-check that the game structure name in the source file has
+been renamed from `nullgame', so that it'll work on OS X. Actually
+compiling it on OS X would be a good way to check this, if
+convenient.
 
 Add a documentation section in puzzles.but.
 
--- a/Recipe
+++ b/Recipe
@@ -16,95 +16,38 @@
 WINDOWS  = windows printing
          + user32.lib gdi32.lib comctl32.lib comdlg32.lib winspool.lib
 COMMON   = midend drawing misc malloc random version
-NET      = net tree234 dsf
-NETSLIDE = netslide tree234
-MINES    = mines tree234
-FLIP     = flip tree234
-PEGS     = pegs tree234
-UNTANGLE = untangle tree234
-SLANT    = slant dsf
-MAP      = map dsf
-LOOPY    = loopy tree234 dsf
-LIGHTUP  = lightup combi
-TENTS    = tents maxflow
-BRIDGES  = bridges dsf
-
-ALL      = list NET NETSLIDE cube fifteen sixteen rect pattern solo twiddle
-         + MINES samegame FLIP guess PEGS dominosa UNTANGLE blackbox SLANT
-         + LIGHTUP MAP LOOPY inertia TENTS BRIDGES
-
 GTK      = gtk printing ps
+# Objects needed for auxiliary command-line programs.
+STANDALONE = nullfe random misc malloc
 
-net      : [X] GTK COMMON NET
-netslide : [X] GTK COMMON NETSLIDE
-cube     : [X] GTK COMMON cube
-fifteen  : [X] GTK COMMON fifteen
-sixteen  : [X] GTK COMMON sixteen
-rect     : [X] GTK COMMON rect
-pattern  : [X] GTK COMMON pattern
-solo     : [X] GTK COMMON solo
-twiddle  : [X] GTK COMMON twiddle
-mines    : [X] GTK COMMON MINES
-samegame : [X] GTK COMMON samegame
-flip     : [X] GTK COMMON FLIP
-guess    : [X] GTK COMMON guess
-pegs     : [X] GTK COMMON PEGS
-dominosa : [X] GTK COMMON dominosa
-untangle : [X] GTK COMMON UNTANGLE
-blackbox : [X] GTK COMMON blackbox
-slant    : [X] GTK COMMON SLANT
-lightup  : [X] GTK COMMON LIGHTUP
-map      : [X] GTK COMMON MAP
-loopy    : [X] GTK COMMON LOOPY
-inertia  : [X] GTK COMMON inertia
-tents    : [X] GTK COMMON TENTS
-bridges  : [X] GTK COMMON BRIDGES
+ALL      = list
 
-# Auxiliary command-line programs.
-STANDALONE = nullfe random misc malloc
+# First half of list.c.
+!begin >list.c
+/*
+ * list.c: List of pointers to puzzle structures, for monolithic
+ * platforms.
+ *
+ * This file is automatically generated by mkfiles.pl. Do not edit
+ * it directly, or the changes will be lost next time mkfiles.pl runs.
+ * Instead, edit Recipe and/or its *.R subfiles.
+ */
+#include "puzzles.h"
+#define GAMELIST(A) \
+!end
 
-solosolver :    [U] solo[STANDALONE_SOLVER] STANDALONE
-patternsolver : [U] pattern[STANDALONE_SOLVER] STANDALONE
-mineobfusc :    [U] mines[STANDALONE_OBFUSCATOR] tree234 STANDALONE
-slantsolver :   [U] slant[STANDALONE_SOLVER] dsf STANDALONE
-mapsolver :     [U] map[STANDALONE_SOLVER] dsf STANDALONE m.lib
-lightupsolver : [U] lightup[STANDALONE_SOLVER] combi STANDALONE
-tentssolver :   [U] tents[STANDALONE_SOLVER] maxflow STANDALONE
+# Now each .R file adds part of the macro definition of GAMELIST to list.c.
+!include *.R
 
-solosolver :    [C] solo[STANDALONE_SOLVER] STANDALONE
-patternsolver : [C] pattern[STANDALONE_SOLVER] STANDALONE
-mineobfusc :    [C] mines[STANDALONE_OBFUSCATOR] tree234 STANDALONE
-slantsolver :   [C] slant[STANDALONE_SOLVER] dsf STANDALONE
-mapsolver :     [C] map[STANDALONE_SOLVER] dsf STANDALONE
-lightupsolver : [C] lightup[STANDALONE_SOLVER] combi STANDALONE
-tentssolver :   [C] tents[STANDALONE_SOLVER] maxflow STANDALONE
+# Then we finish up list.c as follows:
+!begin >list.c
 
-# The Windows Net shouldn't be called `net.exe' since Windows
-# already has a reasonably important utility program by that name!
-netgame  : [G] WINDOWS COMMON NET
-netslide : [G] WINDOWS COMMON NETSLIDE
-cube     : [G] WINDOWS COMMON cube
-fifteen  : [G] WINDOWS COMMON fifteen
-sixteen  : [G] WINDOWS COMMON sixteen
-rect     : [G] WINDOWS COMMON rect
-pattern  : [G] WINDOWS COMMON pattern
-solo     : [G] WINDOWS COMMON solo
-twiddle  : [G] WINDOWS COMMON twiddle
-mines    : [G] WINDOWS COMMON MINES
-samegame : [G] WINDOWS COMMON samegame
-flip     : [G] WINDOWS COMMON FLIP
-guess    : [G] WINDOWS COMMON guess
-pegs     : [G] WINDOWS COMMON PEGS
-dominosa : [G] WINDOWS COMMON dominosa
-untangle : [G] WINDOWS COMMON UNTANGLE
-blackbox : [G] WINDOWS COMMON blackbox
-slant    : [G] WINDOWS COMMON SLANT
-lightup  : [G] WINDOWS COMMON LIGHTUP
-map      : [G] WINDOWS COMMON MAP
-loopy    : [G] WINDOWS COMMON LOOPY
-inertia  : [G] WINDOWS COMMON inertia
-tents    : [G] WINDOWS COMMON TENTS
-bridges  : [G] WINDOWS COMMON BRIDGES
+#define DECL(x) extern const game x;
+#define REF(x) &x,
+GAMELIST(DECL)
+const game *gamelist[] = { GAMELIST(REF) };
+const int gamecount = lenof(gamelist);
+!end
 
 # Mac OS X unified application containing all the puzzles.
 Puzzles  : [MX] osx osx.icns osx-info.plist COMMON ALL
@@ -138,17 +81,6 @@
 	rm -f raw.dmg devicename
 !end
 
-# The `nullgame' source file is a largely blank one, which contains
-# all the correct function definitions to compile and link, but
-# which defines the null game in which nothing is ever drawn and
-# there are no valid moves. Its main purpose is to act as a
-# template for writing new game definition source files. I include
-# it in the Makefile because it will be worse than useless if it
-# ever fails to compile, so it's important that it should actually
-# be built on a regular basis.
-nullgame : [X] GTK COMMON nullgame
-nullgame : [G] WINDOWS COMMON nullgame
-
 # Version management.
 !begin vc
 version.obj: *.c *.h
@@ -194,10 +126,7 @@
 # make install for Unix.
 !begin gtk
 install:
-	for i in cube net netslide fifteen sixteen twiddle \
-	         pattern rect solo mines samegame flip guess \
-		 pegs dominosa untangle blackbox slant lightup \
-		 map loopy inertia tents bridges; do \
+	for i in $(GAMES); do \
 		$(INSTALL_PROGRAM) -m 755 $$i $(DESTDIR)$(gamesdir)/$$i \
 		|| exit 1; \
 	done
--- /dev/null
+++ b/blackbox.R
@@ -1,0 +1,15 @@
+# -*- makefile -*-
+
+blackbox : [X] GTK COMMON blackbox
+
+blackbox : [G] WINDOWS COMMON blackbox
+
+ALL += blackbox
+
+!begin gtk
+GAMES += blackbox
+!end
+
+!begin >list.c
+    A(blackbox) \
+!end
--- /dev/null
+++ b/bridges.R
@@ -1,0 +1,17 @@
+# -*- makefile -*-
+
+BRIDGES  = bridges dsf
+
+bridges  : [X] GTK COMMON BRIDGES
+
+bridges  : [G] WINDOWS COMMON BRIDGES
+
+ALL += BRIDGES
+
+!begin gtk
+GAMES += bridges
+!end
+
+!begin >list.c
+    A(bridges) \
+!end
--- /dev/null
+++ b/cube.R
@@ -1,0 +1,15 @@
+# -*- makefile -*-
+
+cube     : [X] GTK COMMON cube
+
+cube     : [G] WINDOWS COMMON cube
+
+ALL += cube
+
+!begin gtk
+GAMES += cube
+!end
+
+!begin >list.c
+    A(cube) \
+!end
--- a/devel.but
+++ b/devel.but
@@ -193,7 +193,9 @@
 \b On platforms such as MacOS X and PalmOS, which build all the
 puzzles into a single monolithic binary, the game structure in each
 back end must have a different name, and there's a helper module
-\c{list.c} which contains a complete list of those game structures.
+\c{list.c} (constructed automatically by the same Perl script that
+builds the \cw{Makefile}s) which contains a complete list of those
+game structures.
 
 On the latter type of platform, source files may assume that the
 preprocessor symbol \c{COMBINED} has been defined. Thus, the usual
@@ -2916,9 +2918,10 @@
 \c extern const int gamecount;
 
 \c{gamelist} will be an array of \c{gamecount} game structures,
-declared in the source module \c{list.c}. The application should
-search that array for the game it wants, probably by reaching into
-each game structure and looking at its \c{name} field.
+declared in the automatically constructed source module \c{list.c}.
+The application should search that array for the game it wants,
+probably by reaching into each game structure and looking at its
+\c{name} field.
 
 }
 
--- /dev/null
+++ b/dominosa.R
@@ -1,0 +1,15 @@
+# -*- makefile -*-
+
+dominosa : [X] GTK COMMON dominosa
+
+dominosa : [G] WINDOWS COMMON dominosa
+
+ALL += dominosa
+
+!begin gtk
+GAMES += dominosa
+!end
+
+!begin >list.c
+    A(dominosa) \
+!end
--- /dev/null
+++ b/fifteen.R
@@ -1,0 +1,15 @@
+# -*- makefile -*-
+
+fifteen  : [X] GTK COMMON fifteen
+
+fifteen  : [G] WINDOWS COMMON fifteen
+
+ALL += fifteen
+
+!begin gtk
+GAMES += fifteen
+!end
+
+!begin >list.c
+    A(fifteen) \
+!end
--- /dev/null
+++ b/flip.R
@@ -1,0 +1,17 @@
+# -*- makefile -*-
+
+FLIP     = flip tree234
+
+flip     : [X] GTK COMMON FLIP
+
+flip     : [G] WINDOWS COMMON FLIP
+
+ALL += FLIP
+
+!begin gtk
+GAMES += flip
+!end
+
+!begin >list.c
+    A(flip) \
+!end
--- /dev/null
+++ b/guess.R
@@ -1,0 +1,15 @@
+# -*- makefile -*-
+
+guess    : [X] GTK COMMON guess
+
+guess    : [G] WINDOWS COMMON guess
+
+ALL += guess
+
+!begin gtk
+GAMES += guess
+!end
+
+!begin >list.c
+    A(guess) \
+!end
--- /dev/null
+++ b/inertia.R
@@ -1,0 +1,15 @@
+# -*- makefile -*-
+
+inertia  : [X] GTK COMMON inertia
+
+inertia  : [G] WINDOWS COMMON inertia
+
+ALL += inertia
+
+!begin gtk
+GAMES += inertia
+!end
+
+!begin >list.c
+    A(inertia) \
+!end
--- /dev/null
+++ b/lightup.R
@@ -1,0 +1,20 @@
+# -*- makefile -*-
+
+LIGHTUP  = lightup combi
+
+lightup  : [X] GTK COMMON LIGHTUP
+
+lightup  : [G] WINDOWS COMMON LIGHTUP
+
+lightupsolver : [U] lightup[STANDALONE_SOLVER] combi STANDALONE
+lightupsolver : [C] lightup[STANDALONE_SOLVER] combi STANDALONE
+
+ALL += LIGHTUP
+
+!begin gtk
+GAMES += lightup
+!end
+
+!begin >list.c
+    A(lightup) \
+!end
--- a/list.c
+++ /dev/null
@@ -1,72 +1,0 @@
-/*
- * list.c: List of puzzles.
- */
-
-#include "puzzles.h"
-
-/*
- * The available games can be most easily enumerated by searching
- * for the line in each game source file saying "#define thegame
- * <gamename>". Hence, the following piece of shell/Perl should
- * regenerate this list automatically:
-
-perl -ne '/^#define thegame (\S+)/ and $1 ne "nullgame" and print "extern const game $1;\n"' *.c
-echo -e '\nconst game *gamelist[] = {'
-perl -ne '/^#define thegame (\S+)/ and $1 ne "nullgame" and print "    &$1,\n"' *.c
-echo -e '};\n\nconst int gamecount = lenof(gamelist);'
-
- */
-
-extern const game blackbox;
-extern const game bridges;
-extern const game cube;
-extern const game dominosa;
-extern const game fifteen;
-extern const game flip;
-extern const game guess;
-extern const game inertia;
-extern const game lightup;
-extern const game loopy;
-extern const game map;
-extern const game mines;
-extern const game net;
-extern const game netslide;
-extern const game pattern;
-extern const game pegs;
-extern const game rect;
-extern const game samegame;
-extern const game sixteen;
-extern const game slant;
-extern const game solo;
-extern const game tents;
-extern const game twiddle;
-extern const game untangle;
-
-const game *gamelist[] = {
-    &blackbox,
-    &bridges,
-    &cube,
-    &dominosa,
-    &fifteen,
-    &flip,
-    &guess,
-    &inertia,
-    &lightup,
-    &loopy,
-    &map,
-    &mines,
-    &net,
-    &netslide,
-    &pattern,
-    &pegs,
-    &rect,
-    &samegame,
-    &sixteen,
-    &slant,
-    &solo,
-    &tents,
-    &twiddle,
-    &untangle,
-};
-
-const int gamecount = lenof(gamelist);
--- /dev/null
+++ b/loopy.R
@@ -1,0 +1,17 @@
+# -*- makefile -*-
+
+LOOPY    = loopy tree234 dsf
+
+loopy    : [X] GTK COMMON LOOPY
+
+loopy    : [G] WINDOWS COMMON LOOPY
+
+ALL += LOOPY
+
+!begin gtk
+GAMES += loopy
+!end
+
+!begin >list.c
+    A(loopy) \
+!end
--- /dev/null
+++ b/map.R
@@ -1,0 +1,20 @@
+# -*- makefile -*-
+
+MAP      = map dsf
+
+map      : [X] GTK COMMON MAP
+
+map      : [G] WINDOWS COMMON MAP
+
+mapsolver :     [U] map[STANDALONE_SOLVER] dsf STANDALONE m.lib
+mapsolver :     [C] map[STANDALONE_SOLVER] dsf STANDALONE
+
+ALL += MAP
+
+!begin gtk
+GAMES += map
+!end
+
+!begin >list.c
+    A(map) \
+!end
--- /dev/null
+++ b/mines.R
@@ -1,0 +1,20 @@
+# -*- makefile -*-
+
+MINES    = mines tree234
+
+mines    : [X] GTK COMMON MINES
+
+mines    : [G] WINDOWS COMMON MINES
+
+mineobfusc :    [U] mines[STANDALONE_OBFUSCATOR] tree234 STANDALONE
+mineobfusc :    [C] mines[STANDALONE_OBFUSCATOR] tree234 STANDALONE
+
+ALL += MINES
+
+!begin gtk
+GAMES += mines
+!end
+
+!begin >list.c
+    A(mines) \
+!end
--- a/mkfiles.pl
+++ b/mkfiles.pl
@@ -17,16 +17,19 @@
 #  - special-define objects (foo.o[PREPROCSYMBOL]) are not
 #    supported in the mac or vcproj makefiles.
 
-use FileHandle;
+use IO::Handle;
 use Cwd;
 
-open IN, "Recipe" or do {
+@filestack = ();
+$in = new IO::Handle;
+open $in, "Recipe" or do {
     # We want to deal correctly with being run from one of the
     # subdirs in the source tree. So if we can't find Recipe here,
     # try one level up.
     chdir "..";
-    open IN, "Recipe" or die "unable to open Recipe file\n";
+    open $in, "Recipe" or die "unable to open Recipe file\n";
 };
+push @filestack, $in;
 
 # HACK: One of the source files in `charset' is auto-generated by
 # sbcsgen.pl. We need to generate that _now_, before attempting
@@ -45,13 +48,20 @@
 
 @allobjs = (); # all object file names
 
-while (<IN>) {
+readinput: while (1) {
+  while (not defined ($_ = <$in>)) {
+    close $in;
+    last readinput if 0 == scalar @filestack;
+    $in = pop @filestack;
+  }
+
+  chomp;
+  split;
+
   # Skip comments (unless the comments belong, for example because
   # they're part of a diversion).
   next if /^\s*#/ and !defined $divert;
 
-  chomp;
-  split;
   if ($_[0] eq "!begin" and $_[1] eq "help") { $divert = \$help; next; }
   if ($_[0] eq "!end") { $divert = undef; next; }
   if ($_[0] eq "!name") { $project_name = $_[1]; next; }
@@ -59,13 +69,27 @@
   if ($_[0] eq "!makefile" and &mfval($_[1])) { $makefiles{$_[1]}=$_[2]; next;}
   if ($_[0] eq "!specialobj" and &mfval($_[1])) { $specialobj{$_[1]}->{$_[2]} = 1; next;}
   if ($_[0] eq "!begin") {
-      if (&mfval($_[1])) {
+      if ($_[1] =~ /^>(.*)/) {
+	  $divert = \$auxfiles{$1};
+      } elsif (&mfval($_[1])) {
 	  $divert = \$makefile_extra{$_[1]};
-      } else {
-	  $divert = \$dummy;
       }
       next;
   }
+  if ($_[0] eq "!include") {
+      @newfiles = ();
+      for ($i = 1; $i <= $#_; $i++) {
+	  push @newfiles, (sort glob $_[$i]);
+      }
+      for ($i = $#newfiles; $i >= 0; $i--) {
+	  $file = $newfiles[$i];
+	  $f = new IO::Handle;
+	  open $f, "<$file" or die "unable to open include file '$file'\n";
+	  push @filestack, $f;
+      }
+      $in = $filestack[$#filestack];
+      next;
+  }
   # If we're gathering help text, keep doing so.
   if (defined $divert) { ${$divert} .= "$_\n"; next; }
   # Ignore blank lines.
@@ -80,6 +104,11 @@
     $prog = undef;
     die "$.: unexpected + line\n" if !defined $lastlistref;
   } elsif ($_[1] eq "=") {
+    $groups{$_[0]} = [];
+    $listref = $groups{$_[0]};
+    $prog = undef;
+    shift @objs; # eat the group name
+  } elsif ($_[1] eq "+=") {
     $groups{$_[0]} = [] if !defined $groups{$_[0]};
     $listref = $groups{$_[0]};
     $prog = undef;
@@ -89,7 +118,7 @@
     $prog = $_[0];
     shift @objs; # eat the program name
   } else {
-    die "$.: unrecognised line type\n";
+    die "$.: unrecognised line type: '$_'\n";
   }
   shift @objs; # eat the +, the = or the :
 
@@ -113,7 +142,11 @@
   $lastlistref = $listref;
 }
 
-close IN;
+foreach $aux (sort keys %auxfiles) {
+    open AUX, ">$aux";
+    print AUX $auxfiles{$aux};
+    close AUX;
+}
 
 # Find object file names with predefines (in square brackets after
 # the module name), and decide on actual object names for them.
--- /dev/null
+++ b/net.R
@@ -1,0 +1,19 @@
+# -*- makefile -*-
+
+NET      = net tree234 dsf
+
+net      : [X] GTK COMMON NET
+
+# The Windows Net shouldn't be called `net.exe' since Windows
+# already has a reasonably important utility program by that name!
+netgame  : [G] WINDOWS COMMON NET
+
+ALL += NET
+
+!begin gtk
+GAMES += net
+!end
+
+!begin >list.c
+    A(net) \
+!end
--- /dev/null
+++ b/netslide.R
@@ -1,0 +1,17 @@
+# -*- makefile -*-
+
+NETSLIDE = netslide tree234
+
+netslide : [X] GTK COMMON NETSLIDE
+
+netslide : [G] WINDOWS COMMON NETSLIDE
+
+ALL += NETSLIDE
+
+!begin gtk
+GAMES += netslide
+!end
+
+!begin >list.c
+    A(netslide) \
+!end
--- /dev/null
+++ b/nullgame.R
@@ -1,0 +1,12 @@
+# -*- makefile -*-
+
+# The `nullgame' source file is a largely blank one, which contains
+# all the correct function definitions to compile and link, but
+# which defines the null game in which nothing is ever drawn and
+# there are no valid moves. Its main purpose is to act as a
+# template for writing new game definition source files. I include
+# it in the Makefile because it will be worse than useless if it
+# ever fails to compile, so it's important that it should actually
+# be built on a regular basis.
+nullgame : [X] GTK COMMON nullgame
+nullgame : [G] WINDOWS COMMON nullgame
--- /dev/null
+++ b/pattern.R
@@ -1,0 +1,18 @@
+# -*- makefile -*-
+
+pattern  : [X] GTK COMMON pattern
+
+pattern  : [G] WINDOWS COMMON pattern
+
+patternsolver : [U] pattern[STANDALONE_SOLVER] STANDALONE
+patternsolver : [C] pattern[STANDALONE_SOLVER] STANDALONE
+
+ALL += pattern
+
+!begin gtk
+GAMES += pattern
+!end
+
+!begin >list.c
+    A(pattern) \
+!end
--- /dev/null
+++ b/pegs.R
@@ -1,0 +1,17 @@
+# -*- makefile -*-
+
+PEGS     = pegs tree234
+
+pegs     : [X] GTK COMMON PEGS
+
+pegs     : [G] WINDOWS COMMON PEGS
+
+ALL += PEGS
+
+!begin gtk
+GAMES += pegs
+!end
+
+!begin >list.c
+    A(pegs) \
+!end
--- /dev/null
+++ b/rect.R
@@ -1,0 +1,15 @@
+# -*- makefile -*-
+
+rect     : [X] GTK COMMON rect
+
+rect     : [G] WINDOWS COMMON rect
+
+ALL += rect
+
+!begin gtk
+GAMES += rect
+!end
+
+!begin >list.c
+    A(rect) \
+!end
--- /dev/null
+++ b/samegame.R
@@ -1,0 +1,15 @@
+# -*- makefile -*-
+
+samegame : [X] GTK COMMON samegame
+
+samegame : [G] WINDOWS COMMON samegame
+
+ALL += samegame
+
+!begin gtk
+GAMES += samegame
+!end
+
+!begin >list.c
+    A(samegame) \
+!end
--- /dev/null
+++ b/sixteen.R
@@ -1,0 +1,15 @@
+# -*- makefile -*-
+
+sixteen  : [X] GTK COMMON sixteen
+
+sixteen  : [G] WINDOWS COMMON sixteen
+
+ALL += sixteen
+
+!begin gtk
+GAMES += sixteen
+!end
+
+!begin >list.c
+    A(sixteen) \
+!end
--- /dev/null
+++ b/slant.R
@@ -1,0 +1,20 @@
+# -*- makefile -*-
+
+SLANT    = slant dsf
+
+slant    : [X] GTK COMMON SLANT
+
+slant    : [G] WINDOWS COMMON SLANT
+
+slantsolver :   [U] slant[STANDALONE_SOLVER] dsf STANDALONE
+slantsolver :   [C] slant[STANDALONE_SOLVER] dsf STANDALONE
+
+ALL += SLANT
+
+!begin gtk
+GAMES += slant
+!end
+
+!begin >list.c
+    A(slant) \
+!end
--- /dev/null
+++ b/solo.R
@@ -1,0 +1,18 @@
+# -*- makefile -*-
+
+solo     : [X] GTK COMMON solo
+
+solo     : [G] WINDOWS COMMON solo
+
+solosolver :    [U] solo[STANDALONE_SOLVER] STANDALONE
+solosolver :    [C] solo[STANDALONE_SOLVER] STANDALONE
+
+ALL += solo
+
+!begin gtk
+GAMES += solo
+!end
+
+!begin >list.c
+    A(solo) \
+!end
--- /dev/null
+++ b/tents.R
@@ -1,0 +1,20 @@
+# -*- makefile -*-
+
+TENTS    = tents maxflow
+
+tents    : [X] GTK COMMON TENTS
+
+tents    : [G] WINDOWS COMMON TENTS
+
+ALL += TENTS
+
+tentssolver :   [U] tents[STANDALONE_SOLVER] maxflow STANDALONE
+tentssolver :   [C] tents[STANDALONE_SOLVER] maxflow STANDALONE
+
+!begin gtk
+GAMES += tents
+!end
+
+!begin >list.c
+    A(tents) \
+!end
--- /dev/null
+++ b/twiddle.R
@@ -1,0 +1,15 @@
+# -*- makefile -*-
+
+twiddle  : [X] GTK COMMON twiddle
+
+twiddle  : [G] WINDOWS COMMON twiddle
+
+ALL += twiddle
+
+!begin gtk
+GAMES += twiddle
+!end
+
+!begin >list.c
+    A(twiddle) \
+!end
--- /dev/null
+++ b/untangle.R
@@ -1,0 +1,17 @@
+# -*- makefile -*-
+
+UNTANGLE = untangle tree234
+
+untangle : [X] GTK COMMON UNTANGLE
+
+untangle : [G] WINDOWS COMMON UNTANGLE
+
+ALL += UNTANGLE
+
+!begin gtk
+GAMES += untangle
+!end
+
+!begin >list.c
+    A(untangle) \
+!end