Having got Jigsaw mode generation working at reasonable speed, we

can now productise it.

[originally from svn r7979]
This commit is contained in:
Simon Tatham
2008-04-08 10:30:18 +00:00
parent c8a843ee62
commit ea13d39a17
2 changed files with 49 additions and 44 deletions

View File

@ -861,9 +861,9 @@ menu are \e{Width} and \e{Height}, which are self-explanatory.
\cfg{winhelp-topic}{games.solo} \cfg{winhelp-topic}{games.solo}
You have a square grid, which is divided into square or rectangular You have a square grid, which is divided into as many equally sized
blocks. Each square must be filled in with a digit from 1 to the sub-blocks as the grid has rows. Each square must be filled in with
size of the grid, in such a way that 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 \b every row contains only one occurrence of each digit
@ -871,13 +871,19 @@ size of the grid, in such a way that
\b every block contains only one occurrence of each digit. \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 You are given some of the numbers as clues; your aim is to place the
rest of the numbers correctly. rest of the numbers correctly.
The default puzzle size is 3\by\.3 (a 9\by\.9 actual grid, divided Under the default settings, the sub-blocks are square or
into nine 3\by\.3 blocks). You can also select sizes with rectangular. The default puzzle size is 3\by\.3 (a 9\by\.9 actual
rectangular blocks instead of square ones, such as 2\by\.3 (a grid, divided into nine 3\by\.3 blocks). You can also select sizes
6\by\.6 grid divided into six 3\by\.2 blocks). 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 If you select a puzzle size which requires more than 9 digits, the
additional digits will be letters of the alphabet. For example, if additional digits will be letters of the alphabet. For example, if
@ -930,12 +936,19 @@ rows, into which the main grid is divided. (The size of a block is
the inverse of this: for example, if you select 2 columns and 3 rows, the inverse of this: for example, if you select 2 columns and 3 rows,
each actual block will have 3 columns and 2 rows.) each actual block will have 3 columns and 2 rows.)
You can introduce an optional extra constraint on the puzzles, If you tick the \q{X} checkbox, Solo will apply the optional extra
requiring that the two main diagonals of the grid also contain one constraint that the two main diagonals of the grid also contain one
of every digit. (This is sometimes known as \q{Sudoku-X} in of every digit. (This is sometimes known as \q{Sudoku-X} in
newspapers.) In this mode, the squares on the two main diagonals newspapers.) In this mode, the squares on the two main diagonals
will be shaded slightly so that you know it's enabled. 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 You can also configure the type of symmetry shown in the generated
puzzles. More symmetry makes the puzzles look prettier but may also puzzles. More symmetry makes the puzzles look prettier but may also
make them easier, since the symmetry constraints can force more make them easier, since the symmetry constraints can force more

62
solo.c
View File

@ -3,26 +3,6 @@
* *
* TODO: * 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 * - reports from users are that `Trivial'-mode puzzles are still
* rather hard compared to newspapers' easy ones, so some better * rather hard compared to newspapers' easy ones, so some better
* low-end difficulty grading would be nice * low-end difficulty grading would be nice
@ -258,6 +238,9 @@ static int game_fetch_preset(int i, char **name, game_params **params)
{ "3x3 Advanced X", { 3, 3, SYMM_ROT2, DIFF_SET, TRUE } }, { "3x3 Advanced X", { 3, 3, SYMM_ROT2, DIFF_SET, TRUE } },
{ "3x3 Extreme", { 3, 3, SYMM_ROT2, DIFF_EXTREME, FALSE } }, { "3x3 Extreme", { 3, 3, SYMM_ROT2, DIFF_EXTREME, FALSE } },
{ "3x3 Unreasonable", { 3, 3, SYMM_ROT2, DIFF_RECURSIVE, 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 #ifndef SLOW_SYSTEM
{ "3x4 Basic", { 3, 4, SYMM_ROT2, DIFF_SIMPLE, FALSE } }, { "3x4 Basic", { 3, 4, SYMM_ROT2, DIFF_SIMPLE, FALSE } },
{ "4x4 Basic", { 4, 4, SYMM_ROT2, DIFF_SIMPLE, FALSE } }, { "4x4 Basic", { 4, 4, SYMM_ROT2, DIFF_SIMPLE, FALSE } },
@ -376,7 +359,7 @@ static config_item *game_configure(game_params *params)
config_item *ret; config_item *ret;
char buf[80]; char buf[80];
ret = snewn(6, config_item); ret = snewn(7, config_item);
ret[0].name = "Columns of sub-blocks"; ret[0].name = "Columns of sub-blocks";
ret[0].type = C_STRING; ret[0].type = C_STRING;
@ -395,22 +378,27 @@ static config_item *game_configure(game_params *params)
ret[2].sval = NULL; ret[2].sval = NULL;
ret[2].ival = params->xtype; ret[2].ival = params->xtype;
ret[3].name = "Symmetry"; ret[3].name = "Jigsaw (irregularly shaped sub-blocks)";
ret[3].type = C_CHOICES; ret[3].type = C_BOOLEAN;
ret[3].sval = ":None:2-way rotation:4-way rotation:2-way mirror:" 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:" "2-way diagonal mirror:4-way mirror:4-way diagonal mirror:"
"8-way mirror"; "8-way mirror";
ret[3].ival = params->symm; ret[4].ival = params->symm;
ret[4].name = "Difficulty"; ret[5].name = "Difficulty";
ret[4].type = C_CHOICES; ret[5].type = C_CHOICES;
ret[4].sval = ":Trivial:Basic:Intermediate:Advanced:Extreme:Unreasonable"; ret[5].sval = ":Trivial:Basic:Intermediate:Advanced:Extreme:Unreasonable";
ret[4].ival = params->diff; ret[5].ival = params->diff;
ret[5].name = NULL; ret[6].name = NULL;
ret[5].type = C_END; ret[6].type = C_END;
ret[5].sval = NULL; ret[6].sval = NULL;
ret[5].ival = 0; ret[6].ival = 0;
return ret; return ret;
} }
@ -422,8 +410,12 @@ static game_params *custom_params(config_item *cfg)
ret->c = atoi(cfg[0].sval); ret->c = atoi(cfg[0].sval);
ret->r = atoi(cfg[1].sval); ret->r = atoi(cfg[1].sval);
ret->xtype = cfg[2].ival; ret->xtype = cfg[2].ival;
ret->symm = cfg[3].ival; if (cfg[3].ival) {
ret->diff = cfg[4].ival; ret->c *= ret->r;
ret->r = 1;
}
ret->symm = cfg[4].ival;
ret->diff = cfg[5].ival;
return ret; return ret;
} }