mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 16:05:44 -07:00
Improve speed of grid generation: I've found something simple I can
do during construction which massively increases (by over a factor of four with default parameters) the probability that any given randomly generated grid will be uniquely solvable. [originally from svn r6096]
This commit is contained in:
113
dominosa.c
113
dominosa.c
@ -9,8 +9,34 @@
|
|||||||
*
|
*
|
||||||
* - improve solver so as to use more interesting forms of
|
* - improve solver so as to use more interesting forms of
|
||||||
* deduction
|
* deduction
|
||||||
* * odd area
|
*
|
||||||
|
* * rule out a domino placement if it would divide an unfilled
|
||||||
|
* region such that at least one resulting region had an odd
|
||||||
|
* area
|
||||||
|
* + use b.f.s. to determine the area of an unfilled region
|
||||||
|
* + a square is unfilled iff it has at least two possible
|
||||||
|
* placements, and two adjacent unfilled squares are part
|
||||||
|
* of the same region iff the domino placement joining
|
||||||
|
* them is possible
|
||||||
|
*
|
||||||
* * perhaps set analysis
|
* * perhaps set analysis
|
||||||
|
* + look at all unclaimed squares containing a given number
|
||||||
|
* + for each one, find the set of possible numbers that it
|
||||||
|
* can connect to (i.e. each neighbouring tile such that
|
||||||
|
* the placement between it and that neighbour has not yet
|
||||||
|
* been ruled out)
|
||||||
|
* + now proceed similarly to Solo set analysis: try to find
|
||||||
|
* a subset of the squares such that the union of their
|
||||||
|
* possible numbers is the same size as the subset. If so,
|
||||||
|
* rule out those possible numbers for all other squares.
|
||||||
|
* * important wrinkle: the double dominoes complicate
|
||||||
|
* matters. Connecting a number to itself uses up _two_
|
||||||
|
* of the unclaimed squares containing a number. Thus,
|
||||||
|
* when finding the initial subset we must never
|
||||||
|
* include two adjacent squares; and also, when ruling
|
||||||
|
* things out after finding the subset, we must be
|
||||||
|
* careful that we don't rule out precisely the domino
|
||||||
|
* placement that was _included_ in our set!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -530,6 +556,35 @@ static char *new_game_desc(game_params *params, random_state *rs,
|
|||||||
grid2 = snewn(wh, int);
|
grid2 = snewn(wh, int);
|
||||||
list = snewn(2*wh, int);
|
list = snewn(2*wh, int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I haven't been able to think of any particularly clever
|
||||||
|
* techniques for generating instances of Dominosa with a
|
||||||
|
* unique solution. Many of the deductions used in this puzzle
|
||||||
|
* are based on information involving half the grid at a time
|
||||||
|
* (`of all the 6s, exactly one is next to a 3'), so a strategy
|
||||||
|
* of partially solving the grid and then perturbing the place
|
||||||
|
* where the solver got stuck seems particularly likely to
|
||||||
|
* accidentally destroy the information which the solver had
|
||||||
|
* used in getting that far. (Contrast with, say, Mines, in
|
||||||
|
* which most deductions are local so this is an excellent
|
||||||
|
* strategy.)
|
||||||
|
*
|
||||||
|
* Therefore I resort to the basest of brute force methods:
|
||||||
|
* generate a random grid, see if it's solvable, throw it away
|
||||||
|
* and try again if not. My only concession to sophistication
|
||||||
|
* and cleverness is to at least _try_ not to generate obvious
|
||||||
|
* 2x2 ambiguous sections (see comment below in the domino-
|
||||||
|
* flipping section).
|
||||||
|
*
|
||||||
|
* During tests performed on 2005-07-15, I found that the brute
|
||||||
|
* force approach without that tweak had to throw away about 87
|
||||||
|
* grids on average (at the default n=6) before finding a
|
||||||
|
* unique one, or a staggering 379 at n=9; good job the
|
||||||
|
* generator and solver are fast! When I added the
|
||||||
|
* ambiguous-section avoidance, those numbers came down to 19
|
||||||
|
* and 26 respectively, which is a lot more sensible.
|
||||||
|
*/
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/*
|
/*
|
||||||
* To begin with, set grid[i] = i for all i to indicate
|
* To begin with, set grid[i] = i for all i to indicate
|
||||||
@ -783,7 +838,61 @@ static char *new_game_desc(game_params *params, random_state *rs,
|
|||||||
for (i = 0; i < wh; i++)
|
for (i = 0; i < wh; i++)
|
||||||
if (grid[i] > i) {
|
if (grid[i] > i) {
|
||||||
/* Optionally flip the domino round. */
|
/* Optionally flip the domino round. */
|
||||||
int flip = random_upto(rs, 2);
|
int flip = -1;
|
||||||
|
|
||||||
|
if (params->unique) {
|
||||||
|
int t1, t2;
|
||||||
|
/*
|
||||||
|
* If we're after a unique solution, we can do
|
||||||
|
* something here to improve the chances. If
|
||||||
|
* we're placing a domino so that it forms a
|
||||||
|
* 2x2 rectangle with one we've already placed,
|
||||||
|
* and if that domino and this one share a
|
||||||
|
* number, we can try not to put them so that
|
||||||
|
* the identical numbers are diagonally
|
||||||
|
* separated, because that automatically causes
|
||||||
|
* non-uniqueness:
|
||||||
|
*
|
||||||
|
* +---+ +-+-+
|
||||||
|
* |2 3| |2|3|
|
||||||
|
* +---+ -> | | |
|
||||||
|
* |4 2| |4|2|
|
||||||
|
* +---+ +-+-+
|
||||||
|
*/
|
||||||
|
t1 = i;
|
||||||
|
t2 = grid[i];
|
||||||
|
if (t2 == t1 + w) { /* this domino is vertical */
|
||||||
|
if (t1 % w > 0 &&/* and not on the left hand edge */
|
||||||
|
grid[t1-1] == t2-1 &&/* alongside one to left */
|
||||||
|
(grid2[t1-1] == list[j] || /* and has a number */
|
||||||
|
grid2[t1-1] == list[j+1] || /* in common */
|
||||||
|
grid2[t2-1] == list[j] ||
|
||||||
|
grid2[t2-1] == list[j+1])) {
|
||||||
|
if (grid2[t1-1] == list[j] ||
|
||||||
|
grid2[t2-1] == list[j+1])
|
||||||
|
flip = 0;
|
||||||
|
else
|
||||||
|
flip = 1;
|
||||||
|
}
|
||||||
|
} else { /* this domino is horizontal */
|
||||||
|
if (t1 / w > 0 &&/* and not on the top edge */
|
||||||
|
grid[t1-w] == t2-w &&/* alongside one above */
|
||||||
|
(grid2[t1-w] == list[j] || /* and has a number */
|
||||||
|
grid2[t1-w] == list[j+1] || /* in common */
|
||||||
|
grid2[t2-w] == list[j] ||
|
||||||
|
grid2[t2-w] == list[j+1])) {
|
||||||
|
if (grid2[t1-w] == list[j] ||
|
||||||
|
grid2[t2-w] == list[j+1])
|
||||||
|
flip = 0;
|
||||||
|
else
|
||||||
|
flip = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flip < 0)
|
||||||
|
flip = random_upto(rs, 2);
|
||||||
|
|
||||||
grid2[i] = list[j + flip];
|
grid2[i] = list[j + flip];
|
||||||
grid2[grid[i]] = list[j + 1 - flip];
|
grid2[grid[i]] = list[j + 1 - flip];
|
||||||
j += 2;
|
j += 2;
|
||||||
|
Reference in New Issue
Block a user