X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/481628b3d92ae1c7738bb51fe24a236245cd3d54..e8b7bbe145c3ebd4b63c10c3773f4996e7045680:/unequal.c diff --git a/unequal.c b/unequal.c index 81720e4..26fcd41 100644 --- a/unequal.c +++ b/unequal.c @@ -229,7 +229,7 @@ static char *validate_params(game_params *params, int full) if (params->order < 3 || params->order > 32) return "Order must be between 3 and 32"; if (params->diff >= DIFFCOUNT) - return "Unknown difficulty rating."; + return "Unknown difficulty rating"; return NULL; } @@ -408,6 +408,11 @@ static int c2n(int c, int order) { return -1; } +static int game_can_format_as_text_now(game_params *params) +{ + return TRUE; +} + static char *game_text_format(game_state *state) { int x, y, len, n; @@ -880,7 +885,7 @@ static int gg_best_clue(game_state *state, int *scratch, digit *latin) } #endif - for (i = 0; i < ls; i++) { + for (i = ls; i-- > 0 ;) { if (!gg_place_clue(state, scratch[i], latin, 1)) continue; loc = scratch[i] / 5; @@ -896,7 +901,7 @@ static int gg_best_clue(game_state *state, int *scratch, digit *latin) best = i; maxposs = nposs; minclues = nclues; #ifdef STANDALONE_SOLVER if (solver_show_working) - printf("gg_best_clue: b%d (%d,%d) new best [%d poss, %d clues].", + printf("gg_best_clue: b%d (%d,%d) new best [%d poss, %d clues].\n", best, x, y, nposs, nclues); #endif } @@ -971,7 +976,8 @@ static void game_strip(game_state *new, int *scratch, digit *latin, gg_solved++; if (solver_state(copy, difficulty) != 1) { /* put clue back, we can't solve without it. */ - assert(gg_place_clue(new, scratch[i], latin, 0) == 1); + int ret = gg_place_clue(new, scratch[i], latin, 0); + assert(ret == 1); } else { #ifdef STANDALONE_SOLVER if (solver_show_working) @@ -995,14 +1001,15 @@ static char *new_game_desc(game_params *params, random_state *rs, { digit *sq = NULL; int i, x, y, retlen, k, nsol; - int o2 = params->order * params->order, ntries = 0; + int o2 = params->order * params->order, ntries = 1; int *scratch, lscratch = o2*5; char *ret, buf[80]; game_state *state = blank_game(params->order); /* Generate a list of 'things to strip' (randomised later) */ scratch = snewn(lscratch, int); - for (i = 0; i < lscratch; i++) scratch[i] = i; + /* Put the numbers (4 mod 5) before the inequalities (0-3 mod 5) */ + for (i = 0; i < lscratch; i++) scratch[i] = (i%o2)*5 + 4 - (i/o2); generate: #ifdef STANDALONE_SOLVER @@ -1013,7 +1020,9 @@ generate: if (sq) sfree(sq); sq = latin_generate(params->order, rs); latin_debug(sq, params->order); - shuffle(scratch, lscratch, sizeof(int), rs); + /* Separately shuffle the numeric and inequality clues */ + shuffle(scratch, lscratch/5, sizeof(int), rs); + shuffle(scratch+lscratch/5, 4*lscratch/5, sizeof(int), rs); memset(state->nums, 0, o2 * sizeof(digit)); memset(state->flags, 0, o2 * sizeof(unsigned int)); @@ -1030,7 +1039,7 @@ generate: if (nsol > 0) { #ifdef STANDALONE_SOLVER if (solver_show_working) - printf("game_assemble: puzzle as generated is too easy."); + printf("game_assemble: puzzle as generated is too easy.\n"); #endif if (ntries < MAXTRIES) { ntries++; @@ -1038,7 +1047,7 @@ generate: } #ifdef STANDALONE_SOLVER if (solver_show_working) - printf("Unable to generate %s %dx%d after %d attempts.", + printf("Unable to generate %s %dx%d after %d attempts.\n", unequal_diffnames[params->diff], params->order, params->order, MAXTRIES); #endif @@ -1047,7 +1056,7 @@ generate: } #ifdef STANDALONE_SOLVER if (solver_show_working) - printf("new_game_desc: generated %s puzzle; %d attempts (%d solver).", + printf("new_game_desc: generated %s puzzle; %d attempts (%d solver).\n", unequal_diffnames[params->diff], ntries, gg_solved); #endif @@ -1201,18 +1210,16 @@ static char *solve_game(game_state *state, game_state *currstate, */ struct game_ui { - int hx, hy, hpencil; /* as for solo.c, highlight pos and type */ - int cx, cy; /* cursor position (-1,-1 for none) */ + int hx, hy; /* as for solo.c, highlight pos */ + int hshow, hpencil, hcursor; /* show state, type, and ?cursor. */ }; static game_ui *new_ui(game_state *state) { game_ui *ui = snew(game_ui); - ui->hx = ui->hy = -1; - ui->hpencil = 0; - - ui->cx = ui->cy = -1; + ui->hx = ui->hy = 0; + ui->hpencil = ui->hshow = ui->hcursor = 0; return ui; } @@ -1237,20 +1244,19 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, /* See solo.c; if we were pencil-mode highlighting and * somehow a square has just been properly filled, cancel * pencil mode. */ - if (ui->hx >= 0 && ui->hy >= 0 && ui->hpencil && + if (ui->hshow && ui->hpencil && !ui->hcursor && GRID(newstate, nums, ui->hx, ui->hy) != 0) { - ui->hx = ui->hy = -1; + ui->hshow = 0; } } struct game_drawstate { int tilesize, order, started; - digit *nums; /* copy of nums, o^2 */ - unsigned char *hints; /* copy of hints, o^3 */ + digit *nums; /* copy of nums, o^2 */ + unsigned char *hints; /* copy of hints, o^3 */ unsigned int *flags; /* o^2 */ - int hx, hy, hpencil; - int cx, cy; + int hx, hy, hshow, hpencil; /* as for game_ui. */ int hflash; }; @@ -1262,34 +1268,51 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds, button &= ~MOD_MASK; - if (x >= 0 && x < ds->order && y >= 0 && y < ds->order) { + if (x >= 0 && x < ds->order && ((ox - COORD(x)) <= TILE_SIZE) && + y >= 0 && y < ds->order && ((oy - COORD(y)) <= TILE_SIZE)) { if (button == LEFT_BUTTON) { /* normal highlighting for non-immutable squares */ if (GRID(state, flags, x, y) & F_IMMUTABLE) - ui->hx = ui->hy = -1; - else if (x == ui->hx && y == ui->hy && ui->hpencil == 0) - ui->hx = ui->hy = -1; + ui->hshow = 0; + else if (x == ui->hx && y == ui->hy && + ui->hshow && ui->hpencil == 0) + ui->hshow = 0; else { ui->hx = x; ui->hy = y; ui->hpencil = 0; + ui->hshow = 1; } + ui->hcursor = 0; return ""; } if (button == RIGHT_BUTTON) { /* pencil highlighting for non-filled squares */ if (GRID(state, nums, x, y) != 0) - ui->hx = ui->hy = -1; - else if (x == ui->hx && y == ui->hy && ui->hpencil) - ui->hx = ui->hy = -1; + ui->hshow = 0; + else if (x == ui->hx && y == ui->hy && + ui->hshow && ui->hpencil) + ui->hshow = 0; else { ui->hx = x; ui->hy = y; ui->hpencil = 1; + ui->hshow = 1; } + ui->hcursor = 0; return ""; } } - if (button == 'H' || button == 'h') - return dupstr("H"); - if (ui->hx != -1 && ui->hy != -1) { + if (IS_CURSOR_MOVE(button)) { + move_cursor(button, &ui->hx, &ui->hy, ds->order, ds->order, 0); + ui->hshow = ui->hcursor = 1; + return ""; + } + if (ui->hshow && IS_CURSOR_SELECT(button)) { + ui->hpencil = 1 - ui->hpencil; + ui->hcursor = 1; + return ""; + } + + + if (ui->hshow) { debug(("button %d, cbutton %d", button, (int)((char)button))); n = c2n(button, state->order); @@ -1309,17 +1332,23 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds, sprintf(buf, "%c%d,%d,%d", (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); - ui->hx = ui->hy = -1; + if (!ui->hcursor) ui->hshow = 0; return dupstr(buf); } + + if (button == 'H' || button == 'h') + return dupstr("H"); + if (button == 'M' || button == 'm') + return dupstr("M"); + return NULL; } static game_state *execute_move(game_state *state, char *move) { game_state *ret = NULL; - int x, y, n, i; + int x, y, n, i, rc; debug(("execute_move: %s", move)); @@ -1355,7 +1384,18 @@ static game_state *execute_move(game_state *state, char *move) p++; } if (*p) goto badmove; - assert(check_complete(ret->nums, ret, 1) > 0); + rc = check_complete(ret->nums, ret, 1); + assert(rc > 0); + return ret; + } else if (move[0] == 'M') { + ret = dup_game(state); + for (x = 0; x < state->order; x++) { + for (y = 0; y < state->order; y++) { + for (n = 0; n < state->order; n++) { + HINT(ret, x, y, n) = 1; + } + } + } return ret; } else if (move[0] == 'H') { return solver_hint(state, NULL, DIFF_EASY, DIFF_EASY); @@ -1433,8 +1473,8 @@ static game_drawstate *game_new_drawstate(drawing *dr, game_state *state) memset(ds->hints, 0, o3); memset(ds->flags, 0, o2*sizeof(unsigned int)); - ds->hx = ds->hy = ds->cx = ds->cy = -1; - ds->started = ds->hpencil = ds->hflash = 0; + ds->hx = ds->hy = 0; + ds->started = ds->hshow = ds->hpencil = ds->hflash = 0; return ds; } @@ -1484,13 +1524,12 @@ static void draw_gts(drawing *dr, game_drawstate *ds, int ox, int oy, static void draw_furniture(drawing *dr, game_drawstate *ds, game_state *state, game_ui *ui, int x, int y, int hflash) { - int ox = COORD(x), oy = COORD(y), bg, hon, con; + int ox = COORD(x), oy = COORD(y), bg, hon; unsigned int f = GRID(state, flags, x, y); bg = hflash ? COL_HIGHLIGHT : COL_BACKGROUND; - hon = (x == ui->hx && y == ui->hy); - con = (x == ui->cx && y == ui->cy); + hon = (ui->hshow && x == ui->hx && y == ui->hy); /* Clear square. */ draw_rect(dr, ox, oy, TILE_SIZE, TILE_SIZE, @@ -1509,8 +1548,7 @@ static void draw_furniture(drawing *dr, game_drawstate *ds, game_state *state, } /* Draw the square outline (which is the cursor, if we're the cursor). */ - draw_rect_outline(dr, ox, oy, TILE_SIZE, TILE_SIZE, - con ? COL_GUESS : COL_GRID); + draw_rect_outline(dr, ox, oy, TILE_SIZE, TILE_SIZE, COL_GRID); draw_update(dr, ox, oy, TILE_SIZE, TILE_SIZE); @@ -1575,7 +1613,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, game_state *state, int dir, game_ui *ui, float animtime, float flashtime) { - int x, y, i, hchanged = 0, cchanged = 0, stale, hflash = 0; + int x, y, i, hchanged = 0, stale, hflash = 0; debug(("highlight old (%d,%d), new (%d,%d)", ds->hx, ds->hy, ui->hx, ui->hy)); @@ -1587,10 +1625,9 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, draw_rect(dr, 0, 0, DRAW_SIZE, DRAW_SIZE, COL_BACKGROUND); draw_update(dr, 0, 0, DRAW_SIZE, DRAW_SIZE); } - if (ds->hx != ui->hx || ds->hy != ui->hy || ds->hpencil != ui->hpencil) + if (ds->hx != ui->hx || ds->hy != ui->hy || + ds->hshow != ui->hshow || ds->hpencil != ui->hpencil) hchanged = 1; - if (ds->cx != ui->cx || ds->cy != ui->cy) - cchanged = 1; for (x = 0; x < ds->order; x++) { for (y = 0; y < ds->order; y++) { @@ -1606,11 +1643,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, (x == ds->hx && y == ds->hy)) stale = 1; } - if (cchanged) { - if ((x == ui->cx && y == ui->cy) || - (x == ds->cx && y == ds->cy)) - stale = 1; - } if (GRID(state, nums, x, y) != GRID(ds, nums, x, y)) { GRID(ds, nums, x, y) = GRID(state, nums, x, y); @@ -1639,8 +1671,10 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, } } } - ds->hx = ui->hx; ds->hy = ui->hy; ds->hpencil = ui->hpencil; - ds->cx = ui->cx; ds->cy = ui->cy; + ds->hx = ui->hx; ds->hy = ui->hy; + ds->hshow = ui->hshow; + ds->hpencil = ui->hpencil; + ds->started = 1; ds->hflash = hflash; } @@ -1730,7 +1764,7 @@ const struct game thegame = { dup_game, free_game, TRUE, solve_game, - TRUE, game_text_format, + TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, @@ -1748,7 +1782,7 @@ const struct game thegame = { TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, - 0, /* flags */ + REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ }; /* ----------------------------------------------------------------------