X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=loopy.c;h=7d3436aacbc5862ab2d657f93c4b0c828143e4f6;hb=a0a581c8b5422bf0c5ed3fde6aa25811e4eb89fc;hp=bc6ebb306040e7f2387240ef410043a137985b90;hpb=a7dc17c4258837b0ee3927f1db5e1c02acee5cc3;p=sgt-puzzles.git diff --git a/loopy.c b/loopy.c index bc6ebb3..7d3436a 100644 --- a/loopy.c +++ b/loopy.c @@ -513,22 +513,15 @@ static game_params *dup_params(const game_params *params) return ret; } -static const game_params presets[] = { +static const game_params loopy_presets_top[] = { #ifdef SMALL_SCREEN { 7, 7, DIFF_EASY, LOOPY_GRID_SQUARE }, { 7, 7, DIFF_NORMAL, LOOPY_GRID_SQUARE }, { 7, 7, DIFF_HARD, LOOPY_GRID_SQUARE }, - { 7, 7, DIFF_HARD, LOOPY_GRID_HONEYCOMB }, { 7, 7, DIFF_HARD, LOOPY_GRID_TRIANGULAR }, { 5, 5, DIFF_HARD, LOOPY_GRID_SNUBSQUARE }, { 7, 7, DIFF_HARD, LOOPY_GRID_CAIRO }, - { 5, 4, DIFF_HARD, LOOPY_GRID_GREATHEXAGONAL }, - { 5, 5, DIFF_HARD, LOOPY_GRID_OCTAGONAL }, { 5, 5, DIFF_HARD, LOOPY_GRID_KITE }, - { 3, 3, DIFF_HARD, LOOPY_GRID_FLORET }, - { 3, 3, DIFF_HARD, LOOPY_GRID_DODECAGONAL }, - { 3, 3, DIFF_HARD, LOOPY_GRID_GREATDODECAGONAL }, - { 3, 2, DIFF_HARD, LOOPY_GRID_GREATGREATDODECAGONAL }, { 6, 6, DIFF_HARD, LOOPY_GRID_PENROSE_P2 }, { 6, 6, DIFF_HARD, LOOPY_GRID_PENROSE_P3 }, #else @@ -538,38 +531,64 @@ static const game_params presets[] = { { 10, 10, DIFF_NORMAL, LOOPY_GRID_SQUARE }, { 7, 7, DIFF_HARD, LOOPY_GRID_SQUARE }, { 10, 10, DIFF_HARD, LOOPY_GRID_SQUARE }, - { 10, 10, DIFF_HARD, LOOPY_GRID_HONEYCOMB }, { 12, 10, DIFF_HARD, LOOPY_GRID_TRIANGULAR }, { 7, 7, DIFF_HARD, LOOPY_GRID_SNUBSQUARE }, { 9, 9, DIFF_HARD, LOOPY_GRID_CAIRO }, + { 5, 5, DIFF_HARD, LOOPY_GRID_KITE }, + { 10, 10, DIFF_HARD, LOOPY_GRID_PENROSE_P2 }, + { 10, 10, DIFF_HARD, LOOPY_GRID_PENROSE_P3 }, +#endif +}; + +static const game_params loopy_presets_more[] = { +#ifdef SMALL_SCREEN + { 7, 7, DIFF_HARD, LOOPY_GRID_HONEYCOMB }, + { 5, 4, DIFF_HARD, LOOPY_GRID_GREATHEXAGONAL }, + { 5, 5, DIFF_HARD, LOOPY_GRID_OCTAGONAL }, + { 3, 3, DIFF_HARD, LOOPY_GRID_FLORET }, + { 3, 3, DIFF_HARD, LOOPY_GRID_DODECAGONAL }, + { 3, 3, DIFF_HARD, LOOPY_GRID_GREATDODECAGONAL }, + { 3, 2, DIFF_HARD, LOOPY_GRID_GREATGREATDODECAGONAL }, +#else + { 10, 10, DIFF_HARD, LOOPY_GRID_HONEYCOMB }, { 5, 4, DIFF_HARD, LOOPY_GRID_GREATHEXAGONAL }, { 7, 7, DIFF_HARD, LOOPY_GRID_OCTAGONAL }, - { 5, 5, DIFF_HARD, LOOPY_GRID_KITE }, { 5, 5, DIFF_HARD, LOOPY_GRID_FLORET }, { 5, 4, DIFF_HARD, LOOPY_GRID_DODECAGONAL }, { 5, 4, DIFF_HARD, LOOPY_GRID_GREATDODECAGONAL }, { 5, 3, DIFF_HARD, LOOPY_GRID_GREATGREATDODECAGONAL }, - { 10, 10, DIFF_HARD, LOOPY_GRID_PENROSE_P2 }, - { 10, 10, DIFF_HARD, LOOPY_GRID_PENROSE_P3 }, #endif }; -static int game_fetch_preset(int i, char **name, game_params **params) +static void preset_menu_add_preset_with_title(struct preset_menu *menu, + const game_params *params) { - game_params *tmppar; char buf[80]; + game_params *dup_params; - if (i < 0 || i >= lenof(presets)) - return FALSE; + sprintf(buf, "%dx%d %s - %s", params->h, params->w, + gridnames[params->type], diffnames[params->diff]); - tmppar = snew(game_params); - *tmppar = presets[i]; - *params = tmppar; - sprintf(buf, "%dx%d %s - %s", tmppar->h, tmppar->w, - gridnames[tmppar->type], diffnames[tmppar->diff]); - *name = dupstr(buf); + dup_params = snew(game_params); + *dup_params = *params; - return TRUE; + preset_menu_add_preset(menu, dupstr(buf), dup_params); +} + +static struct preset_menu *game_preset_menu(void) +{ + struct preset_menu *top, *more; + int i; + + top = preset_menu_new(); + for (i = 0; i < lenof(loopy_presets_top); i++) + preset_menu_add_preset_with_title(top, &loopy_presets_top[i]); + + more = preset_menu_add_submenu(top, dupstr("More...")); + for (i = 0; i < lenof(loopy_presets_more); i++) + preset_menu_add_preset_with_title(more, &loopy_presets_more[i]); + + return top; } static void free_params(game_params *params) @@ -2928,7 +2947,8 @@ static char *interpret_move(const game_state *state, game_ui *ui, grid *g = state->game_grid; grid_edge *e; int i; - char *ret, buf[80]; + char *movebuf; + int movelen, movesize; char button_char = ' '; enum line_state old_state; @@ -2990,11 +3010,83 @@ static char *interpret_move(const game_state *state, game_ui *ui, return NULL; } + movelen = 0; + movesize = 80; + movebuf = snewn(movesize, char); + movelen = sprintf(movebuf, "%d%c", i, (int)button_char); + { + static enum { OFF, FIXED, ADAPTIVE, DUNNO } autofollow = DUNNO; + if (autofollow == DUNNO) { + const char *env = getenv("LOOPY_AUTOFOLLOW"); + if (env && !strcmp(env, "off")) + autofollow = OFF; + else if (env && !strcmp(env, "fixed")) + autofollow = FIXED; + else if (env && !strcmp(env, "adaptive")) + autofollow = ADAPTIVE; + else + autofollow = OFF; + } + + if (autofollow != OFF) { + int dotid; + for (dotid = 0; dotid < 2; dotid++) { + grid_dot *dot = (dotid == 0 ? e->dot1 : e->dot2); + grid_edge *e_this = e; + + while (1) { + int j, n_found; + grid_edge *e_next = NULL; + + for (j = n_found = 0; j < dot->order; j++) { + grid_edge *e_candidate = dot->edges[j]; + int i_candidate = e_candidate - g->edges; + if (e_candidate != e_this && + (autofollow == FIXED || + state->lines[i] == LINE_NO || + state->lines[i_candidate] != LINE_NO)) { + e_next = e_candidate; + n_found++; + } + } - sprintf(buf, "%d%c", i, (int)button_char); - ret = dupstr(buf); + if (n_found != 1 || + state->lines[e_next - g->edges] != state->lines[i]) + break; + + if (e_next == e) { + /* + * Special case: we might have come all the + * way round a loop and found our way back to + * the same edge we started from. In that + * situation, we must terminate not only this + * while loop, but the 'for' outside it that + * was tracing in both directions from the + * starting edge, because if we let it trace + * in the second direction then we'll only + * find ourself traversing the same loop in + * the other order and generate an encoded + * move string that mentions the same set of + * edges twice. + */ + goto autofollow_done; + } - return ret; + dot = (e_next->dot1 != dot ? e_next->dot1 : e_next->dot2); + if (movelen > movesize - 40) { + movesize = movesize * 5 / 4 + 128; + movebuf = sresize(movebuf, movesize, char); + } + e_this = e_next; + movelen += sprintf(movebuf+movelen, "%d%c", + (int)(e_this - g->edges), button_char); + } + } + autofollow_done:; + } + } + + return sresize(movebuf, movelen+1, char); } static game_state *execute_move(const game_state *state, const char *move) @@ -3548,7 +3640,7 @@ static void game_print(drawing *dr, const game_state *state, int tilesize) const struct game thegame = { "Loopy", "games.loopy", "loopy", default_params, - game_fetch_preset, NULL, + NULL, game_preset_menu, decode_params, encode_params, free_params,