mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 08:01:30 -07:00
Net: preference for how loop highlighting interacts with locking.
Net's loop highlighting detects any loop in the current state of the grid. I've occasionally found that to be a bit of a spoiler, since sometimes it can point out a deduction I should make before I've figured it out for myself - e.g. when I've just locked all but two of the squares involved in the loop, and the last two _just happen_ to be oriented so as to complete the loop. In that situation I'd prefer if the loop _didn't_ immediately light up and point out to me that I need to arrange that those squares aren't connected to each other. The simple answer is to only count edges connecting two _locked_ squares, for the purposes of loop detection. But this is obviously unacceptable to some players - in particular, those who play without the locking feature at all. So it should be a user preference.
This commit is contained in:
69
net.c
69
net.c
@ -1135,7 +1135,8 @@ static void perturb(int w, int h, unsigned char *tiles, bool wrapping,
|
||||
|
||||
static int *compute_loops_inner(int w, int h, bool wrapping,
|
||||
const unsigned char *tiles,
|
||||
const unsigned char *barriers);
|
||||
const unsigned char *barriers,
|
||||
bool include_unlocked_squares);
|
||||
|
||||
static char *new_game_desc(const game_params *params, random_state *rs,
|
||||
char **aux, bool interactive)
|
||||
@ -1464,7 +1465,8 @@ static char *new_game_desc(const game_params *params, random_state *rs,
|
||||
*/
|
||||
prev_loopsquares = w*h+1;
|
||||
while (1) {
|
||||
loops = compute_loops_inner(w, h, params->wrapping, tiles, NULL);
|
||||
loops = compute_loops_inner(w, h, params->wrapping, tiles, NULL,
|
||||
true);
|
||||
this_loopsquares = 0;
|
||||
for (i = 0; i < w*h; i++) {
|
||||
if (loops[i]) {
|
||||
@ -1919,6 +1921,7 @@ struct net_neighbour_ctx {
|
||||
int w, h;
|
||||
const unsigned char *tiles, *barriers;
|
||||
int i, n, neighbours[4];
|
||||
bool include_unlocked_squares;
|
||||
};
|
||||
static int net_neighbour(int vertex, void *vctx)
|
||||
{
|
||||
@ -1939,6 +1942,9 @@ static int net_neighbour(int vertex, void *vctx)
|
||||
continue;
|
||||
OFFSETWH(x1, y1, x, y, dir, ctx->w, ctx->h);
|
||||
v1 = y1 * ctx->w + x1;
|
||||
if (!ctx->include_unlocked_squares &&
|
||||
!(tile & ctx->tiles[v1] & LOCKED))
|
||||
continue;
|
||||
if (ctx->tiles[v1] & F(dir))
|
||||
ctx->neighbours[ctx->n++] = v1;
|
||||
}
|
||||
@ -1952,32 +1958,39 @@ static int net_neighbour(int vertex, void *vctx)
|
||||
|
||||
static int *compute_loops_inner(int w, int h, bool wrapping,
|
||||
const unsigned char *tiles,
|
||||
const unsigned char *barriers)
|
||||
const unsigned char *barriers,
|
||||
bool include_unlocked_squares)
|
||||
{
|
||||
struct net_neighbour_ctx ctx;
|
||||
struct findloopstate *fls;
|
||||
int *loops;
|
||||
int x, y;
|
||||
int x, y, v;
|
||||
|
||||
fls = findloop_new_state(w*h);
|
||||
ctx.w = w;
|
||||
ctx.h = h;
|
||||
ctx.tiles = tiles;
|
||||
ctx.barriers = barriers;
|
||||
ctx.include_unlocked_squares = include_unlocked_squares;
|
||||
findloop_run(fls, w*h, net_neighbour, &ctx);
|
||||
|
||||
loops = snewn(w*h, int);
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
for (x = 0; x < w; x++) {
|
||||
int x1, y1, dir;
|
||||
int x1, y1, v1, dir;
|
||||
int flags = 0;
|
||||
|
||||
v = y * w + x;
|
||||
for (dir = 1; dir < 0x10; dir <<= 1) {
|
||||
if ((tiles[y*w+x] & dir) &&
|
||||
if ((tiles[v] & dir) &&
|
||||
!(barriers && (barriers[y*w+x] & dir))) {
|
||||
OFFSETWH(x1, y1, x, y, dir, w, h);
|
||||
if ((tiles[y1*w+x1] & F(dir)) &&
|
||||
v1 = y1 * w + x1;
|
||||
if (!include_unlocked_squares &&
|
||||
!(tiles[v] & tiles[v1] & LOCKED))
|
||||
continue;
|
||||
if ((tiles[v1] & F(dir)) &&
|
||||
findloop_is_loop_edge(fls, y*w+x, y1*w+x1))
|
||||
flags |= ERR(dir);
|
||||
}
|
||||
@ -1990,10 +2003,12 @@ static int *compute_loops_inner(int w, int h, bool wrapping,
|
||||
return loops;
|
||||
}
|
||||
|
||||
static int *compute_loops(const game_state *state)
|
||||
static int *compute_loops(const game_state *state,
|
||||
bool include_unlocked_squares)
|
||||
{
|
||||
return compute_loops_inner(state->width, state->height, state->wrapping,
|
||||
state->tiles, state->imm->barriers);
|
||||
state->tiles, state->imm->barriers,
|
||||
include_unlocked_squares);
|
||||
}
|
||||
|
||||
struct game_ui {
|
||||
@ -2006,6 +2021,8 @@ struct game_ui {
|
||||
int dragtilex, dragtiley, dragstartx, dragstarty;
|
||||
bool dragged;
|
||||
#endif
|
||||
|
||||
bool unlocked_loops;
|
||||
};
|
||||
|
||||
static game_ui *new_ui(const game_state *state)
|
||||
@ -2013,6 +2030,10 @@ static game_ui *new_ui(const game_state *state)
|
||||
void *seed;
|
||||
int seedsize;
|
||||
game_ui *ui = snew(game_ui);
|
||||
|
||||
ui->unlocked_loops = true;
|
||||
|
||||
if (state) {
|
||||
ui->org_x = ui->org_y = 0;
|
||||
ui->cur_x = ui->cx = state->width / 2;
|
||||
ui->cur_y = ui->cy = state->height / 2;
|
||||
@ -2020,12 +2041,16 @@ static game_ui *new_ui(const game_state *state)
|
||||
get_random_seed(&seed, &seedsize);
|
||||
ui->rs = random_new(seed, seedsize);
|
||||
sfree(seed);
|
||||
} else {
|
||||
ui->rs = NULL;
|
||||
}
|
||||
|
||||
return ui;
|
||||
}
|
||||
|
||||
static void free_ui(game_ui *ui)
|
||||
{
|
||||
if (ui->rs)
|
||||
random_free(ui->rs);
|
||||
sfree(ui);
|
||||
}
|
||||
@ -2060,6 +2085,28 @@ static void decode_ui(game_ui *ui, const char *encoding,
|
||||
}
|
||||
}
|
||||
|
||||
static config_item *get_prefs(game_ui *ui)
|
||||
{
|
||||
config_item *ret;
|
||||
|
||||
ret = snewn(2, config_item);
|
||||
|
||||
ret[0].name = "Highlight loops involving unlocked squares";
|
||||
ret[0].kw = "unlocked-loops";
|
||||
ret[0].type = C_BOOLEAN;
|
||||
ret[0].u.boolean.bval = ui->unlocked_loops;
|
||||
|
||||
ret[1].name = NULL;
|
||||
ret[1].type = C_END;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void set_prefs(game_ui *ui, const config_item *cfg)
|
||||
{
|
||||
ui->unlocked_loops = cfg[0].u.boolean.bval;
|
||||
}
|
||||
|
||||
static void game_changed_state(game_ui *ui, const game_state *oldstate,
|
||||
const game_state *newstate)
|
||||
{
|
||||
@ -2891,7 +2938,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
|
||||
* of barriers.
|
||||
*/
|
||||
active = compute_active(state, ui->cx, ui->cy);
|
||||
loops = compute_loops(state);
|
||||
loops = compute_loops(state, ui->unlocked_loops);
|
||||
|
||||
for (dy = -1; dy < ds->height+1; dy++) {
|
||||
for (dx = -1; dx < ds->width+1; dx++) {
|
||||
@ -3270,7 +3317,7 @@ const struct game thegame = {
|
||||
free_game,
|
||||
true, solve_game,
|
||||
false, NULL, NULL, /* can_format_as_text_now, text_format */
|
||||
NULL, NULL, /* get_prefs, set_prefs */
|
||||
get_prefs, set_prefs,
|
||||
new_ui,
|
||||
free_ui,
|
||||
encode_ui,
|
||||
|
Reference in New Issue
Block a user