summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/solo.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/puzzles/src/solo.c')
-rw-r--r--apps/plugins/puzzles/src/solo.c197
1 files changed, 126 insertions, 71 deletions
diff --git a/apps/plugins/puzzles/src/solo.c b/apps/plugins/puzzles/src/solo.c
index 49753f41dc..2445501f57 100644
--- a/apps/plugins/puzzles/src/solo.c
+++ b/apps/plugins/puzzles/src/solo.c
@@ -20,7 +20,7 @@
20 * + while I'm revamping this area, filling in the _last_ 20 * + while I'm revamping this area, filling in the _last_
21 * number in a nearly-full row or column should certainly be 21 * number in a nearly-full row or column should certainly be
22 * permitted even at the lowest difficulty level. 22 * permitted even at the lowest difficulty level.
23 * + also Owen noticed that `Basic' grids requiring numeric 23 * + also Alex noticed that `Basic' grids requiring numeric
24 * elimination are actually very hard, so I wonder if a 24 * elimination are actually very hard, so I wonder if a
25 * difficulty gradation between that and positional- 25 * difficulty gradation between that and positional-
26 * elimination-only might be in order 26 * elimination-only might be in order
@@ -87,11 +87,15 @@
87#include <string.h> 87#include <string.h>
88#include <assert.h> 88#include <assert.h>
89#include <ctype.h> 89#include <ctype.h>
90#include <math.h> 90#ifdef NO_TGMATH_H
91# include <math.h>
92#else
93# include <tgmath.h>
94#endif
91 95
92#ifdef STANDALONE_SOLVER 96#ifdef STANDALONE_SOLVER
93#include <stdarg.h> 97#include <stdarg.h>
94int solver_show_working, solver_recurse_depth; 98static int solver_show_working, solver_recurse_depth;
95#endif 99#endif
96 100
97#include "puzzles.h" 101#include "puzzles.h"
@@ -2638,6 +2642,7 @@ static void solver(int cr, struct block_structure *blocks,
2638 sfree(usage->row); 2642 sfree(usage->row);
2639 sfree(usage->col); 2643 sfree(usage->col);
2640 sfree(usage->blk); 2644 sfree(usage->blk);
2645 sfree(usage->diag);
2641 if (usage->kblocks) { 2646 if (usage->kblocks) {
2642 free_block_structure(usage->kblocks); 2647 free_block_structure(usage->kblocks);
2643 free_block_structure(usage->extra_cages); 2648 free_block_structure(usage->extra_cages);
@@ -2969,6 +2974,7 @@ static bool gridgen(int cr, struct block_structure *blocks,
2969 sfree(usage->blk); 2974 sfree(usage->blk);
2970 sfree(usage->col); 2975 sfree(usage->col);
2971 sfree(usage->row); 2976 sfree(usage->row);
2977 sfree(usage->diag);
2972 sfree(usage); 2978 sfree(usage);
2973 2979
2974 return ret; 2980 return ret;
@@ -3222,7 +3228,7 @@ static char *encode_solve_move(int cr, digit *grid)
3222 return ret; 3228 return ret;
3223} 3229}
3224 3230
3225static void dsf_to_blocks(int *dsf, struct block_structure *blocks, 3231static void dsf_to_blocks(DSF *dsf, struct block_structure *blocks,
3226 int min_expected, int max_expected) 3232 int min_expected, int max_expected)
3227{ 3233{
3228 int cr = blocks->c * blocks->r, area = cr * cr; 3234 int cr = blocks->c * blocks->r, area = cr * cr;
@@ -3654,10 +3660,11 @@ static char *new_game_desc(const game_params *params, random_state *rs,
3654 * the puzzle size: all 2x2 puzzles appear to be Trivial 3660 * the puzzle size: all 2x2 puzzles appear to be Trivial
3655 * (DIFF_BLOCK) so we cannot hold out for even a Basic 3661 * (DIFF_BLOCK) so we cannot hold out for even a Basic
3656 * (DIFF_SIMPLE) one. 3662 * (DIFF_SIMPLE) one.
3663 * Jigsaw puzzles of size 2 and 3 are also all trivial.
3657 */ 3664 */
3658 dlev.maxdiff = params->diff; 3665 dlev.maxdiff = params->diff;
3659 dlev.maxkdiff = params->kdiff; 3666 dlev.maxkdiff = params->kdiff;
3660 if (c == 2 && r == 2) 3667 if ((c == 2 && r == 2) || (r == 1 && c < 4))
3661 dlev.maxdiff = DIFF_BLOCK; 3668 dlev.maxdiff = DIFF_BLOCK;
3662 3669
3663 grid = snewn(area, digit); 3670 grid = snewn(area, digit);
@@ -3684,11 +3691,11 @@ static char *new_game_desc(const game_params *params, random_state *rs,
3684 * constructing the block structure. 3691 * constructing the block structure.
3685 */ 3692 */
3686 if (r == 1) { /* jigsaw mode */ 3693 if (r == 1) { /* jigsaw mode */
3687 int *dsf = divvy_rectangle(cr, cr, cr, rs); 3694 DSF *dsf = divvy_rectangle(cr, cr, cr, rs);
3688 3695
3689 dsf_to_blocks (dsf, blocks, cr, cr); 3696 dsf_to_blocks (dsf, blocks, cr, cr);
3690 3697
3691 sfree(dsf); 3698 dsf_free(dsf);
3692 } else { /* basic Sudoku mode */ 3699 } else { /* basic Sudoku mode */
3693 for (y = 0; y < cr; y++) 3700 for (y = 0; y < cr; y++)
3694 for (x = 0; x < cr; x++) 3701 for (x = 0; x < cr; x++)
@@ -3903,14 +3910,14 @@ static const char *spec_to_grid(const char *desc, digit *grid, int area)
3903 * end of the block spec, and return an error string or NULL if everything 3910 * end of the block spec, and return an error string or NULL if everything
3904 * is OK. The DSF is stored in *PDSF. 3911 * is OK. The DSF is stored in *PDSF.
3905 */ 3912 */
3906static const char *spec_to_dsf(const char **pdesc, int **pdsf, 3913static const char *spec_to_dsf(const char **pdesc, DSF **pdsf,
3907 int cr, int area) 3914 int cr, int area)
3908{ 3915{
3909 const char *desc = *pdesc; 3916 const char *desc = *pdesc;
3910 int pos = 0; 3917 int pos = 0;
3911 int *dsf; 3918 DSF *dsf;
3912 3919
3913 *pdsf = dsf = snew_dsf(area); 3920 *pdsf = dsf = dsf_new(area);
3914 3921
3915 while (*desc && *desc != ',') { 3922 while (*desc && *desc != ',') {
3916 int c; 3923 int c;
@@ -3921,7 +3928,7 @@ static const char *spec_to_dsf(const char **pdesc, int **pdsf,
3921 else if (*desc >= 'a' && *desc <= 'z') 3928 else if (*desc >= 'a' && *desc <= 'z')
3922 c = *desc - 'a' + 1; 3929 c = *desc - 'a' + 1;
3923 else { 3930 else {
3924 sfree(dsf); 3931 dsf_free(dsf);
3925 return "Invalid character in game description"; 3932 return "Invalid character in game description";
3926 } 3933 }
3927 desc++; 3934 desc++;
@@ -3936,7 +3943,7 @@ static const char *spec_to_dsf(const char **pdesc, int **pdsf,
3936 * side of it. 3943 * side of it.
3937 */ 3944 */
3938 if (pos >= 2*cr*(cr-1)) { 3945 if (pos >= 2*cr*(cr-1)) {
3939 sfree(dsf); 3946 dsf_free(dsf);
3940 return "Too much data in block structure specification"; 3947 return "Too much data in block structure specification";
3941 } 3948 }
3942 3949
@@ -3966,7 +3973,7 @@ static const char *spec_to_dsf(const char **pdesc, int **pdsf,
3966 * edge at the end. 3973 * edge at the end.
3967 */ 3974 */
3968 if (pos != 2*cr*(cr-1)+1) { 3975 if (pos != 2*cr*(cr-1)+1) {
3969 sfree(dsf); 3976 dsf_free(dsf);
3970 return "Not enough data in block structure specification"; 3977 return "Not enough data in block structure specification";
3971 } 3978 }
3972 3979
@@ -4008,7 +4015,7 @@ static const char *validate_block_desc(const char **pdesc, int cr, int area,
4008 int min_nr_squares, int max_nr_squares) 4015 int min_nr_squares, int max_nr_squares)
4009{ 4016{
4010 const char *err; 4017 const char *err;
4011 int *dsf; 4018 DSF *dsf;
4012 4019
4013 err = spec_to_dsf(pdesc, &dsf, cr, area); 4020 err = spec_to_dsf(pdesc, &dsf, cr, area);
4014 if (err) { 4021 if (err) {
@@ -4037,7 +4044,7 @@ static const char *validate_block_desc(const char **pdesc, int cr, int area,
4037 if (canons[c] == j) { 4044 if (canons[c] == j) {
4038 counts[c]++; 4045 counts[c]++;
4039 if (counts[c] > max_nr_squares) { 4046 if (counts[c] > max_nr_squares) {
4040 sfree(dsf); 4047 dsf_free(dsf);
4041 sfree(canons); 4048 sfree(canons);
4042 sfree(counts); 4049 sfree(counts);
4043 return "A jigsaw block is too big"; 4050 return "A jigsaw block is too big";
@@ -4047,7 +4054,7 @@ static const char *validate_block_desc(const char **pdesc, int cr, int area,
4047 4054
4048 if (c == ncanons) { 4055 if (c == ncanons) {
4049 if (ncanons >= max_nr_blocks) { 4056 if (ncanons >= max_nr_blocks) {
4050 sfree(dsf); 4057 dsf_free(dsf);
4051 sfree(canons); 4058 sfree(canons);
4052 sfree(counts); 4059 sfree(counts);
4053 return "Too many distinct jigsaw blocks"; 4060 return "Too many distinct jigsaw blocks";
@@ -4059,14 +4066,14 @@ static const char *validate_block_desc(const char **pdesc, int cr, int area,
4059 } 4066 }
4060 4067
4061 if (ncanons < min_nr_blocks) { 4068 if (ncanons < min_nr_blocks) {
4062 sfree(dsf); 4069 dsf_free(dsf);
4063 sfree(canons); 4070 sfree(canons);
4064 sfree(counts); 4071 sfree(counts);
4065 return "Not enough distinct jigsaw blocks"; 4072 return "Not enough distinct jigsaw blocks";
4066 } 4073 }
4067 for (c = 0; c < ncanons; c++) { 4074 for (c = 0; c < ncanons; c++) {
4068 if (counts[c] < min_nr_squares) { 4075 if (counts[c] < min_nr_squares) {
4069 sfree(dsf); 4076 dsf_free(dsf);
4070 sfree(canons); 4077 sfree(canons);
4071 sfree(counts); 4078 sfree(counts);
4072 return "A jigsaw block is too small"; 4079 return "A jigsaw block is too small";
@@ -4076,7 +4083,7 @@ static const char *validate_block_desc(const char **pdesc, int cr, int area,
4076 sfree(counts); 4083 sfree(counts);
4077 } 4084 }
4078 4085
4079 sfree(dsf); 4086 dsf_free(dsf);
4080 return NULL; 4087 return NULL;
4081} 4088}
4082 4089
@@ -4161,13 +4168,13 @@ static game_state *new_game(midend *me, const game_params *params,
4161 4168
4162 if (r == 1) { 4169 if (r == 1) {
4163 const char *err; 4170 const char *err;
4164 int *dsf; 4171 DSF *dsf;
4165 assert(*desc == ','); 4172 assert(*desc == ',');
4166 desc++; 4173 desc++;
4167 err = spec_to_dsf(&desc, &dsf, cr, area); 4174 err = spec_to_dsf(&desc, &dsf, cr, area);
4168 assert(err == NULL); 4175 assert(err == NULL);
4169 dsf_to_blocks(dsf, state->blocks, cr, cr); 4176 dsf_to_blocks(dsf, state->blocks, cr, cr);
4170 sfree(dsf); 4177 dsf_free(dsf);
4171 } else { 4178 } else {
4172 int x, y; 4179 int x, y;
4173 4180
@@ -4179,13 +4186,13 @@ static game_state *new_game(midend *me, const game_params *params,
4179 4186
4180 if (params->killer) { 4187 if (params->killer) {
4181 const char *err; 4188 const char *err;
4182 int *dsf; 4189 DSF *dsf;
4183 assert(*desc == ','); 4190 assert(*desc == ',');
4184 desc++; 4191 desc++;
4185 err = spec_to_dsf(&desc, &dsf, cr, area); 4192 err = spec_to_dsf(&desc, &dsf, cr, area);
4186 assert(err == NULL); 4193 assert(err == NULL);
4187 dsf_to_blocks(dsf, state->kblocks, cr, area); 4194 dsf_to_blocks(dsf, state->kblocks, cr, area);
4188 sfree(dsf); 4195 dsf_free(dsf);
4189 make_blocks_from_whichblock(state->kblocks); 4196 make_blocks_from_whichblock(state->kblocks);
4190 4197
4191 assert(*desc == ','); 4198 assert(*desc == ',');
@@ -4550,6 +4557,17 @@ struct game_ui {
4550 * allowed on immutable squares. 4557 * allowed on immutable squares.
4551 */ 4558 */
4552 bool hcursor; 4559 bool hcursor;
4560
4561 /*
4562 * User preference option: if the user right-clicks in a square
4563 * and presses a number or letter key to add/remove a pencil mark,
4564 * do we hide the mouse highlight again afterwards?
4565 *
4566 * Historically our answer was yes. The Android port prefers no.
4567 * There are advantages both ways, depending how much you dislike
4568 * the highlight cluttering your view. So it's a preference.
4569 */
4570 bool pencil_keep_highlight;
4553}; 4571};
4554 4572
4555static game_ui *new_ui(const game_state *state) 4573static game_ui *new_ui(const game_state *state)
@@ -4558,8 +4576,9 @@ static game_ui *new_ui(const game_state *state)
4558 4576
4559 ui->hx = ui->hy = 0; 4577 ui->hx = ui->hy = 0;
4560 ui->hpencil = false; 4578 ui->hpencil = false;
4561 ui->hshow = false; 4579 ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false);
4562 ui->hcursor = false; 4580
4581 ui->pencil_keep_highlight = false;
4563 4582
4564 return ui; 4583 return ui;
4565} 4584}
@@ -4569,13 +4588,26 @@ static void free_ui(game_ui *ui)
4569 sfree(ui); 4588 sfree(ui);
4570} 4589}
4571 4590
4572static char *encode_ui(const game_ui *ui) 4591static config_item *get_prefs(game_ui *ui)
4573{ 4592{
4574 return NULL; 4593 config_item *ret;
4594
4595 ret = snewn(2, config_item);
4596
4597 ret[0].name = "Keep mouse highlight after changing a pencil mark";
4598 ret[0].kw = "pencil-keep-highlight";
4599 ret[0].type = C_BOOLEAN;
4600 ret[0].u.boolean.bval = ui->pencil_keep_highlight;
4601
4602 ret[1].name = NULL;
4603 ret[1].type = C_END;
4604
4605 return ret;
4575} 4606}
4576 4607
4577static void decode_ui(game_ui *ui, const char *encoding) 4608static void set_prefs(game_ui *ui, const config_item *cfg)
4578{ 4609{
4610 ui->pencil_keep_highlight = cfg[0].u.boolean.bval;
4579} 4611}
4580 4612
4581static void game_changed_state(game_ui *ui, const game_state *oldstate, 4613static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -4594,6 +4626,14 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
4594 } 4626 }
4595} 4627}
4596 4628
4629static const char *current_key_label(const game_ui *ui,
4630 const game_state *state, int button)
4631{
4632 if (ui->hshow && (button == CURSOR_SELECT))
4633 return ui->hpencil ? "Ink" : "Pencil";
4634 return "";
4635}
4636
4597struct game_drawstate { 4637struct game_drawstate {
4598 bool started, xtype; 4638 bool started, xtype;
4599 int cr; 4639 int cr;
@@ -4613,7 +4653,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
4613 int tx, ty; 4653 int tx, ty;
4614 char buf[80]; 4654 char buf[80];
4615 4655
4616 button &= ~MOD_MASK; 4656 button = STRIP_BUTTON_MODIFIERS(button);
4617 4657
4618 tx = (x + TILE_SIZE - BORDER) / TILE_SIZE - 1; 4658 tx = (x + TILE_SIZE - BORDER) / TILE_SIZE - 1;
4619 ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1; 4659 ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1;
@@ -4632,7 +4672,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
4632 ui->hpencil = false; 4672 ui->hpencil = false;
4633 } 4673 }
4634 ui->hcursor = false; 4674 ui->hcursor = false;
4635 return UI_UPDATE; 4675 return MOVE_UI_UPDATE;
4636 } 4676 }
4637 if (button == RIGHT_BUTTON) { 4677 if (button == RIGHT_BUTTON) {
4638 /* 4678 /*
@@ -4652,20 +4692,19 @@ static char *interpret_move(const game_state *state, game_ui *ui,
4652 ui->hshow = false; 4692 ui->hshow = false;
4653 } 4693 }
4654 ui->hcursor = false; 4694 ui->hcursor = false;
4655 return UI_UPDATE; 4695 return MOVE_UI_UPDATE;
4656 } 4696 }
4657 } 4697 }
4658 if (IS_CURSOR_MOVE(button)) { 4698 if (IS_CURSOR_MOVE(button)) {
4659 move_cursor(button, &ui->hx, &ui->hy, cr, cr, false);
4660 ui->hshow = true;
4661 ui->hcursor = true; 4699 ui->hcursor = true;
4662 return UI_UPDATE; 4700 return move_cursor(button, &ui->hx, &ui->hy, cr, cr, false,
4701 &ui->hshow);
4663 } 4702 }
4664 if (ui->hshow && 4703 if (ui->hshow &&
4665 (button == CURSOR_SELECT)) { 4704 (button == CURSOR_SELECT)) {
4666 ui->hpencil = !ui->hpencil; 4705 ui->hpencil = !ui->hpencil;
4667 ui->hcursor = true; 4706 ui->hcursor = true;
4668 return UI_UPDATE; 4707 return MOVE_UI_UPDATE;
4669 } 4708 }
4670 4709
4671 if (ui->hshow && 4710 if (ui->hshow &&
@@ -4695,10 +4734,37 @@ static char *interpret_move(const game_state *state, game_ui *ui,
4695 if (ui->hpencil && state->grid[ui->hy*cr+ui->hx]) 4734 if (ui->hpencil && state->grid[ui->hy*cr+ui->hx])
4696 return NULL; 4735 return NULL;
4697 4736
4737 /*
4738 * If you ask to fill a square with what it already contains,
4739 * or blank it when it's already empty, that has no effect...
4740 */
4741 if ((!ui->hpencil || n == 0) && state->grid[ui->hy*cr+ui->hx] == n) {
4742 bool anypencil = false;
4743 int i;
4744 for (i = 0; i < cr; i++)
4745 anypencil = anypencil ||
4746 state->pencil[(ui->hy*cr+ui->hx) * cr + i];
4747 if (!anypencil) {
4748 /* ... expect to remove the cursor in mouse mode. */
4749 if (!ui->hcursor) {
4750 ui->hshow = false;
4751 return MOVE_UI_UPDATE;
4752 }
4753 return NULL;
4754 }
4755 }
4756
4698 sprintf(buf, "%c%d,%d,%d", 4757 sprintf(buf, "%c%d,%d,%d",
4699 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); 4758 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n);
4700 4759
4701 if (!ui->hcursor) ui->hshow = false; 4760 /*
4761 * Hide the highlight after a keypress, if it was mouse-
4762 * generated. Also, don't hide it if this move has changed
4763 * pencil marks and the user preference says not to hide the
4764 * highlight in that situation.
4765 */
4766 if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight))
4767 ui->hshow = false;
4702 4768
4703 return dupstr(buf); 4769 return dupstr(buf);
4704 } 4770 }
@@ -4787,7 +4853,7 @@ static game_state *execute_move(const game_state *from, const char *move)
4787#define GETTILESIZE(cr, w) ( (double)(w-1) / (double)(cr+1) ) 4853#define GETTILESIZE(cr, w) ( (double)(w-1) / (double)(cr+1) )
4788 4854
4789static void game_compute_size(const game_params *params, int tilesize, 4855static void game_compute_size(const game_params *params, int tilesize,
4790 int *x, int *y) 4856 const game_ui *ui, int *x, int *y)
4791{ 4857{
4792 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 4858 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
4793 struct { int tilesize; } ads, *ds = &ads; 4859 struct { int tilesize; } ads, *ds = &ads;
@@ -4920,6 +4986,18 @@ static void draw_number(drawing *dr, game_drawstate *ds,
4920 (ds->xtype && (ondiag0(y*cr+x) || ondiag1(y*cr+x))) ? COL_XDIAGONALS : 4986 (ds->xtype && (ondiag0(y*cr+x) || ondiag1(y*cr+x))) ? COL_XDIAGONALS :
4921 COL_BACKGROUND)); 4987 COL_BACKGROUND));
4922 4988
4989 /* pencil-mode highlight */
4990 if ((hl & 15) == 2) {
4991 int coords[6];
4992 coords[0] = cx;
4993 coords[1] = cy;
4994 coords[2] = cx+cw/2;
4995 coords[3] = cy;
4996 coords[4] = cx;
4997 coords[5] = cy+ch/2;
4998 draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT);
4999 }
5000
4923 /* 5001 /*
4924 * Draw the corners of thick lines in corner-adjacent squares, 5002 * Draw the corners of thick lines in corner-adjacent squares,
4925 * which jut into this square by one pixel. 5003 * which jut into this square by one pixel.
@@ -4933,18 +5011,6 @@ static void draw_number(drawing *dr, game_drawstate *ds,
4933 if (x+1 < cr && y+1 < cr && state->blocks->whichblock[y*cr+x] != state->blocks->whichblock[(y+1)*cr+x+1]) 5011 if (x+1 < cr && y+1 < cr && state->blocks->whichblock[y*cr+x] != state->blocks->whichblock[(y+1)*cr+x+1])
4934 draw_rect(dr, tx+TILE_SIZE-1-2*GRIDEXTRA, ty+TILE_SIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); 5012 draw_rect(dr, tx+TILE_SIZE-1-2*GRIDEXTRA, ty+TILE_SIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID);
4935 5013
4936 /* pencil-mode highlight */
4937 if ((hl & 15) == 2) {
4938 int coords[6];
4939 coords[0] = cx;
4940 coords[1] = cy;
4941 coords[2] = cx+cw/2;
4942 coords[3] = cy;
4943 coords[4] = cx;
4944 coords[5] = cy+ch/2;
4945 draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT);
4946 }
4947
4948 if (state->kblocks) { 5014 if (state->kblocks) {
4949 int t = GRIDEXTRA * 3; 5015 int t = GRIDEXTRA * 3;
4950 int kcx, kcy, kcw, kch; 5016 int kcx, kcy, kcw, kch;
@@ -5104,7 +5170,7 @@ static void draw_number(drawing *dr, game_drawstate *ds,
5104 fw = (pr - pl) / (float)pw; 5170 fw = (pr - pl) / (float)pw;
5105 fh = (pb - pt) / (float)ph; 5171 fh = (pb - pt) / (float)ph;
5106 fs = min(fw, fh); 5172 fs = min(fw, fh);
5107 if (fs > bestsize) { 5173 if (fs >= bestsize) {
5108 bestsize = fs; 5174 bestsize = fs;
5109 pbest = pw; 5175 pbest = pw;
5110 } 5176 }
@@ -5175,14 +5241,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
5175 5241
5176 if (!ds->started) { 5242 if (!ds->started) {
5177 /* 5243 /*
5178 * The initial contents of the window are not guaranteed
5179 * and can vary with front ends. To be on the safe side,
5180 * all games should start by drawing a big
5181 * background-colour rectangle covering the whole window.
5182 */
5183 draw_rect(dr, 0, 0, SIZE(cr), SIZE(cr), COL_BACKGROUND);
5184
5185 /*
5186 * Draw the grid. We draw it as a big thick rectangle of 5244 * Draw the grid. We draw it as a big thick rectangle of
5187 * COL_GRID initially; individual calls to draw_number() 5245 * COL_GRID initially; individual calls to draw_number()
5188 * will poke the right-shaped holes in it. 5246 * will poke the right-shaped holes in it.
@@ -5315,14 +5373,8 @@ static int game_status(const game_state *state)
5315 return state->completed ? +1 : 0; 5373 return state->completed ? +1 : 0;
5316} 5374}
5317 5375
5318static bool game_timing_state(const game_state *state, game_ui *ui) 5376static void game_print_size(const game_params *params, const game_ui *ui,
5319{ 5377 float *x, float *y)
5320 if (state->completed)
5321 return false;
5322 return true;
5323}
5324
5325static void game_print_size(const game_params *params, float *x, float *y)
5326{ 5378{
5327 int pw, ph; 5379 int pw, ph;
5328 5380
@@ -5331,7 +5383,7 @@ static void game_print_size(const game_params *params, float *x, float *y)
5331 * for this game, because players will want to jot down no end 5383 * for this game, because players will want to jot down no end
5332 * of pencil marks in the squares. 5384 * of pencil marks in the squares.
5333 */ 5385 */
5334 game_compute_size(params, 900, &pw, &ph); 5386 game_compute_size(params, 900, ui, &pw, &ph);
5335 *x = pw / 100.0F; 5387 *x = pw / 100.0F;
5336 *y = ph / 100.0F; 5388 *y = ph / 100.0F;
5337} 5389}
@@ -5505,7 +5557,8 @@ static void outline_block_structure(drawing *dr, game_drawstate *ds,
5505 sfree(coords); 5557 sfree(coords);
5506} 5558}
5507 5559
5508static void game_print(drawing *dr, const game_state *state, int tilesize) 5560static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
5561 int tilesize)
5509{ 5562{
5510 int cr = state->cr; 5563 int cr = state->cr;
5511 int ink = print_mono_colour(dr, 0); 5564 int ink = print_mono_colour(dr, 0);
@@ -5620,12 +5673,14 @@ const struct game thegame = {
5620 free_game, 5673 free_game,
5621 true, solve_game, 5674 true, solve_game,
5622 true, game_can_format_as_text_now, game_text_format, 5675 true, game_can_format_as_text_now, game_text_format,
5676 get_prefs, set_prefs,
5623 new_ui, 5677 new_ui,
5624 free_ui, 5678 free_ui,
5625 encode_ui, 5679 NULL, /* encode_ui */
5626 decode_ui, 5680 NULL, /* decode_ui */
5627 game_request_keys, 5681 game_request_keys,
5628 game_changed_state, 5682 game_changed_state,
5683 current_key_label,
5629 interpret_move, 5684 interpret_move,
5630 execute_move, 5685 execute_move,
5631 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 5686 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -5639,7 +5694,7 @@ const struct game thegame = {
5639 game_status, 5694 game_status,
5640 true, false, game_print_size, game_print, 5695 true, false, game_print_size, game_print,
5641 false, /* wants_statusbar */ 5696 false, /* wants_statusbar */
5642 false, game_timing_state, 5697 false, NULL, /* timing_state */
5643 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ 5698 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */
5644}; 5699};
5645 5700