Exemple #1
0
static char *new_game_desc(game_params *params, random_state *rs,
			   char **aux, int interactive)
{
    int nballs = params->minballs, i;
    char *grid, *ret;
    unsigned char *bmp;

    if (params->maxballs > params->minballs)
        nballs += random_upto(rs, params->maxballs - params->minballs + 1);

    grid = snewn(params->w*params->h, char);
    memset(grid, 0, params->w * params->h * sizeof(char));

    bmp = snewn(nballs*2 + 2, unsigned char);
    memset(bmp, 0, (nballs*2 + 2) * sizeof(unsigned char));

    bmp[0] = params->w;
    bmp[1] = params->h;

    for (i = 0; i < nballs; i++) {
        int x, y;

        do {
            x = random_upto(rs, params->w);
            y = random_upto(rs, params->h);
        } while (grid[y*params->w + x]);

        grid[y*params->w + x] = 1;

        bmp[(i+1)*2 + 0] = x;
        bmp[(i+1)*2 + 1] = y;
#ifdef ANDROID
        if (android_cancelled()) {
            sfree(grid);
            sfree(bmp);
            return NULL;
        }
#endif
    }
    sfree(grid);

    obfuscate_bitmap(bmp, (nballs*2 + 2) * 8, FALSE);
    ret = bin2hex(bmp, nballs*2 + 2);
    sfree(bmp);

    return ret;
}
Exemple #2
0
static char *new_game_desc(game_params *params, random_state *rs,
                           char **aux, int interactive)
{
    const int w = params->w;
    const int h = params->h;
    const int sz = w * h;
    int *board = snewn(sz, int);
    int *randomize = snewn(sz, int);
    char *game_description = snewn(sz + 1, char);
    int i;

    for (i = 0; i < sz; ++i) {
        board[i] = EMPTY;
        randomize[i] = i;
    }

    make_board(board, w, h, rs);
#ifdef ANDROID
    if (android_cancelled()) {
	sfree(randomize);
	sfree(board);
	return NULL;
    }
#endif
    g_board = board;
    qsort(randomize, sz, sizeof (int), compare);
    minimize_clue_set(board, w, h, randomize);

    for (i = 0; i < sz; ++i) {
        assert(board[i] >= 0);
        assert(board[i] < 10);
        game_description[i] = board[i] + '0';
    }
    game_description[sz] = '\0';

/*
    solver(board, w, h, aux);
    print_board(board, w, h);
*/

    sfree(randomize);
    sfree(board);

    return game_description;
}
Exemple #3
0
/* generate a random valid board; uses validate_board. */
static void make_board(int *board, int w, int h, random_state *rs) {
    int *dsf;

    const unsigned int sz = w * h;

    /* w=h=2 is a special case which requires a number > max(w, h) */
    /* TODO prove that this is the case ONLY for w=h=2. */
    const int maxsize = min(max(max(w, h), 3), 9);

    /* Note that if 1 in {w, h} then it's impossible to have a region
     * of size > w*h, so the special case only affects w=h=2. */

    int nboards = 0;
    int i;

    assert(w >= 1);
    assert(h >= 1);

    assert(board);

    dsf = snew_dsf(sz); /* implicit dsf_init */

    /* I abuse the board variable: when generating the puzzle, it
     * contains a shuffled list of numbers {0, ..., nsq-1}. */
    for (i = 0; i < (int)sz; ++i) board[i] = i;

    while (1) {
	int change;
	++nboards;
	shuffle(board, sz, sizeof (int), rs);
	/* while the board can in principle be fixed */
	do {
#ifdef ANDROID
	    if (android_cancelled()) {
		sfree(dsf);
		return;
	    }
#endif
	    change = FALSE;
	    for (i = 0; i < (int)sz; ++i) {
		int a = SENTINEL;
		int b = SENTINEL;
		int c = SENTINEL;
		const int aa = dsf_canonify(dsf, board[i]);
		int cc = sz;
		int j;
		for (j = 0; j < 4; ++j) {
		    const int x = (board[i] % w) + dx[j];
		    const int y = (board[i] / w) + dy[j];
		    int bb;
		    if (x < 0 || x >= w || y < 0 || y >= h) continue;
		    bb = dsf_canonify(dsf, w*y + x);
		    if (aa == bb) continue;
		    else if (dsf_size(dsf, aa) == dsf_size(dsf, bb)) {
			a = aa;
			b = bb;
			c = cc;
		    } else if (cc == sz) c = cc = bb;
		}
		if (a != SENTINEL) {
		    a = dsf_canonify(dsf, a);
		    assert(a != dsf_canonify(dsf, b));
		    if (c != sz) assert(a != dsf_canonify(dsf, c));
		    dsf_merge(dsf, a, c == sz? b: c);
		    /* if repair impossible; make a new board */
		    if (dsf_size(dsf, a) > maxsize) goto retry;
		    change = TRUE;
		}
	    }
	} while (change);

	for (i = 0; i < (int)sz; ++i) board[i] = dsf_size(dsf, i);

	sfree(dsf);
	printv("returning board number %d\n", nboards);
	return;

    retry:
	dsf_init(dsf, sz);
    }
    assert(FALSE); /* unreachable */
}
Exemple #4
0
static char *new_game_desc(game_params *params, random_state *rs,
			   char **aux, int interactive)
{
    int n = params->n, w = n+2, h = n+1, wh = w*h;
    int *grid, *grid2, *list;
    int i, j, k, len;
    char *ret;

    /*
     * Allocate space in which to lay the grid out.
     */
    grid = snewn(wh, int);
    grid2 = snewn(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 {
        domino_layout_prealloc(w, h, rs, grid, grid2, list);

        /*
         * Now we have a complete layout covering the whole
         * rectangle with dominoes. So shuffle the actual domino
         * values and fill the rectangle with numbers.
         */
        k = 0;
        for (i = 0; i <= params->n; i++)
            for (j = 0; j <= i; j++) {
                list[k++] = i;
                list[k++] = j;
            }
        shuffle(list, k/2, 2*sizeof(*list), rs);
        j = 0;
        for (i = 0; i < wh; i++)
            if (grid[i] > i) {
                /* Optionally flip the domino round. */
                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[grid[i]] = list[j + 1 - flip];
                j += 2;
            }
        assert(j == k);
#ifdef ANDROID
        if (android_cancelled()) {
            sfree(list);
            sfree(grid2);
            sfree(grid);
            return NULL;
        }
#endif
    } while (params->unique && solver(w, h, n, grid2, NULL) > 1);

#ifdef GENERATION_DIAGNOSTICS
    for (j = 0; j < h; j++) {
        for (i = 0; i < w; i++) {
            putchar('0' + grid2[j*w+i]);
        }
        putchar('\n');
    }
    putchar('\n');
#endif

    /*
     * Encode the resulting game state.
     * 
     * Our encoding is a string of digits. Any number greater than
     * 9 is represented by a decimal integer within square
     * brackets. We know there are n+2 of every number (it's paired
     * with each number from 0 to n inclusive, and one of those is
     * itself so that adds another occurrence), so we can work out
     * the string length in advance.
     */

    /*
     * To work out the total length of the decimal encodings of all
     * the numbers from 0 to n inclusive:
     *  - every number has a units digit; total is n+1.
     *  - all numbers above 9 have a tens digit; total is max(n+1-10,0).
     *  - all numbers above 99 have a hundreds digit; total is max(n+1-100,0).
     *  - and so on.
     */
    len = n+1;
    for (i = 10; i <= n; i *= 10)
	len += max(n + 1 - i, 0);
    /* Now add two square brackets for each number above 9. */
    len += 2 * max(n + 1 - 10, 0);
    /* And multiply by n+2 for the repeated occurrences of each number. */
    len *= n+2;

    /*
     * Now actually encode the string.
     */
    ret = snewn(len+1, char);
    j = 0;
    for (i = 0; i < wh; i++) {
        k = grid2[i];
        if (k < 10)
            ret[j++] = '0' + k;
        else
            j += sprintf(ret+j, "[%d]", k);
        assert(j <= len);
    }
    assert(j == len);
    ret[j] = '\0';

    /*
     * Encode the solved state as an aux_info.
     */
    {
	char *auxinfo = snewn(wh+1, char);

	for (i = 0; i < wh; i++) {
	    int v = grid[i];
	    auxinfo[i] = (v == i+1 ? 'L' : v == i-1 ? 'R' :
			  v == i+w ? 'T' : v == i-w ? 'B' : '.');
	}
	auxinfo[wh] = '\0';

	*aux = auxinfo;
    }

    sfree(list);
    sfree(grid2);
    sfree(grid);

    return ret;
}