shithub: puzzles

Download patch

ref: ea13d39a1780406421d2e9aa01c4caeca100c9eb
parent: c8a843ee62e2a4a984a39aecd65865d7e9ab189d
author: Simon Tatham <[email protected]>
date: Tue Apr 8 06:30:18 EDT 2008

Having got Jigsaw mode generation working at reasonable speed, we
can now productise it.

[originally from svn r7979]

--- a/puzzles.but
+++ b/puzzles.but
@@ -861,9 +861,9 @@
 
 \cfg{winhelp-topic}{games.solo}
 
-You have a square grid, which is divided into square or rectangular
-blocks. Each square must be filled in with a digit from 1 to the
-size of the grid, in such a way that
+You have a square grid, which is divided into as many equally sized
+sub-blocks as the grid has rows. Each square must be filled in with
+a digit from 1 to the size of the grid, in such a way that
 
 \b every row contains only one occurrence of each digit
 
@@ -871,13 +871,19 @@
 
 \b every block contains only one occurrence of each digit.
 
+\b (optionally, by default off) each of the square's two main
+diagonals contains only one occurrence of each digit.
+
 You are given some of the numbers as clues; your aim is to place the
 rest of the numbers correctly.
 
-The default puzzle size is 3\by\.3 (a 9\by\.9 actual grid, divided
-into nine 3\by\.3 blocks). You can also select sizes with
-rectangular blocks instead of square ones, such as 2\by\.3 (a
-6\by\.6 grid divided into six 3\by\.2 blocks).
+Under the default settings, the sub-blocks are square or
+rectangular. The default puzzle size is 3\by\.3 (a 9\by\.9 actual
+grid, divided into nine 3\by\.3 blocks). You can also select sizes
+with rectangular blocks instead of square ones, such as 2\by\.3 (a
+6\by\.6 grid divided into six 3\by\.2 blocks). Alternatively, you
+can select \q{jigsaw} mode, in which the sub-blocks are arbitrary
+shapes which differ between individual puzzles.
 
 If you select a puzzle size which requires more than 9 digits, the
 additional digits will be letters of the alphabet. For example, if
@@ -930,11 +936,18 @@
 the inverse of this: for example, if you select 2 columns and 3 rows,
 each actual block will have 3 columns and 2 rows.)
 
-You can introduce an optional extra constraint on the puzzles,
-requiring that the two main diagonals of the grid also contain one
+If you tick the \q{X} checkbox, Solo will apply the optional extra
+constraint that the two main diagonals of the grid also contain one
 of every digit. (This is sometimes known as \q{Sudoku-X} in
 newspapers.) In this mode, the squares on the two main diagonals
 will be shaded slightly so that you know it's enabled.
+
+If you tick the \q{Jigsaw} checkbox, Solo will generate randomly
+shaped sub-blocks. In this mode, the actual grid size will be taken
+to be the product of the numbers entered in the \q{Columns} and
+\q{Rows} boxes. There is no reason why you have to enter a number
+greater than 1 in both boxes; Jigsaw mode has no constraint on the
+grid size, and it can even be a prime number if you feel like it.
 
 You can also configure the type of symmetry shown in the generated
 puzzles. More symmetry makes the puzzles look prettier but may also
--- a/solo.c
+++ b/solo.c
@@ -3,26 +3,6 @@
  *
  * TODO:
  *
- *  - Jigsaw Sudoku is currently an undocumented feature enabled
- *    by setting r (`Rows of sub-blocks' in the GUI configurer) to
- *    1. The reason it's undocumented is because they're rather
- *    erratic to generate, because gridgen tends to hang up for
- *    ages. I think this is because some jigsaw block layouts
- *    simply do not admit very many valid filled grids (and
- *    perhaps some have none at all).
- *     + To fix this, I think probably the solution is a change in
- * 	 grid generation policy: gridgen needs to have less of an
- * 	 all-or-nothing attitude and instead make only a limited
- * 	 amount of effort to construct a filled grid before giving
- * 	 up and trying a new layout. (Come to think of it, this
- * 	 same change might also make 5x5 standard Sudoku more
- * 	 practical to generate, if correctly tuned.)
- *     + If I get this fixed, other work needed on jigsaw mode is:
- * 	  * introduce a GUI config checkbox. game_configure()
- * 	    ticks this box iff r==1; if it's ticked in a call to
- * 	    custom_params(), we replace (c, r) with (c*r, 1).
- *        * document it.
- *
  *  - reports from users are that `Trivial'-mode puzzles are still
  *    rather hard compared to newspapers' easy ones, so some better
  *    low-end difficulty grading would be nice
@@ -258,6 +238,9 @@
         { "3x3 Advanced X", { 3, 3, SYMM_ROT2, DIFF_SET, TRUE } },
         { "3x3 Extreme", { 3, 3, SYMM_ROT2, DIFF_EXTREME, FALSE } },
         { "3x3 Unreasonable", { 3, 3, SYMM_ROT2, DIFF_RECURSIVE, FALSE } },
+        { "9 Jigsaw Basic", { 9, 1, SYMM_ROT2, DIFF_SIMPLE, FALSE } },
+        { "9 Jigsaw Basic X", { 9, 1, SYMM_ROT2, DIFF_SIMPLE, TRUE } },
+        { "9 Jigsaw Advanced", { 9, 1, SYMM_ROT2, DIFF_SET, FALSE } },
 #ifndef SLOW_SYSTEM
         { "3x4 Basic", { 3, 4, SYMM_ROT2, DIFF_SIMPLE, FALSE } },
         { "4x4 Basic", { 4, 4, SYMM_ROT2, DIFF_SIMPLE, FALSE } },
@@ -376,7 +359,7 @@
     config_item *ret;
     char buf[80];
 
-    ret = snewn(6, config_item);
+    ret = snewn(7, config_item);
 
     ret[0].name = "Columns of sub-blocks";
     ret[0].type = C_STRING;
@@ -395,22 +378,27 @@
     ret[2].sval = NULL;
     ret[2].ival = params->xtype;
 
-    ret[3].name = "Symmetry";
-    ret[3].type = C_CHOICES;
-    ret[3].sval = ":None:2-way rotation:4-way rotation:2-way mirror:"
+    ret[3].name = "Jigsaw (irregularly shaped sub-blocks)";
+    ret[3].type = C_BOOLEAN;
+    ret[3].sval = NULL;
+    ret[3].ival = (params->r == 1);
+
+    ret[4].name = "Symmetry";
+    ret[4].type = C_CHOICES;
+    ret[4].sval = ":None:2-way rotation:4-way rotation:2-way mirror:"
         "2-way diagonal mirror:4-way mirror:4-way diagonal mirror:"
         "8-way mirror";
-    ret[3].ival = params->symm;
+    ret[4].ival = params->symm;
 
-    ret[4].name = "Difficulty";
-    ret[4].type = C_CHOICES;
-    ret[4].sval = ":Trivial:Basic:Intermediate:Advanced:Extreme:Unreasonable";
-    ret[4].ival = params->diff;
+    ret[5].name = "Difficulty";
+    ret[5].type = C_CHOICES;
+    ret[5].sval = ":Trivial:Basic:Intermediate:Advanced:Extreme:Unreasonable";
+    ret[5].ival = params->diff;
 
-    ret[5].name = NULL;
-    ret[5].type = C_END;
-    ret[5].sval = NULL;
-    ret[5].ival = 0;
+    ret[6].name = NULL;
+    ret[6].type = C_END;
+    ret[6].sval = NULL;
+    ret[6].ival = 0;
 
     return ret;
 }
@@ -422,8 +410,12 @@
     ret->c = atoi(cfg[0].sval);
     ret->r = atoi(cfg[1].sval);
     ret->xtype = cfg[2].ival;
-    ret->symm = cfg[3].ival;
-    ret->diff = cfg[4].ival;
+    if (cfg[3].ival) {
+	ret->c *= ret->r;
+	ret->r = 1;
+    }
+    ret->symm = cfg[4].ival;
+    ret->diff = cfg[5].ival;
 
     return ret;
 }