diff options
Diffstat (limited to 'apps/plugins/puzzles/src/guess.c')
-rw-r--r-- | apps/plugins/puzzles/src/guess.c | 221 |
1 files changed, 129 insertions, 92 deletions
diff --git a/apps/plugins/puzzles/src/guess.c b/apps/plugins/puzzles/src/guess.c index a501579442..5c5f941230 100644 --- a/apps/plugins/puzzles/src/guess.c +++ b/apps/plugins/puzzles/src/guess.c | |||
@@ -7,7 +7,11 @@ | |||
7 | #include <string.h> | 7 | #include <string.h> |
8 | #include <assert.h> | 8 | #include <assert.h> |
9 | #include <ctype.h> | 9 | #include <ctype.h> |
10 | #include <math.h> | 10 | #ifdef NO_TGMATH_H |
11 | # include <math.h> | ||
12 | #else | ||
13 | # include <tgmath.h> | ||
14 | #endif | ||
11 | 15 | ||
12 | #include "puzzles.h" | 16 | #include "puzzles.h" |
13 | 17 | ||
@@ -35,6 +39,11 @@ typedef struct pegrow { | |||
35 | int *pegs; /* 0 is 'empty' */ | 39 | int *pegs; /* 0 is 'empty' */ |
36 | int *feedback; /* may well be unused */ | 40 | int *feedback; /* may well be unused */ |
37 | } *pegrow; | 41 | } *pegrow; |
42 | /* Pegs can have these flags OR'ed into them. */ | ||
43 | #define PEG_CURSOR 0x1000 | ||
44 | #define PEG_HOLD 0x2000 | ||
45 | #define PEG_LABELLED 0x4000 | ||
46 | #define PEG_FLAGS (PEG_CURSOR | PEG_HOLD | PEG_LABELLED) | ||
38 | 47 | ||
39 | struct game_state { | 48 | struct game_state { |
40 | game_params params; | 49 | game_params params; |
@@ -88,13 +97,7 @@ static bool game_fetch_preset(int i, char **name, game_params **params) | |||
88 | return false; | 97 | return false; |
89 | 98 | ||
90 | *name = dupstr(guess_presets[i].name); | 99 | *name = dupstr(guess_presets[i].name); |
91 | /* | 100 | *params = dup_params(&guess_presets[i].params); |
92 | * get round annoying const issues | ||
93 | */ | ||
94 | { | ||
95 | game_params tmp = guess_presets[i].params; | ||
96 | *params = dup_params(&tmp); | ||
97 | } | ||
98 | 101 | ||
99 | return true; | 102 | return true; |
100 | } | 103 | } |
@@ -365,16 +368,6 @@ static char *solve_game(const game_state *state, const game_state *currstate, | |||
365 | return dupstr("S"); | 368 | return dupstr("S"); |
366 | } | 369 | } |
367 | 370 | ||
368 | static bool game_can_format_as_text_now(const game_params *params) | ||
369 | { | ||
370 | return true; | ||
371 | } | ||
372 | |||
373 | static char *game_text_format(const game_state *state) | ||
374 | { | ||
375 | return NULL; | ||
376 | } | ||
377 | |||
378 | static bool is_markable(const game_params *params, pegrow pegs) | 371 | static bool is_markable(const game_params *params, pegrow pegs) |
379 | { | 372 | { |
380 | int i, nset = 0, nrequired; | 373 | int i, nset = 0, nrequired; |
@@ -386,6 +379,7 @@ static bool is_markable(const game_params *params, pegrow pegs) | |||
386 | for (i = 0; i < params->npegs; i++) { | 379 | for (i = 0; i < params->npegs; i++) { |
387 | int c = pegs->pegs[i]; | 380 | int c = pegs->pegs[i]; |
388 | if (c > 0) { | 381 | if (c > 0) { |
382 | assert(c <= params->ncolours); | ||
389 | colcount->pegs[c-1]++; | 383 | colcount->pegs[c-1]++; |
390 | nset++; | 384 | nset++; |
391 | } | 385 | } |
@@ -414,7 +408,7 @@ struct game_ui { | |||
414 | int drag_col, drag_x, drag_y; /* x and y are *center* of peg! */ | 408 | int drag_col, drag_x, drag_y; /* x and y are *center* of peg! */ |
415 | int drag_opeg; /* peg index, if dragged from a peg (from current guess), otherwise -1 */ | 409 | int drag_opeg; /* peg index, if dragged from a peg (from current guess), otherwise -1 */ |
416 | 410 | ||
417 | bool show_labels; /* label the colours with letters */ | 411 | bool show_labels; /* label the colours with numbers */ |
418 | pegrow hint; | 412 | pegrow hint; |
419 | }; | 413 | }; |
420 | 414 | ||
@@ -422,19 +416,45 @@ static game_ui *new_ui(const game_state *state) | |||
422 | { | 416 | { |
423 | game_ui *ui = snew(game_ui); | 417 | game_ui *ui = snew(game_ui); |
424 | memset(ui, 0, sizeof(game_ui)); | 418 | memset(ui, 0, sizeof(game_ui)); |
425 | ui->params = state->params; /* structure copy */ | 419 | if (state != NULL) { |
426 | ui->curr_pegs = new_pegrow(state->params.npegs); | 420 | ui->params = state->params; /* structure copy */ |
427 | ui->holds = snewn(state->params.npegs, bool); | 421 | ui->curr_pegs = new_pegrow(state->params.npegs); |
428 | memset(ui->holds, 0, sizeof(bool)*state->params.npegs); | 422 | ui->holds = snewn(state->params.npegs, bool); |
423 | memset(ui->holds, 0, sizeof(bool)*state->params.npegs); | ||
424 | } | ||
425 | ui->display_cur = getenv_bool("PUZZLES_SHOW_CURSOR", false); | ||
429 | ui->drag_opeg = -1; | 426 | ui->drag_opeg = -1; |
430 | return ui; | 427 | return ui; |
431 | } | 428 | } |
432 | 429 | ||
430 | static config_item *get_prefs(game_ui *ui) | ||
431 | { | ||
432 | config_item *ret; | ||
433 | |||
434 | ret = snewn(2, config_item); | ||
435 | |||
436 | ret[0].name = "Label colours with numbers"; | ||
437 | ret[0].kw = "show-labels"; | ||
438 | ret[0].type = C_BOOLEAN; | ||
439 | ret[0].u.boolean.bval = ui->show_labels; | ||
440 | |||
441 | ret[1].name = NULL; | ||
442 | ret[1].type = C_END; | ||
443 | |||
444 | return ret; | ||
445 | } | ||
446 | |||
447 | static void set_prefs(game_ui *ui, const config_item *cfg) | ||
448 | { | ||
449 | ui->show_labels = cfg[0].u.boolean.bval; | ||
450 | } | ||
451 | |||
433 | static void free_ui(game_ui *ui) | 452 | static void free_ui(game_ui *ui) |
434 | { | 453 | { |
435 | if (ui->hint) | 454 | if (ui->hint) |
436 | free_pegrow(ui->hint); | 455 | free_pegrow(ui->hint); |
437 | free_pegrow(ui->curr_pegs); | 456 | if (ui->curr_pegs) |
457 | free_pegrow(ui->curr_pegs); | ||
438 | sfree(ui->holds); | 458 | sfree(ui->holds); |
439 | sfree(ui); | 459 | sfree(ui); |
440 | } | 460 | } |
@@ -462,12 +482,16 @@ static char *encode_ui(const game_ui *ui) | |||
462 | return sresize(ret, p - ret, char); | 482 | return sresize(ret, p - ret, char); |
463 | } | 483 | } |
464 | 484 | ||
465 | static void decode_ui(game_ui *ui, const char *encoding) | 485 | static void decode_ui(game_ui *ui, const char *encoding, |
486 | const game_state *state) | ||
466 | { | 487 | { |
467 | int i; | 488 | int i; |
468 | const char *p = encoding; | 489 | const char *p = encoding; |
469 | for (i = 0; i < ui->curr_pegs->npegs; i++) { | 490 | for (i = 0; i < ui->curr_pegs->npegs; i++) { |
470 | ui->curr_pegs->pegs[i] = atoi(p); | 491 | ui->curr_pegs->pegs[i] = atoi(p); |
492 | if (ui->curr_pegs->pegs[i] < 0 || | ||
493 | ui->curr_pegs->pegs[i] > ui->params.ncolours) | ||
494 | ui->curr_pegs->pegs[i] = 0; /* Remove invalid pegs. */ | ||
471 | while (*p && isdigit((unsigned char)*p)) p++; | 495 | while (*p && isdigit((unsigned char)*p)) p++; |
472 | if (*p == '_') { | 496 | if (*p == '_') { |
473 | /* NB: old versions didn't store holds */ | 497 | /* NB: old versions didn't store holds */ |
@@ -507,7 +531,20 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate, | |||
507 | ui->markable = is_markable(&newstate->params, ui->curr_pegs); | 531 | ui->markable = is_markable(&newstate->params, ui->curr_pegs); |
508 | /* Clean up cursor position */ | 532 | /* Clean up cursor position */ |
509 | if (!ui->markable && ui->peg_cur == newstate->solution->npegs) | 533 | if (!ui->markable && ui->peg_cur == newstate->solution->npegs) |
510 | ui->peg_cur--; | 534 | ui->peg_cur = 0; |
535 | } | ||
536 | |||
537 | static const char *current_key_label(const game_ui *ui, | ||
538 | const game_state *state, int button) | ||
539 | { | ||
540 | if (state->solved) return ""; | ||
541 | if (button == CURSOR_SELECT) { | ||
542 | if (ui->peg_cur == state->params.npegs) return "Submit"; | ||
543 | return "Place"; | ||
544 | } | ||
545 | if (button == CURSOR_SELECT2 && ui->peg_cur != state->params.npegs) | ||
546 | return "Hold"; | ||
547 | return ""; | ||
511 | } | 548 | } |
512 | 549 | ||
513 | #define PEGSZ (ds->pegsz) | 550 | #define PEGSZ (ds->pegsz) |
@@ -700,7 +737,11 @@ static void compute_hint(const game_state *state, game_ui *ui) | |||
700 | for (j = 0; j < state->params.npegs; ++j) | 737 | for (j = 0; j < state->params.npegs; ++j) |
701 | if (state->guesses[i]->pegs[j] > maxcolour) | 738 | if (state->guesses[i]->pegs[j] > maxcolour) |
702 | maxcolour = state->guesses[i]->pegs[j]; | 739 | maxcolour = state->guesses[i]->pegs[j]; |
703 | maxcolour = min(maxcolour + 1, state->params.ncolours); | 740 | if (state->params.allow_multiple) |
741 | maxcolour = min(maxcolour + 1, state->params.ncolours); | ||
742 | else | ||
743 | maxcolour = min(maxcolour + state->params.npegs, | ||
744 | state->params.ncolours); | ||
704 | 745 | ||
705 | increase_mincolour: | 746 | increase_mincolour: |
706 | for (i = 0; i < state->next_go; ++i) { | 747 | for (i = 0; i < state->next_go; ++i) { |
@@ -722,6 +763,7 @@ increase_mincolour: | |||
722 | } | 763 | } |
723 | 764 | ||
724 | while (ui->hint->pegs[0] <= state->params.ncolours) { | 765 | while (ui->hint->pegs[0] <= state->params.ncolours) { |
766 | if (!is_markable(&state->params, ui->hint)) goto increment_pegrow; | ||
725 | for (i = 0; i < state->next_go; ++i) { | 767 | for (i = 0; i < state->next_go; ++i) { |
726 | mark_pegs(ui->hint, state->guesses[i], maxcolour); | 768 | mark_pegs(ui->hint, state->guesses[i], maxcolour); |
727 | for (j = 0; j < state->params.npegs; ++j) | 769 | for (j = 0; j < state->params.npegs; ++j) |
@@ -777,7 +819,7 @@ static char *interpret_move(const game_state *from, game_ui *ui, | |||
777 | */ | 819 | */ |
778 | if (button == 'l' || button == 'L') { | 820 | if (button == 'l' || button == 'L') { |
779 | ui->show_labels = !ui->show_labels; | 821 | ui->show_labels = !ui->show_labels; |
780 | return UI_UPDATE; | 822 | return MOVE_UI_UPDATE; |
781 | } | 823 | } |
782 | 824 | ||
783 | if (from->solved) return NULL; | 825 | if (from->solved) return NULL; |
@@ -834,13 +876,13 @@ static char *interpret_move(const game_state *from, game_ui *ui, | |||
834 | ui->drag_y = y; | 876 | ui->drag_y = y; |
835 | debug(("Start dragging, col = %d, (%d,%d)", | 877 | debug(("Start dragging, col = %d, (%d,%d)", |
836 | ui->drag_col, ui->drag_x, ui->drag_y)); | 878 | ui->drag_col, ui->drag_x, ui->drag_y)); |
837 | ret = UI_UPDATE; | 879 | ret = MOVE_UI_UPDATE; |
838 | } | 880 | } |
839 | } else if (button == LEFT_DRAG && ui->drag_col) { | 881 | } else if (button == LEFT_DRAG && ui->drag_col) { |
840 | ui->drag_x = x; | 882 | ui->drag_x = x; |
841 | ui->drag_y = y; | 883 | ui->drag_y = y; |
842 | debug(("Keep dragging, (%d,%d)", ui->drag_x, ui->drag_y)); | 884 | debug(("Keep dragging, (%d,%d)", ui->drag_x, ui->drag_y)); |
843 | ret = UI_UPDATE; | 885 | ret = MOVE_UI_UPDATE; |
844 | } else if (button == LEFT_RELEASE && ui->drag_col) { | 886 | } else if (button == LEFT_RELEASE && ui->drag_col) { |
845 | if (over_guess > -1) { | 887 | if (over_guess > -1) { |
846 | debug(("Dropping colour %d onto guess peg %d", | 888 | debug(("Dropping colour %d onto guess peg %d", |
@@ -857,13 +899,13 @@ static char *interpret_move(const game_state *from, game_ui *ui, | |||
857 | ui->drag_opeg = -1; | 899 | ui->drag_opeg = -1; |
858 | ui->display_cur = false; | 900 | ui->display_cur = false; |
859 | debug(("Stop dragging.")); | 901 | debug(("Stop dragging.")); |
860 | ret = UI_UPDATE; | 902 | ret = MOVE_UI_UPDATE; |
861 | } else if (button == RIGHT_BUTTON) { | 903 | } else if (button == RIGHT_BUTTON) { |
862 | if (over_guess > -1) { | 904 | if (over_guess > -1) { |
863 | /* we use ths feedback in the game_ui to signify | 905 | /* we use ths feedback in the game_ui to signify |
864 | * 'carry this peg to the next guess as well'. */ | 906 | * 'carry this peg to the next guess as well'. */ |
865 | ui->holds[over_guess] ^= 1; | 907 | ui->holds[over_guess] ^= 1; |
866 | ret = UI_UPDATE; | 908 | ret = MOVE_UI_UPDATE; |
867 | } | 909 | } |
868 | } else if (button == LEFT_RELEASE && over_hint && ui->markable) { | 910 | } else if (button == LEFT_RELEASE && over_hint && ui->markable) { |
869 | /* NB this won't trigger if on the end of a drag; that's on | 911 | /* NB this won't trigger if on the end of a drag; that's on |
@@ -872,44 +914,47 @@ static char *interpret_move(const game_state *from, game_ui *ui, | |||
872 | } | 914 | } |
873 | 915 | ||
874 | /* keyboard input */ | 916 | /* keyboard input */ |
875 | if (button == CURSOR_UP || button == CURSOR_DOWN) { | 917 | if (IS_CURSOR_MOVE(button)) { |
876 | ui->display_cur = true; | ||
877 | if (button == CURSOR_DOWN && (ui->colour_cur+1) < from->params.ncolours) | ||
878 | ui->colour_cur++; | ||
879 | if (button == CURSOR_UP && ui->colour_cur > 0) | ||
880 | ui->colour_cur--; | ||
881 | ret = UI_UPDATE; | ||
882 | } else if (button == 'h' || button == 'H' || button == '?') { | ||
883 | compute_hint(from, ui); | ||
884 | ret = UI_UPDATE; | ||
885 | } else if (button == CURSOR_LEFT || button == CURSOR_RIGHT) { | ||
886 | int maxcur = from->params.npegs; | 918 | int maxcur = from->params.npegs; |
887 | if (ui->markable) maxcur++; | 919 | if (ui->markable) maxcur++; |
888 | 920 | ||
889 | ui->display_cur = true; | 921 | ret = move_cursor(button, &ui->peg_cur, &ui->colour_cur, |
890 | if (button == CURSOR_RIGHT && (ui->peg_cur+1) < maxcur) | 922 | maxcur, from->params.ncolours, |
891 | ui->peg_cur++; | 923 | false, &ui->display_cur); |
892 | if (button == CURSOR_LEFT && ui->peg_cur > 0) | 924 | } else if (button == 'h' || button == 'H' || button == '?') { |
893 | ui->peg_cur--; | 925 | compute_hint(from, ui); |
894 | ret = UI_UPDATE; | 926 | ret = MOVE_UI_UPDATE; |
895 | } else if (IS_CURSOR_SELECT(button)) { | 927 | } else if (button == CURSOR_SELECT) { |
896 | ui->display_cur = true; | 928 | ui->display_cur = true; |
897 | if (ui->peg_cur == from->params.npegs) { | 929 | if (ui->peg_cur == from->params.npegs) { |
898 | ret = encode_move(from, ui); | 930 | ret = encode_move(from, ui); |
899 | } else { | 931 | } else { |
900 | set_peg(&from->params, ui, ui->peg_cur, ui->colour_cur+1); | 932 | set_peg(&from->params, ui, ui->peg_cur, ui->colour_cur+1); |
901 | ret = UI_UPDATE; | 933 | ret = MOVE_UI_UPDATE; |
902 | } | 934 | } |
903 | } else if (button == 'D' || button == 'd' || button == '\b') { | 935 | } else if (((button >= '1' && button <= '0' + from->params.ncolours) || |
936 | (button == '0' && from->params.ncolours == 10)) && | ||
937 | ui->peg_cur < from->params.npegs) { | ||
904 | ui->display_cur = true; | 938 | ui->display_cur = true; |
905 | set_peg(&from->params, ui, ui->peg_cur, 0); | 939 | /* Number keys insert a peg and advance the cursor. */ |
906 | ret = UI_UPDATE; | 940 | set_peg(&from->params, ui, ui->peg_cur, |
941 | button == '0' ? 10 : button - '0'); | ||
942 | if (ui->peg_cur + 1 < from->params.npegs + ui->markable) | ||
943 | ui->peg_cur++; | ||
944 | ret = MOVE_UI_UPDATE; | ||
945 | } else if (button == 'D' || button == 'd' || button == '\b') { | ||
946 | if (!ui->display_cur || ui->curr_pegs->pegs[ui->peg_cur] != 0) { | ||
947 | ui->display_cur = true; | ||
948 | set_peg(&from->params, ui, ui->peg_cur, 0); | ||
949 | ret = MOVE_UI_UPDATE; | ||
950 | } else | ||
951 | ret = MOVE_NO_EFFECT; | ||
907 | } else if (button == CURSOR_SELECT2) { | 952 | } else if (button == CURSOR_SELECT2) { |
908 | if (ui->peg_cur == from->params.npegs) | 953 | if (ui->peg_cur == from->params.npegs) |
909 | return NULL; | 954 | return NULL; |
910 | ui->display_cur = true; | 955 | ui->display_cur = true; |
911 | ui->holds[ui->peg_cur] ^= 1; | 956 | ui->holds[ui->peg_cur] ^= 1; |
912 | ret = UI_UPDATE; | 957 | ret = MOVE_UI_UPDATE; |
913 | } | 958 | } |
914 | return ret; | 959 | return ret; |
915 | } | 960 | } |
@@ -925,6 +970,8 @@ static game_state *execute_move(const game_state *from, const char *move) | |||
925 | ret->solved = -1; | 970 | ret->solved = -1; |
926 | return ret; | 971 | return ret; |
927 | } else if (move[0] == 'G') { | 972 | } else if (move[0] == 'G') { |
973 | /* No guesses are allowed once the game is solved. */ | ||
974 | if (from->solved) return NULL; | ||
928 | p = move+1; | 975 | p = move+1; |
929 | 976 | ||
930 | ret = dup_game(from); | 977 | ret = dup_game(from); |
@@ -975,7 +1022,7 @@ static game_state *execute_move(const game_state *from, const char *move) | |||
975 | #define BORDER 0.5 | 1022 | #define BORDER 0.5 |
976 | 1023 | ||
977 | static void game_compute_size(const game_params *params, int tilesize, | 1024 | static void game_compute_size(const game_params *params, int tilesize, |
978 | int *x, int *y) | 1025 | const game_ui *ui, int *x, int *y) |
979 | { | 1026 | { |
980 | double hmul, vmul_c, vmul_g, vmul; | 1027 | double hmul, vmul_c, vmul_g, vmul; |
981 | int hintw = (params->npegs+1)/2; | 1028 | int hintw = (params->npegs+1)/2; |
@@ -1019,7 +1066,8 @@ static void game_set_size(drawing *dr, game_drawstate *ds, | |||
1019 | guessh = ((ds->pegsz + ds->gapsz) * params->nguesses); /* guesses */ | 1066 | guessh = ((ds->pegsz + ds->gapsz) * params->nguesses); /* guesses */ |
1020 | guessh += ds->gapsz + ds->pegsz; /* solution */ | 1067 | guessh += ds->gapsz + ds->pegsz; /* solution */ |
1021 | 1068 | ||
1022 | game_compute_size(params, tilesize, &ds->w, &ds->h); | 1069 | /* We know we don't need anything from the game_ui we haven't got */ |
1070 | game_compute_size(params, tilesize, NULL, &ds->w, &ds->h); | ||
1023 | ds->colx = ds->border; | 1071 | ds->colx = ds->border; |
1024 | ds->coly = (ds->h - colh) / 2; | 1072 | ds->coly = (ds->h - colh) / 2; |
1025 | 1073 | ||
@@ -1196,7 +1244,7 @@ static void draw_peg(drawing *dr, game_drawstate *ds, int cx, int cy, | |||
1196 | 1244 | ||
1197 | if (labelled && col) { | 1245 | if (labelled && col) { |
1198 | char buf[2]; | 1246 | char buf[2]; |
1199 | buf[0] = 'a'-1 + col; | 1247 | buf[0] = '0' + (col % 10); |
1200 | buf[1] = '\0'; | 1248 | buf[1] = '\0'; |
1201 | draw_text(dr, cx+PEGRAD, cy+PEGRAD, FONT_VARIABLE, PEGRAD, | 1249 | draw_text(dr, cx+PEGRAD, cy+PEGRAD, FONT_VARIABLE, PEGRAD, |
1202 | ALIGN_HCENTRE|ALIGN_VCENTRE, COL_FRAME, buf); | 1250 | ALIGN_HCENTRE|ALIGN_VCENTRE, COL_FRAME, buf); |
@@ -1233,23 +1281,25 @@ static void guess_redraw(drawing *dr, game_drawstate *ds, int guess, | |||
1233 | for (i = 0; i < dest->npegs; i++) { | 1281 | for (i = 0; i < dest->npegs; i++) { |
1234 | scol = src ? src->pegs[i] : 0; | 1282 | scol = src ? src->pegs[i] : 0; |
1235 | if (i == cur_col) | 1283 | if (i == cur_col) |
1236 | scol |= 0x1000; | 1284 | scol |= PEG_CURSOR; |
1237 | if (holds && holds[i]) | 1285 | if (holds && holds[i]) |
1238 | scol |= 0x2000; | 1286 | scol |= PEG_HOLD; |
1239 | if (labelled) | 1287 | if (labelled) |
1240 | scol |= 0x4000; | 1288 | scol |= PEG_LABELLED; |
1241 | if ((dest->pegs[i] != scol) || force) { | 1289 | if ((dest->pegs[i] != scol) || force) { |
1242 | draw_peg(dr, ds, rowx + PEGOFF * i, rowy, false, labelled, | 1290 | draw_peg(dr, ds, rowx + PEGOFF * i, rowy, false, labelled, |
1243 | scol &~ 0x7000); | 1291 | scol &~ PEG_FLAGS); |
1292 | if (scol & PEG_CURSOR) | ||
1293 | draw_cursor(dr, ds, rowx + PEGOFF * i, rowy); | ||
1244 | /* | 1294 | /* |
1245 | * Hold marker. | 1295 | * Hold marker. |
1246 | */ | 1296 | */ |
1247 | draw_rect(dr, rowx + PEGOFF * i, rowy + PEGSZ + ds->gapsz/2, | 1297 | if (scol & PEG_HOLD) { |
1248 | PEGSZ, 2, (scol & 0x2000 ? COL_HOLD : COL_BACKGROUND)); | 1298 | draw_rect(dr, rowx + PEGOFF * i, |
1249 | draw_update(dr, rowx + PEGOFF * i, rowy + PEGSZ + ds->gapsz/2, | 1299 | rowy + PEGSZ + ds->gapsz/2 - 2, PEGSZ, 2, COL_HOLD); |
1250 | PEGSZ, 2); | 1300 | } |
1251 | if (scol & 0x1000) | 1301 | draw_update(dr, rowx + PEGOFF * i, |
1252 | draw_cursor(dr, ds, rowx + PEGOFF * i, rowy); | 1302 | rowy + PEGSZ + ds->gapsz/2 - 2, PEGSZ, 2); |
1253 | } | 1303 | } |
1254 | dest->pegs[i] = scol; | 1304 | dest->pegs[i] = scol; |
1255 | } | 1305 | } |
@@ -1276,9 +1326,9 @@ static void hint_redraw(drawing *dr, game_drawstate *ds, int guess, | |||
1276 | for (i = 0; i < dest->npegs; i++) { | 1326 | for (i = 0; i < dest->npegs; i++) { |
1277 | scol = src ? src->feedback[i] : 0; | 1327 | scol = src ? src->feedback[i] : 0; |
1278 | if (i == 0 && cursor) | 1328 | if (i == 0 && cursor) |
1279 | scol |= 0x1000; | 1329 | scol |= PEG_CURSOR; |
1280 | if (i == 0 && markable) | 1330 | if (i == 0 && markable) |
1281 | scol |= 0x2000; | 1331 | scol |= PEG_HOLD; |
1282 | if ((scol != dest->feedback[i]) || force) { | 1332 | if ((scol != dest->feedback[i]) || force) { |
1283 | need_redraw = true; | 1333 | need_redraw = true; |
1284 | } | 1334 | } |
@@ -1349,7 +1399,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, | |||
1349 | new_move = (state->next_go != ds->next_go) || !ds->started; | 1399 | new_move = (state->next_go != ds->next_go) || !ds->started; |
1350 | 1400 | ||
1351 | if (!ds->started) { | 1401 | if (!ds->started) { |
1352 | draw_rect(dr, 0, 0, ds->w, ds->h, COL_BACKGROUND); | ||
1353 | draw_rect(dr, SOLN_OX, SOLN_OY - ds->gapsz - 1, SOLN_W, 2, COL_FRAME); | 1402 | draw_rect(dr, SOLN_OX, SOLN_OY - ds->gapsz - 1, SOLN_W, 2, COL_FRAME); |
1354 | draw_update(dr, 0, 0, ds->w, ds->h); | 1403 | draw_update(dr, 0, 0, ds->w, ds->h); |
1355 | } | 1404 | } |
@@ -1364,19 +1413,18 @@ static void game_redraw(drawing *dr, game_drawstate *ds, | |||
1364 | for (i = 0; i < state->params.ncolours; i++) { | 1413 | for (i = 0; i < state->params.ncolours; i++) { |
1365 | int val = i+1; | 1414 | int val = i+1; |
1366 | if (ui->display_cur && ui->colour_cur == i) | 1415 | if (ui->display_cur && ui->colour_cur == i) |
1367 | val |= 0x1000; | 1416 | val |= PEG_CURSOR; |
1368 | if (ui->show_labels) | 1417 | if (ui->show_labels) |
1369 | val |= 0x2000; | 1418 | val |= PEG_HOLD; |
1370 | if (ds->colours->pegs[i] != val) { | 1419 | if (ds->colours->pegs[i] != val) { |
1371 | draw_peg(dr, ds, COL_X(i), COL_Y(i), false, ui->show_labels, i+1); | 1420 | draw_peg(dr, ds, COL_X(i), COL_Y(i), false, ui->show_labels, i+1); |
1372 | if (val & 0x1000) | 1421 | if (val & PEG_CURSOR) |
1373 | draw_cursor(dr, ds, COL_X(i), COL_Y(i)); | 1422 | draw_cursor(dr, ds, COL_X(i), COL_Y(i)); |
1374 | ds->colours->pegs[i] = val; | 1423 | ds->colours->pegs[i] = val; |
1375 | } | 1424 | } |
1376 | } | 1425 | } |
1377 | 1426 | ||
1378 | /* draw the guesses (so far) and the hints | 1427 | /* draw the guesses (so far) and the hints (postponing the |
1379 | * (in reverse order to avoid trampling holds, and postponing the | ||
1380 | * next_go'th to not overrender the top of the circular cursor) */ | 1428 | * next_go'th to not overrender the top of the circular cursor) */ |
1381 | for (i = state->params.nguesses - 1; i >= 0; i--) { | 1429 | for (i = state->params.nguesses - 1; i >= 0; i--) { |
1382 | if (i < state->next_go || state->solved) { | 1430 | if (i < state->next_go || state->solved) { |
@@ -1473,19 +1521,6 @@ static int game_status(const game_state *state) | |||
1473 | return state->solved; | 1521 | return state->solved; |
1474 | } | 1522 | } |
1475 | 1523 | ||
1476 | static bool game_timing_state(const game_state *state, game_ui *ui) | ||
1477 | { | ||
1478 | return true; | ||
1479 | } | ||
1480 | |||
1481 | static void game_print_size(const game_params *params, float *x, float *y) | ||
1482 | { | ||
1483 | } | ||
1484 | |||
1485 | static void game_print(drawing *dr, const game_state *state, int tilesize) | ||
1486 | { | ||
1487 | } | ||
1488 | |||
1489 | #ifdef COMBINED | 1524 | #ifdef COMBINED |
1490 | #define thegame guess | 1525 | #define thegame guess |
1491 | #endif | 1526 | #endif |
@@ -1506,13 +1541,15 @@ const struct game thegame = { | |||
1506 | dup_game, | 1541 | dup_game, |
1507 | free_game, | 1542 | free_game, |
1508 | true, solve_game, | 1543 | true, solve_game, |
1509 | false, game_can_format_as_text_now, game_text_format, | 1544 | false, NULL, NULL, /* can_format_as_text_now, text_format */ |
1545 | get_prefs, set_prefs, | ||
1510 | new_ui, | 1546 | new_ui, |
1511 | free_ui, | 1547 | free_ui, |
1512 | encode_ui, | 1548 | encode_ui, |
1513 | decode_ui, | 1549 | decode_ui, |
1514 | NULL, /* game_request_keys */ | 1550 | NULL, /* game_request_keys */ |
1515 | game_changed_state, | 1551 | game_changed_state, |
1552 | current_key_label, | ||
1516 | interpret_move, | 1553 | interpret_move, |
1517 | execute_move, | 1554 | execute_move, |
1518 | PEG_PREFER_SZ, game_compute_size, game_set_size, | 1555 | PEG_PREFER_SZ, game_compute_size, game_set_size, |
@@ -1524,9 +1561,9 @@ const struct game thegame = { | |||
1524 | game_flash_length, | 1561 | game_flash_length, |
1525 | game_get_cursor_location, | 1562 | game_get_cursor_location, |
1526 | game_status, | 1563 | game_status, |
1527 | false, false, game_print_size, game_print, | 1564 | false, false, NULL, NULL, /* print_size, print */ |
1528 | false, /* wants_statusbar */ | 1565 | false, /* wants_statusbar */ |
1529 | false, game_timing_state, | 1566 | false, NULL, /* timing_state */ |
1530 | 0, /* flags */ | 1567 | 0, /* flags */ |
1531 | }; | 1568 | }; |
1532 | 1569 | ||