/*
* TODO:
*
- * - The dragging semantics are still subtly wrong in complex
- * cases.
- *
* - Improve the generator.
* * actually, we seem to be mostly sensible already now. I
* want more choice over the type of main block and location
* target marker pale.
* * The cattle grid effect is still disgusting. Think of
* something completely different.
- * * I think TRCIRC and BLCIRC should actually be drawn, as a
- * pair of differently coloured octants. Haul out the
- * Bresenham code, I suspect.
* * The highlight for next-piece-to-move in the solver is
* excessive, and the shadow blends in too well with the
* piece lowlights. Adjust both.
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 */
}
}
-static char *encode_params(game_params *params, int full)
+static char *encode_params(const game_params *params, int full)
{
char data[256];
return dupstr(data);
}
-static config_item *game_configure(game_params *params)
+static config_item *game_configure(const game_params *params)
{
config_item *ret;
char buf[80];
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);
return ret;
}
-static char *validate_params(game_params *params, int full)
+static char *validate_params(const game_params *params, int full)
{
if (params->w > MAXWID)
return "Width must be at most " STR(MAXWID);
int *list, nlist, pos;
int tx, ty;
int i, j;
- int moves;
+ int moves = 0; /* placate optimiser */
/*
* Set up a board and fill it with singletons, except for a
}
}
+ sfree(dsf);
+ sfree(list);
+ sfree(tried_merge);
sfree(board2);
*rtx = tx;
* End of solver/generator code.
*/
-static char *new_game_desc(game_params *params, random_state *rs,
+static char *new_game_desc(const game_params *params, random_state *rs,
char **aux, int interactive)
{
int w = params->w, h = params->h, wh = w*h;
return ret;
}
-static char *validate_desc(game_params *params, char *desc)
+static char *validate_desc(const game_params *params, const char *desc)
{
int w = params->w, h = params->h, wh = w*h;
int *active, *link;
- int mains = 0, mpos = -1;
+ int mains = 0;
int i, tx, ty, minmoves;
char *ret;
link[i] = -1;
if (strchr("mM", c) != NULL) {
mains++;
- mpos = i;
}
i++;
}
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 w = params->w, h = params->h, wh = w*h;
game_state *state;
return state;
}
-static game_state *dup_game(game_state *state)
+static game_state *dup_game(const game_state *state)
{
int w = state->w, h = state->h, wh = w*h;
game_state *ret = snew(game_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 *moves;
int nmoves;
return ret;
}
-static char *game_text_format(game_state *state)
+static int game_can_format_as_text_now(const game_params *params)
+{
+ return TRUE;
+}
+
+static char *game_text_format(const game_state *state)
{
return board_text_format(state->w, state->h, state->board,
state->imm->forcefield);
int *bfs_queue; /* used as scratch in interpret_move */
};
-static game_ui *new_ui(game_state *state)
+static game_ui *new_ui(const game_state *state)
{
int w = state->w, h = state->h, wh = w*h;
game_ui *ui = snew(game_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)
{
}
int started;
};
-static char *interpret_move(game_state *state, game_ui *ui, 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, wh = w*h;
int tx, ty, i, j;
*/
return "";
} else if (button == LEFT_DRAG && ui->dragging) {
+ int dist, distlimit, dx, dy, s, px, py;
+
tx = FROMCOORD(x);
ty = FROMCOORD(y);
tx -= ui->drag_offset_x;
ty -= ui->drag_offset_y;
- if (tx < 0 || tx >= w || ty < 0 || ty >= h ||
- !ui->reachable[ty*w+tx])
- return NULL; /* this drag has no effect */
- ui->drag_currpos = ty*w+tx;
- return "";
+ /*
+ * Now search outwards from (tx,ty), in order of Manhattan
+ * distance, until we find a reachable square.
+ */
+ distlimit = w+tx;
+ distlimit = max(distlimit, h+ty);
+ distlimit = max(distlimit, tx);
+ distlimit = max(distlimit, ty);
+ for (dist = 0; dist <= distlimit; dist++) {
+ for (dx = -dist; dx <= dist; dx++)
+ for (s = -1; s <= +1; s += 2) {
+ dy = s * (dist - abs(dx));
+ px = tx + dx;
+ py = ty + dy;
+ if (px >= 0 && px < w && py >= 0 && py < h &&
+ ui->reachable[py*w+px]) {
+ ui->drag_currpos = py*w+px;
+ return "";
+ }
+ }
+ }
+ return NULL; /* give up - this drag has no effect */
} else if (button == LEFT_RELEASE && ui->dragging) {
char data[256], *str;
return TRUE;
}
-static game_state *execute_move(game_state *state, char *move)
+static game_state *execute_move(const game_state *state, const char *move)
{
int w = state->w, h = state->h /* , wh = w*h */;
char c;
* 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)
{
/* fool the macros */
- struct dummy { int tilesize; } dummy = { tilesize }, *ds = &dummy;
+ struct dummy { int tilesize; } dummy, *ds = &dummy;
+ dummy.tilesize = tilesize;
*x = params->w * TILESIZE + 2*BORDER;
*y = params->h * TILESIZE + 2*BORDER;
}
static void game_set_size(drawing *dr, game_drawstate *ds,
- game_params *params, int tilesize)
+ const game_params *params, int tilesize)
{
ds->tilesize = tilesize;
}
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)
{
int w = state->w, h = state->h, wh = w*h;
struct game_drawstate *ds = snew(struct game_drawstate);
#define TYPE_TRCIRC 0x5000
#define TYPE_BLCIRC 0x6000
#define TYPE_BRCIRC 0x7000
-static void maybe_rect(drawing *dr, int x, int y, int w, int h, int coltype)
+static void maybe_rect(drawing *dr, int x, int y, int w, int h,
+ int coltype, int col2)
{
int colour = coltype & COL_MASK, type = coltype & TYPE_MASK;
cx = x;
cy = y;
- assert(w == h);
r = w-1;
if (type & 0x1000)
cx += r;
if (type & 0x2000)
cy += r;
- draw_circle(dr, cx, cy, r, colour, colour);
+
+ if (col2 == -1 || col2 == coltype) {
+ assert(w == h);
+ draw_circle(dr, cx, cy, r, colour, colour);
+ } else {
+ /*
+ * We aim to draw a quadrant of a circle in two
+ * different colours. We do this using Bresenham's
+ * algorithm directly, because the Puzzles drawing API
+ * doesn't have a draw-sector primitive.
+ */
+ int bx, by, bd, bd2;
+ int xm = (type & 0x1000 ? -1 : +1);
+ int ym = (type & 0x2000 ? -1 : +1);
+
+ by = r;
+ bx = 0;
+ bd = 0;
+ while (by >= bx) {
+ /*
+ * Plot the point.
+ */
+ {
+ int x1 = cx+xm*bx, y1 = cy+ym*bx;
+ int x2, y2;
+
+ x2 = cx+xm*by; y2 = y1;
+ draw_rect(dr, min(x1,x2), min(y1,y2),
+ abs(x1-x2)+1, abs(y1-y2)+1, colour);
+ x2 = x1; y2 = cy+ym*by;
+ draw_rect(dr, min(x1,x2), min(y1,y2),
+ abs(x1-x2)+1, abs(y1-y2)+1, col2);
+ }
+
+ bd += 2*bx + 1;
+ bd2 = bd - (2*by - 1);
+ if (abs(bd2) < abs(bd)) {
+ bd = bd2;
+ by--;
+ }
+ bx++;
+ }
+ }
unclip(dr);
}
int tx, int ty, unsigned long val,
int cl, int cc, int ch)
{
+ int coords[6];
+
draw_rect(dr, tx, ty, TILESIZE, TILESIZE, cc);
if (val & PIECE_LBORDER)
draw_rect(dr, tx, ty, HIGHLIGHT_WIDTH, TILESIZE,
if (val & PIECE_BBORDER)
draw_rect(dr, tx, ty+TILESIZE-HIGHLIGHT_WIDTH,
TILESIZE, HIGHLIGHT_WIDTH, cl);
- if (!((PIECE_BBORDER | PIECE_LBORDER) &~ val))
+ if (!((PIECE_BBORDER | PIECE_LBORDER) &~ val)) {
draw_rect(dr, tx, ty+TILESIZE-HIGHLIGHT_WIDTH,
- HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH, cc);
- if (!((PIECE_TBORDER | PIECE_RBORDER) &~ val))
+ HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH, cl);
+ clip(dr, tx, ty+TILESIZE-HIGHLIGHT_WIDTH,
+ HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH);
+ coords[0] = tx - 1;
+ coords[1] = ty + TILESIZE - HIGHLIGHT_WIDTH - 1;
+ coords[2] = tx + HIGHLIGHT_WIDTH;
+ coords[3] = ty + TILESIZE - HIGHLIGHT_WIDTH - 1;
+ coords[4] = tx - 1;
+ coords[5] = ty + TILESIZE;
+ draw_polygon(dr, coords, 3, ch, ch);
+ unclip(dr);
+ } else if (val & PIECE_BLCORNER) {
+ draw_rect(dr, tx, ty+TILESIZE-HIGHLIGHT_WIDTH,
+ HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH, ch);
+ clip(dr, tx, ty+TILESIZE-HIGHLIGHT_WIDTH,
+ HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH);
+ coords[0] = tx - 1;
+ coords[1] = ty + TILESIZE - HIGHLIGHT_WIDTH - 1;
+ coords[2] = tx + HIGHLIGHT_WIDTH;
+ coords[3] = ty + TILESIZE - HIGHLIGHT_WIDTH - 1;
+ coords[4] = tx - 1;
+ coords[5] = ty + TILESIZE;
+ draw_polygon(dr, coords, 3, cl, cl);
+ unclip(dr);
+ }
+ if (!((PIECE_TBORDER | PIECE_RBORDER) &~ val)) {
draw_rect(dr, tx+TILESIZE-HIGHLIGHT_WIDTH, ty,
- HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH, cc);
+ HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH, cl);
+ clip(dr, tx+TILESIZE-HIGHLIGHT_WIDTH, ty,
+ HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH);
+ coords[0] = tx + TILESIZE - HIGHLIGHT_WIDTH - 1;
+ coords[1] = ty - 1;
+ coords[2] = tx + TILESIZE;
+ coords[3] = ty - 1;
+ coords[4] = tx + TILESIZE - HIGHLIGHT_WIDTH - 1;
+ coords[5] = ty + HIGHLIGHT_WIDTH;
+ draw_polygon(dr, coords, 3, ch, ch);
+ unclip(dr);
+ } else if (val & PIECE_TRCORNER) {
+ draw_rect(dr, tx+TILESIZE-HIGHLIGHT_WIDTH, ty,
+ HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH, ch);
+ clip(dr, tx+TILESIZE-HIGHLIGHT_WIDTH, ty,
+ HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH);
+ coords[0] = tx + TILESIZE - HIGHLIGHT_WIDTH - 1;
+ coords[1] = ty - 1;
+ coords[2] = tx + TILESIZE;
+ coords[3] = ty - 1;
+ coords[4] = tx + TILESIZE - HIGHLIGHT_WIDTH - 1;
+ coords[5] = ty + HIGHLIGHT_WIDTH;
+ draw_polygon(dr, coords, 3, cl, cl);
+ unclip(dr);
+ }
if (val & PIECE_TLCORNER)
draw_rect(dr, tx, ty, HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH, ch);
if (val & PIECE_BRCORNER)
maybe_rect(dr, RECT(0,0),
(val & (PIECE_TLCORNER | PIECE_TBORDER |
- PIECE_LBORDER)) ? -1 : cc);
+ PIECE_LBORDER)) ? -1 : cc, -1);
maybe_rect(dr, RECT(1,0),
(val & PIECE_TLCORNER) ? ch : (val & PIECE_TBORDER) ? -1 :
- (val & PIECE_LBORDER) ? ch : cc);
+ (val & PIECE_LBORDER) ? ch : cc, -1);
maybe_rect(dr, RECT(2,0),
- (val & PIECE_TBORDER) ? -1 : cc);
+ (val & PIECE_TBORDER) ? -1 : cc, -1);
maybe_rect(dr, RECT(3,0),
(val & PIECE_TRCORNER) ? cl : (val & PIECE_TBORDER) ? -1 :
- (val & PIECE_RBORDER) ? cl : cc);
+ (val & PIECE_RBORDER) ? cl : cc, -1);
maybe_rect(dr, RECT(4,0),
(val & (PIECE_TRCORNER | PIECE_TBORDER |
- PIECE_RBORDER)) ? -1 : cc);
+ PIECE_RBORDER)) ? -1 : cc, -1);
maybe_rect(dr, RECT(0,1),
(val & PIECE_TLCORNER) ? ch : (val & PIECE_LBORDER) ? -1 :
- (val & PIECE_TBORDER) ? ch : cc);
+ (val & PIECE_TBORDER) ? ch : cc, -1);
maybe_rect(dr, RECT(1,1),
- (val & PIECE_TLCORNER) ? cc : -1);
+ (val & PIECE_TLCORNER) ? cc : -1, -1);
maybe_rect(dr, RECT(1,1),
(val & PIECE_TLCORNER) ? ch | TYPE_TLCIRC :
!((PIECE_TBORDER | PIECE_LBORDER) &~ val) ? ch | TYPE_BRCIRC :
- (val & (PIECE_TBORDER | PIECE_LBORDER)) ? ch : cc);
+ (val & (PIECE_TBORDER | PIECE_LBORDER)) ? ch : cc, -1);
maybe_rect(dr, RECT(2,1),
- (val & PIECE_TBORDER) ? ch : cc);
+ (val & PIECE_TBORDER) ? ch : cc, -1);
+ maybe_rect(dr, RECT(3,1),
+ (val & PIECE_TRCORNER) ? cc : -1, -1);
maybe_rect(dr, RECT(3,1),
(val & (PIECE_TBORDER | PIECE_RBORDER)) == PIECE_TBORDER ? ch :
(val & (PIECE_TBORDER | PIECE_RBORDER)) == PIECE_RBORDER ? cl :
- !((PIECE_TBORDER|PIECE_RBORDER) &~ val) ? cc | TYPE_BLCIRC :
- cc);
+ !((PIECE_TBORDER|PIECE_RBORDER) &~ val) ? cl | TYPE_BLCIRC :
+ (val & PIECE_TRCORNER) ? cl | TYPE_TRCIRC :
+ cc, ch);
maybe_rect(dr, RECT(4,1),
(val & PIECE_TRCORNER) ? ch : (val & PIECE_RBORDER) ? -1 :
- (val & PIECE_TBORDER) ? ch : cc);
+ (val & PIECE_TBORDER) ? ch : cc, -1);
maybe_rect(dr, RECT(0,2),
- (val & PIECE_LBORDER) ? -1 : cc);
+ (val & PIECE_LBORDER) ? -1 : cc, -1);
maybe_rect(dr, RECT(1,2),
- (val & PIECE_LBORDER) ? ch : cc);
+ (val & PIECE_LBORDER) ? ch : cc, -1);
maybe_rect(dr, RECT(2,2),
- cc);
+ cc, -1);
maybe_rect(dr, RECT(3,2),
- (val & PIECE_RBORDER) ? cl : cc);
+ (val & PIECE_RBORDER) ? cl : cc, -1);
maybe_rect(dr, RECT(4,2),
- (val & PIECE_RBORDER) ? -1 : cc);
+ (val & PIECE_RBORDER) ? -1 : cc, -1);
maybe_rect(dr, RECT(0,3),
(val & PIECE_BLCORNER) ? cl : (val & PIECE_LBORDER) ? -1 :
- (val & PIECE_BBORDER) ? cl : cc);
+ (val & PIECE_BBORDER) ? cl : cc, -1);
+ maybe_rect(dr, RECT(1,3),
+ (val & PIECE_BLCORNER) ? cc : -1, -1);
maybe_rect(dr, RECT(1,3),
(val & (PIECE_BBORDER | PIECE_LBORDER)) == PIECE_BBORDER ? cl :
(val & (PIECE_BBORDER | PIECE_LBORDER)) == PIECE_LBORDER ? ch :
- !((PIECE_BBORDER|PIECE_LBORDER) &~ val) ? cc | TYPE_TRCIRC :
- cc);
+ !((PIECE_BBORDER|PIECE_LBORDER) &~ val) ? ch | TYPE_TRCIRC :
+ (val & PIECE_BLCORNER) ? ch | TYPE_BLCIRC :
+ cc, cl);
maybe_rect(dr, RECT(2,3),
- (val & PIECE_BBORDER) ? cl : cc);
+ (val & PIECE_BBORDER) ? cl : cc, -1);
maybe_rect(dr, RECT(3,3),
- (val & PIECE_BRCORNER) ? cc : -1);
+ (val & PIECE_BRCORNER) ? cc : -1, -1);
maybe_rect(dr, RECT(3,3),
(val & PIECE_BRCORNER) ? cl | TYPE_BRCIRC :
!((PIECE_BBORDER | PIECE_RBORDER) &~ val) ? cl | TYPE_TLCIRC :
- (val & (PIECE_BBORDER | PIECE_RBORDER)) ? cl : cc);
+ (val & (PIECE_BBORDER | PIECE_RBORDER)) ? cl : cc, -1);
maybe_rect(dr, RECT(4,3),
(val & PIECE_BRCORNER) ? cl : (val & PIECE_RBORDER) ? -1 :
- (val & PIECE_BBORDER) ? cl : cc);
+ (val & PIECE_BBORDER) ? cl : cc, -1);
maybe_rect(dr, RECT(0,4),
- (val & (PIECE_BLCORNER | PIECE_BBORDER | PIECE_LBORDER)) ? -1 : cc);
+ (val & (PIECE_BLCORNER | PIECE_BBORDER |
+ PIECE_LBORDER)) ? -1 : cc, -1);
maybe_rect(dr, RECT(1,4),
(val & PIECE_BLCORNER) ? ch : (val & PIECE_BBORDER) ? -1 :
- (val & PIECE_LBORDER) ? ch : cc);
+ (val & PIECE_LBORDER) ? ch : cc, -1);
maybe_rect(dr, RECT(2,4),
- (val & PIECE_BBORDER) ? -1 : cc);
+ (val & PIECE_BBORDER) ? -1 : cc, -1);
maybe_rect(dr, RECT(3,4),
(val & PIECE_BRCORNER) ? cl : (val & PIECE_BBORDER) ? -1 :
- (val & PIECE_RBORDER) ? cl : cc);
+ (val & PIECE_RBORDER) ? cl : cc, -1);
maybe_rect(dr, RECT(4,4),
(val & (PIECE_BRCORNER | PIECE_BBORDER |
- PIECE_RBORDER)) ? -1 : cc);
+ PIECE_RBORDER)) ? -1 : cc, -1);
#undef RECT
}
return val;
}
-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 w = state->w, h = state->h, wh = w*h;
unsigned char *board;
sfree(board);
}
-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 < 0 && newstate->completed >= 0)
return FLASH_TIME;
return 0.0F;
}
-static int game_timing_state(game_state *state, game_ui *ui)
+static int game_status(const game_state *state)
+{
+ return state->completed ? +1 : 0;
+}
+
+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)
{
}
-static void game_print(drawing *dr, game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, int tilesize)
{
}
#ifdef COMBINED
-#define thegame nullgame
+#define thegame slide
#endif
const struct game thegame = {
"Slide", NULL, NULL,
default_params,
- game_fetch_preset,
+ game_fetch_preset, NULL,
decode_params,
encode_params,
free_params,
dup_game,
free_game,
TRUE, solve_game,
- TRUE, game_text_format,
+ TRUE, game_can_format_as_text_now, game_text_format,
new_ui,
free_ui,
encode_ui,
game_redraw,
game_anim_length,
game_flash_length,
+ game_status,
FALSE, FALSE, game_print_size, game_print,
TRUE, /* wants_statusbar */
FALSE, game_timing_state,
game_state *s;
char *id = NULL, *desc, *err;
int count = FALSE;
- int ret, really_verbose = FALSE;
+ int ret;
int *moves;
while (--argc > 0) {
char *p = *++argv;
+ /*
if (!strcmp(p, "-v")) {
- really_verbose = TRUE;
- } else if (!strcmp(p, "-c")) {
+ verbose = TRUE;
+ } else
+ */
+ if (!strcmp(p, "-c")) {
count = TRUE;
} else if (*p == '-') {
fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);