X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=dominosa.c;h=c86ba19dfade335d9925fbef8ca1b354513e5037;hb=db313b3948d27244dd7c34c2609c66d6204d8931;hp=d80425caf489b565de12527cbbc02153f9eb3b45;hpb=0b93de904a98f119b1a95d3a53029f1ed4bfb9b3;p=sgt-puzzles.git diff --git a/dominosa.c b/dominosa.c index d80425c..c86ba19 100644 --- a/dominosa.c +++ b/dominosa.c @@ -64,6 +64,8 @@ enum { COL_DOMINOCLASH, COL_DOMINOTEXT, COL_EDGE, + COL_HIGHLIGHT_1, + COL_HIGHLIGHT_2, NCOLOURS }; @@ -133,7 +135,7 @@ static void free_params(game_params *params) sfree(params); } -static game_params *dup_params(game_params *params) +static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ @@ -148,7 +150,7 @@ static void decode_params(game_params *params, char const *string) params->unique = FALSE; } -static char *encode_params(game_params *params, int full) +static char *encode_params(const game_params *params, int full) { char buf[80]; sprintf(buf, "%d", params->n); @@ -157,7 +159,7 @@ static char *encode_params(game_params *params, int full) return dupstr(buf); } -static config_item *game_configure(game_params *params) +static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; @@ -183,7 +185,7 @@ static config_item *game_configure(game_params *params) return ret; } -static game_params *custom_params(config_item *cfg) +static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); @@ -193,7 +195,7 @@ static game_params *custom_params(config_item *cfg) return ret; } -static char *validate_params(game_params *params, int full) +static char *validate_params(const game_params *params, int full) { if (params->n < 1) return "Maximum face number must be at least one"; @@ -746,7 +748,7 @@ static char *new_game_desc(const game_params *params, random_state *rs, return ret; } -static char *validate_desc(const game_params *params, char *desc) +static char *validate_desc(const game_params *params, const char *desc) { int n = params->n, w = n+2, h = n+1, wh = w*h; int *occurrences; @@ -797,7 +799,8 @@ static char *validate_desc(const game_params *params, char *desc) return ret; } -static game_state *new_game(midend *me, game_params *params, char *desc) +static game_state *new_game(midend *me, const game_params *params, + const char *desc) { int n = params->n, w = n+2, h = n+1, wh = w*h; game_state *state = snew(game_state); @@ -840,7 +843,7 @@ static game_state *new_game(midend *me, game_params *params, char *desc) return state; } -static game_state *dup_game(game_state *state) +static game_state *dup_game(const game_state *state) { int n = state->params.n, w = n+2, h = n+1, wh = w*h; game_state *ret = snew(game_state); @@ -871,8 +874,8 @@ static void free_game(game_state *state) sfree(state); } -static char *solve_game(game_state *state, game_state *currstate, - char *aux, char **error) +static char *solve_game(const game_state *state, const game_state *currstate, + const char *aux, char **error) { int n = state->params.n, w = n+2, h = n+1, wh = w*h; int *placements; @@ -941,25 +944,88 @@ static char *solve_game(game_state *state, game_state *currstate, return ret; } -static int game_can_format_as_text_now(game_params *params) +static int game_can_format_as_text_now(const game_params *params) { - return TRUE; + return params->n < 1000; } -static char *game_text_format(game_state *state) +static void draw_domino(char *board, int start, char corner, + int dshort, int nshort, char cshort, + int dlong, int nlong, char clong) { - return NULL; + int go_short = nshort*dshort, go_long = nlong*dlong, i; + + board[start] = corner; + board[start + go_short] = corner; + board[start + go_long] = corner; + board[start + go_short + go_long] = corner; + + for (i = 1; i < nshort; ++i) { + int j = start + i*dshort, k = start + i*dshort + go_long; + if (board[j] != corner) board[j] = cshort; + if (board[k] != corner) board[k] = cshort; + } + + for (i = 1; i < nlong; ++i) { + int j = start + i*dlong, k = start + i*dlong + go_short; + if (board[j] != corner) board[j] = clong; + if (board[k] != corner) board[k] = clong; + } +} + +static char *game_text_format(const game_state *state) +{ + int w = state->w, h = state->h, r, c; + int cw = 4, ch = 2, gw = cw*w + 2, gh = ch * h + 1, len = gw * gh; + char *board = snewn(len + 1, char); + + memset(board, ' ', len); + + for (r = 0; r < h; ++r) { + for (c = 0; c < w; ++c) { + int cell = r*ch*gw + cw*c, center = cell + gw*ch/2 + cw/2; + int i = r*w + c, num = state->numbers->numbers[i]; + + if (num < 100) { + board[center] = '0' + num % 10; + if (num >= 10) board[center - 1] = '0' + num / 10; + } else { + board[center+1] = '0' + num % 10; + board[center] = '0' + num / 10 % 10; + board[center-1] = '0' + num / 100; + } + + if (state->edges[i] & EDGE_L) board[center - cw/2] = '|'; + if (state->edges[i] & EDGE_R) board[center + cw/2] = '|'; + if (state->edges[i] & EDGE_T) board[center - gw] = '-'; + if (state->edges[i] & EDGE_B) board[center + gw] = '-'; + + if (state->grid[i] == i) continue; /* no domino pairing */ + if (state->grid[i] < i) continue; /* already done */ + assert (state->grid[i] == i + 1 || state->grid[i] == i + w); + if (state->grid[i] == i + 1) + draw_domino(board, cell, '+', gw, ch, '|', +1, 2*cw, '-'); + else if (state->grid[i] == i + w) + draw_domino(board, cell, '+', +1, cw, '-', gw, 2*ch, '|'); + } + board[r*ch*gw + gw - 1] = '\n'; + board[r*ch*gw + gw + gw - 1] = '\n'; + } + board[len - 1] = '\n'; + board[len] = '\0'; + return board; } struct game_ui { - int cur_x, cur_y, cur_visible; + int cur_x, cur_y, cur_visible, highlight_1, highlight_2; }; -static game_ui *new_ui(game_state *state) +static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->cur_x = ui->cur_y = 0; ui->cur_visible = 0; + ui->highlight_1 = ui->highlight_2 = -1; return ui; } @@ -968,17 +1034,17 @@ static void free_ui(game_ui *ui) sfree(ui); } -static char *encode_ui(game_ui *ui) +static char *encode_ui(const game_ui *ui) { return NULL; } -static void decode_ui(game_ui *ui, char *encoding) +static void decode_ui(game_ui *ui, const char *encoding) { } -static void game_changed_state(game_ui *ui, game_state *oldstate, - game_state *newstate) +static void game_changed_state(game_ui *ui, const game_state *oldstate, + const game_state *newstate) { if (!oldstate->completed && newstate->completed) ui->cur_visible = 0; @@ -1001,8 +1067,9 @@ struct game_drawstate { unsigned long *visible; }; -static char *interpret_move(game_state *state, game_ui *ui, const game_drawstate *ds, - int x, int y, int button) +static char *interpret_move(const game_state *state, game_ui *ui, + const game_drawstate *ds, + int x, int y, int button) { int w = state->w, h = state->h; char buf[80]; @@ -1070,12 +1137,28 @@ static char *interpret_move(game_state *state, game_ui *ui, const game_drawstate sprintf(buf, "%c%d,%d", (int)(button == CURSOR_SELECT2 ? 'E' : 'D'), d1, d2); return dupstr(buf); + } else if (isdigit(button)) { + int n = state->params.n, num = button - '0'; + if (num > n) { + return NULL; + } else if (ui->highlight_1 == num) { + ui->highlight_1 = -1; + } else if (ui->highlight_2 == num) { + ui->highlight_2 = -1; + } else if (ui->highlight_1 == -1) { + ui->highlight_1 = num; + } else if (ui->highlight_2 == -1) { + ui->highlight_2 = num; + } else { + return NULL; + } + return ""; } return NULL; } -static game_state *execute_move(game_state *state, char *move) +static game_state *execute_move(const game_state *state, const char *move) { int n = state->params.n, w = n+2, h = n+1, wh = w*h; int d1, d2, d3, p; @@ -1230,8 +1313,8 @@ static game_state *execute_move(game_state *state, char *move) * Drawing routines. */ -static void game_compute_size(game_params *params, int tilesize, - int *x, int *y) +static void game_compute_size(const game_params *params, int tilesize, + int *x, int *y) { int n = params->n, w = n+2, h = n+1; @@ -1244,7 +1327,7 @@ static void game_compute_size(game_params *params, int tilesize, } static void game_set_size(drawing *dr, game_drawstate *ds, - game_params *params, int tilesize) + const game_params *params, int tilesize) { ds->tilesize = tilesize; } @@ -1275,11 +1358,19 @@ static float *game_colours(frontend *fe, int *ncolours) ret[COL_EDGE * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2 / 3; ret[COL_EDGE * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2 / 3; + ret[COL_HIGHLIGHT_1 * 3 + 0] = 0.85; + ret[COL_HIGHLIGHT_1 * 3 + 1] = 0.20; + ret[COL_HIGHLIGHT_1 * 3 + 2] = 0.20; + + ret[COL_HIGHLIGHT_2 * 3 + 0] = 0.30; + ret[COL_HIGHLIGHT_2 * 3 + 1] = 0.85; + ret[COL_HIGHLIGHT_2 * 3 + 2] = 0.20; + *ncolours = NCOLOURS; return ret; } -static game_drawstate *game_new_drawstate(drawing *dr, game_state *state) +static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; @@ -1315,6 +1406,8 @@ enum { * EDGE_* [0x100 -- 0xF00] * and must fit into an unsigned long (32 bits). */ +#define DF_HIGHLIGHT_1 0x10 +#define DF_HIGHLIGHT_2 0x20 #define DF_FLASH 0x40 #define DF_CLASH 0x80 @@ -1328,8 +1421,8 @@ enum { #define CEDGE_OFF (TILESIZE / 8) #define IS_EMPTY(s,x,y) ((s)->grid[(y)*(s)->w+(x)] == ((y)*(s)->w+(x))) -static void draw_tile(drawing *dr, game_drawstate *ds, game_state *state, - int x, int y, int type) +static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state, + int x, int y, int type, int highlight_1, int highlight_2) { int w = state->w /*, h = state->h */; int cx = COORD(x), cy = COORD(y); @@ -1425,6 +1518,12 @@ static void draw_tile(drawing *dr, game_drawstate *ds, game_state *state, draw_rect_corners(dr, ox, oy, CURSOR_RADIUS+1, nc); } + if (flags & DF_HIGHLIGHT_1) { + nc = COL_HIGHLIGHT_1; + } else if (flags & DF_HIGHLIGHT_2) { + nc = COL_HIGHLIGHT_2; + } + sprintf(str, "%d", state->numbers->numbers[y*w+x]); draw_text(dr, cx+TILESIZE/2, cy+TILESIZE/2, FONT_VARIABLE, TILESIZE/2, ALIGN_HCENTRE | ALIGN_VCENTRE, nc, str); @@ -1433,9 +1532,10 @@ static void draw_tile(drawing *dr, game_drawstate *ds, game_state *state, unclip(dr); } -static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, - game_state *state, int dir, game_ui *ui, - float animtime, float flashtime) +static void game_redraw(drawing *dr, game_drawstate *ds, + const game_state *oldstate, const game_state *state, + int dir, const game_ui *ui, + float animtime, float flashtime) { int n = state->params.n, w = state->w, h = state->h, wh = w*h; int x, y, i; @@ -1486,8 +1586,8 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, else c = TYPE_BLANK; + n1 = state->numbers->numbers[n]; if (c != TYPE_BLANK) { - n1 = state->numbers->numbers[n]; n2 = state->numbers->numbers[state->grid[n]]; di = DINDEX(n1, n2); if (used[di] > 1) @@ -1496,6 +1596,11 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, c |= state->edges[n]; } + if (n1 == ui->highlight_1) + c |= DF_HIGHLIGHT_1; + if (n1 == ui->highlight_2) + c |= DF_HIGHLIGHT_2; + if (flashtime != 0) c |= DF_FLASH; /* we're flashing */ @@ -1512,7 +1617,8 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, } if (ds->visible[n] != c) { - draw_tile(dr, ds, state, x, y, c); + draw_tile(dr, ds, state, x, y, c, + ui->highlight_1, ui->highlight_2); ds->visible[n] = c; } } @@ -1520,32 +1626,35 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, sfree(used); } -static float game_anim_length(game_state *oldstate, game_state *newstate, - int dir, game_ui *ui) +static float game_anim_length(const game_state *oldstate, + const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } -static float game_flash_length(game_state *oldstate, game_state *newstate, - int dir, game_ui *ui) +static float game_flash_length(const game_state *oldstate, + const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) + { + ui->highlight_1 = ui->highlight_2 = -1; return FLASH_TIME; + } return 0.0F; } -static int game_status(game_state *state) +static int game_status(const game_state *state) { return state->completed ? +1 : 0; } -static int game_timing_state(game_state *state, game_ui *ui) +static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } -static void game_print_size(game_params *params, float *x, float *y) +static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; @@ -1557,7 +1666,7 @@ static void game_print_size(game_params *params, float *x, float *y) *y = ph / 100.0F; } -static void game_print(drawing *dr, game_state *state, int tilesize) +static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->w, h = state->h; int c, x, y; @@ -1589,7 +1698,7 @@ static void game_print(drawing *dr, game_state *state, int tilesize) else c = TYPE_BLANK; - draw_tile(dr, ds, state, x, y, c); + draw_tile(dr, ds, state, x, y, c, -1, -1); } } @@ -1600,7 +1709,7 @@ static void game_print(drawing *dr, game_state *state, int tilesize) const struct game thegame = { "Dominosa", "games.dominosa", "dominosa", default_params, - game_fetch_preset, + game_fetch_preset, NULL, decode_params, encode_params, free_params, @@ -1613,7 +1722,7 @@ const struct game thegame = { dup_game, free_game, TRUE, solve_game, - FALSE, game_can_format_as_text_now, game_text_format, + TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui,