COL_1, COL_2, COL_3, COL_4, COL_5, COL_6, COL_7, COL_8,
COL_MINE, COL_BANG, COL_CROSS, COL_FLAG, COL_FLAGBASE, COL_QUERY,
COL_HIGHLIGHT, COL_LOWLIGHT,
+ COL_WRONGNUMBER,
NCOLOURS
};
*/
int n, unique;
random_state *rs;
- midend_data *me; /* to give back the new game desc */
+ midend *me; /* to give back the new game desc */
};
struct game_state {
int w, h, n, dead, won;
- int used_solve, just_used_solve;
+ int used_solve;
struct mine_layout *layout; /* real mine positions */
signed char *grid; /* player knowledge */
/*
/*
* Count the bits in a word. Only needs to cope with 16 bits.
*/
-static int bitcount16(int word)
+static int bitcount16(int inword)
{
+ unsigned int word = inword;
+
word = ((word & 0xAAAA) >> 1) + (word & 0x5555);
word = ((word & 0xCCCC) >> 2) + (word & 0x3333);
word = ((word & 0xF0F0) >> 4) + (word & 0x0F0F);
word = ((word & 0xFF00) >> 8) + (word & 0x00FF);
- return word;
+ return (int)word;
}
/*
return 0;
}
-static game_state *new_game(midend_data *me, game_params *params, char *desc)
+static game_state *new_game(midend *me, game_params *params, char *desc)
{
game_state *state = snew(game_state);
int i, wh, x, y, ret, masked;
state->h = params->h;
state->n = params->n;
state->dead = state->won = FALSE;
- state->used_solve = state->just_used_solve = FALSE;
+ state->used_solve = FALSE;
wh = state->w * state->h;
ret->dead = state->dead;
ret->won = state->won;
ret->used_solve = state->used_solve;
- ret->just_used_solve = state->just_used_solve;
ret->layout = state->layout;
ret->layout->refcount++;
ret->grid = snewn(ret->w * ret->h, signed char);
struct game_ui {
int hx, hy, hradius; /* for mouse-down highlights */
+ int validradius;
int flash_is_death;
- int deaths;
+ int deaths, completed;
};
static game_ui *new_ui(game_state *state)
{
game_ui *ui = snew(game_ui);
ui->hx = ui->hy = -1;
- ui->hradius = 0;
+ ui->hradius = ui->validradius = 0;
ui->deaths = 0;
+ ui->completed = FALSE;
ui->flash_is_death = FALSE; /* *shrug* */
return ui;
}
{
char buf[80];
/*
- * The deaths counter needs preserving across a serialisation.
+ * The deaths counter and completion status need preserving
+ * across a serialisation.
*/
sprintf(buf, "D%d", ui->deaths);
+ if (ui->completed)
+ strcat(buf, "C");
return dupstr(buf);
}
static void decode_ui(game_ui *ui, char *encoding)
{
- sscanf(encoding, "D%d", &ui->deaths);
+ int p= 0;
+ sscanf(encoding, "D%d%n", &ui->deaths, &p);
+ if (encoding[p] == 'C')
+ ui->completed = TRUE;
}
static void game_changed_state(game_ui *ui, game_state *oldstate,
game_state *newstate)
{
+ if (newstate->won)
+ ui->completed = TRUE;
}
struct game_drawstate {
- int w, h, started, tilesize;
+ int w, h, started, tilesize, bg;
signed char *grid;
/*
* Items in this `grid' array have all the same values as in
ui->hx = cx;
ui->hy = cy;
ui->hradius = (from->grid[cy*from->w+cx] >= 0 ? 1 : 0);
+ if (button == LEFT_BUTTON)
+ ui->validradius = ui->hradius;
+ else if (button == MIDDLE_BUTTON)
+ ui->validradius = 1;
return "";
}
*/
if (button == LEFT_RELEASE &&
(from->grid[cy * from->w + cx] == -2 ||
- from->grid[cy * from->w + cx] == -3)) {
+ from->grid[cy * from->w + cx] == -3) &&
+ ui->validradius == 0) {
/* Check if you've killed yourself. */
if (from->layout->mines && from->layout->mines[cy * from->w + cx])
ui->deaths++;
* surrounding the tile is equal to its mine count, and if
* so then we open all other surrounding squares.
*/
- if (from->grid[cy * from->w + cx] > 0) {
+ if (from->grid[cy * from->w + cx] > 0 && ui->validradius == 1) {
int dy, dx, n;
/* Count mine markers. */
ret->grid[yy*ret->w+xx] = v;
}
}
- ret->used_solve = ret->just_used_solve = TRUE;
+ ret->used_solve = TRUE;
ret->won = TRUE;
return ret;
} else {
ret = dup_game(from);
- ret->just_used_solve = FALSE;
while (*move) {
if (move[0] == 'F' &&
*y = BORDER * 2 + TILE_SIZE * params->h;
}
-static void game_set_size(game_drawstate *ds, game_params *params,
- int tilesize)
+static void game_set_size(drawing *dr, game_drawstate *ds,
+ game_params *params, int tilesize)
{
ds->tilesize = tilesize;
}
-static float *game_colours(frontend *fe, game_state *state, int *ncolours)
+static float *game_colours(frontend *fe, int *ncolours)
{
float *ret = snewn(3 * NCOLOURS, float);
ret[COL_LOWLIGHT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2.0 / 3.0;
ret[COL_LOWLIGHT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2.0 / 3.0;
+ ret[COL_WRONGNUMBER * 3 + 0] = 1.0F;
+ ret[COL_WRONGNUMBER * 3 + 1] = 0.6F;
+ ret[COL_WRONGNUMBER * 3 + 2] = 0.6F;
+
*ncolours = NCOLOURS;
return ret;
}
-static game_drawstate *game_new_drawstate(game_state *state)
+static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
{
struct game_drawstate *ds = snew(struct game_drawstate);
ds->started = FALSE;
ds->tilesize = 0; /* not decided yet */
ds->grid = snewn(ds->w * ds->h, signed char);
+ ds->bg = -1;
memset(ds->grid, -99, ds->w * ds->h);
return ds;
}
-static void game_free_drawstate(game_drawstate *ds)
+static void game_free_drawstate(drawing *dr, game_drawstate *ds)
{
sfree(ds->grid);
sfree(ds);
}
-static void draw_tile(frontend *fe, game_drawstate *ds,
+static void draw_tile(drawing *dr, game_drawstate *ds,
int x, int y, int v, int bg)
{
if (v < 0) {
/*
* Omit the highlights in this case.
*/
- draw_rect(fe, x, y, TILE_SIZE, TILE_SIZE,
+ draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE,
bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg);
- draw_line(fe, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
- draw_line(fe, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
+ draw_line(dr, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
+ draw_line(dr, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
} else {
/*
* Draw highlights to indicate the square is covered.
coords[3] = y;
coords[4] = x;
coords[5] = y + TILE_SIZE - 1;
- draw_polygon(fe, coords, 3, COL_LOWLIGHT ^ hl, COL_LOWLIGHT ^ hl);
+ draw_polygon(dr, coords, 3, COL_LOWLIGHT ^ hl, COL_LOWLIGHT ^ hl);
coords[0] = x;
coords[1] = y;
- draw_polygon(fe, coords, 3, COL_HIGHLIGHT ^ hl,
+ draw_polygon(dr, coords, 3, COL_HIGHLIGHT ^ hl,
COL_HIGHLIGHT ^ hl);
- draw_rect(fe, x + HIGHLIGHT_WIDTH, y + HIGHLIGHT_WIDTH,
+ draw_rect(dr, x + HIGHLIGHT_WIDTH, y + HIGHLIGHT_WIDTH,
TILE_SIZE - 2*HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH,
bg);
}
SETCOORD(3, 0.25, 0.8);
SETCOORD(4, 0.55, 0.7);
SETCOORD(5, 0.55, 0.35);
- draw_polygon(fe, coords, 6, COL_FLAGBASE, COL_FLAGBASE);
+ draw_polygon(dr, coords, 6, COL_FLAGBASE, COL_FLAGBASE);
SETCOORD(0, 0.6, 0.2);
SETCOORD(1, 0.6, 0.5);
SETCOORD(2, 0.2, 0.35);
- draw_polygon(fe, coords, 3, COL_FLAG, COL_FLAG);
+ draw_polygon(dr, coords, 3, COL_FLAG, COL_FLAG);
#undef SETCOORD
} else if (v == -3) {
/*
* Draw a question mark.
*/
- draw_text(fe, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
+ draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
FONT_VARIABLE, TILE_SIZE * 6 / 8,
ALIGN_VCENTRE | ALIGN_HCENTRE,
COL_QUERY, "?");
* Exception is that for value 65 (mine we've just trodden
* on), we clear the square to COL_BANG.
*/
- draw_rect(fe, x, y, TILE_SIZE, TILE_SIZE,
+ if (v & 32) {
+ bg = COL_WRONGNUMBER;
+ v &= ~32;
+ }
+ draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE,
(v == 65 ? COL_BANG :
bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg));
- draw_line(fe, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
- draw_line(fe, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
+ draw_line(dr, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
+ draw_line(dr, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
if (v > 0 && v <= 8) {
/*
char str[2];
str[0] = v + '0';
str[1] = '\0';
- draw_text(fe, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
+ draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
FONT_VARIABLE, TILE_SIZE * 7 / 8,
ALIGN_VCENTRE | ALIGN_HCENTRE,
(COL_1 - 1) + v, str);
* FIXME: this could be done better!
*/
#if 0
- draw_text(fe, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
+ draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
FONT_VARIABLE, TILE_SIZE * 7 / 8,
ALIGN_VCENTRE | ALIGN_HCENTRE,
COL_MINE, "*");
xdy = -tdy;
}
- draw_polygon(fe, coords, 5*4, COL_MINE, COL_MINE);
+ draw_polygon(dr, coords, 5*4, COL_MINE, COL_MINE);
- draw_rect(fe, cx-r/3, cy-r/3, r/3, r/4, COL_HIGHLIGHT);
+ draw_rect(dr, cx-r/3, cy-r/3, r/3, r/4, COL_HIGHLIGHT);
}
#endif
*/
int dx;
for (dx = -1; dx <= +1; dx++) {
- draw_line(fe, x + 3 + dx, y + 2,
+ draw_line(dr, x + 3 + dx, y + 2,
x + TILE_SIZE - 3 + dx,
y + TILE_SIZE - 2, COL_CROSS);
- draw_line(fe, x + TILE_SIZE - 3 + dx, y + 2,
+ draw_line(dr, x + TILE_SIZE - 3 + dx, y + 2,
x + 3 + dx, y + TILE_SIZE - 2,
COL_CROSS);
}
}
}
- draw_update(fe, x, y, TILE_SIZE, TILE_SIZE);
+ draw_update(dr, x, y, TILE_SIZE, TILE_SIZE);
}
-static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
+static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
game_state *state, int dir, game_ui *ui,
float animtime, float flashtime)
{
if (!ds->started) {
int coords[10];
- draw_rect(fe, 0, 0,
+ draw_rect(dr, 0, 0,
TILE_SIZE * state->w + 2 * BORDER,
TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND);
- draw_update(fe, 0, 0,
+ draw_update(dr, 0, 0,
TILE_SIZE * state->w + 2 * BORDER,
TILE_SIZE * state->h + 2 * BORDER);
coords[9] = COORD(state->h) + OUTER_HIGHLIGHT_WIDTH - 1;
coords[6] = coords[8] + TILE_SIZE;
coords[7] = coords[9] - TILE_SIZE;
- draw_polygon(fe, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT);
+ draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT);
coords[1] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
coords[0] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
- draw_polygon(fe, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT);
+ draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT);
ds->started = TRUE;
}
if (state->layout->mines && state->layout->mines[y*ds->w+x])
mines++;
+ if (v >= 0 && v <= 8) {
+ /*
+ * Count up the flags around this tile, and if
+ * there are too _many_, highlight the tile.
+ */
+ int dx, dy, flags = 0;
+
+ for (dy = -1; dy <= +1; dy++)
+ for (dx = -1; dx <= +1; dx++) {
+ int nx = x+dx, ny = y+dy;
+ if (nx >= 0 && nx < ds->w &&
+ ny >= 0 && ny < ds->h &&
+ state->grid[ny*ds->w+nx] == -1)
+ flags++;
+ }
+
+ if (flags > v)
+ v |= 32;
+ }
+
if ((v == -2 || v == -3) &&
(abs(x-ui->hx) <= ui->hradius && abs(y-ui->hy) <= ui->hradius))
v -= 20;
- if (ds->grid[y*ds->w+x] != v || bg != COL_BACKGROUND) {
- draw_tile(fe, ds, COORD(x), COORD(y), v, bg);
- ds->grid[y*ds->w+x] = (bg == COL_BACKGROUND ? v : -10);
+ if (ds->grid[y*ds->w+x] != v || bg != ds->bg) {
+ draw_tile(dr, ds, COORD(x), COORD(y), v, bg);
+ ds->grid[y*ds->w+x] = v;
}
}
+ ds->bg = bg;
if (!state->layout->mines)
mines = state->layout->n;
if (ui->deaths)
sprintf(statusbar + strlen(statusbar),
" Deaths: %d", ui->deaths);
- status_bar(fe, statusbar);
+ status_bar(dr, statusbar);
}
}
return 0.0F;
}
-static int game_wants_statusbar(void)
+static int game_timing_state(game_state *state, game_ui *ui)
{
+ if (state->dead || state->won || ui->completed || !state->layout->mines)
+ return FALSE;
return TRUE;
}
-static int game_timing_state(game_state *state)
+static void game_print_size(game_params *params, float *x, float *y)
+{
+}
+
+static void game_print(drawing *dr, game_state *state, int tilesize)
{
- if (state->dead || state->won || !state->layout->mines)
- return FALSE;
- return TRUE;
}
#ifdef COMBINED
#endif
const struct game thegame = {
- "Mines", "games.mines",
+ "Mines", "games.mines", "mines",
default_params,
game_fetch_preset,
decode_params,
game_redraw,
game_anim_length,
game_flash_length,
- game_wants_statusbar,
+ FALSE, FALSE, game_print_size, game_print,
+ TRUE, /* wants_statusbar */
TRUE, game_timing_state,
BUTTON_BEATS(LEFT_BUTTON, RIGHT_BUTTON),
};
* 9x9:4,4,004000007c00010022080
* $ ./mineobfusc 9x9:4,4,004000007c00010022080
* 9x9:4,4,mb071b49fbd1cb6a0d5868
- *
- * gcc -DSTANDALONE_OBFUSCATOR -o mineobfusc mines.c malloc.c random.c tree234.c misc.c
*/
-#include <stdarg.h>
-
-void frontend_default_colour(frontend *fe, float *output) {}
-void draw_text(frontend *fe, int x, int y, int fonttype, int fontsize,
- int align, int colour, char *text) {}
-void draw_rect(frontend *fe, int x, int y, int w, int h, int colour) {}
-void draw_line(frontend *fe, int x1, int y1, int x2, int y2, int colour) {}
-void draw_polygon(frontend *fe, int *coords, int npoints,
- int fillcolour, int outlinecolour) {}
-void clip(frontend *fe, int x, int y, int w, int h) {}
-void unclip(frontend *fe) {}
-void start_draw(frontend *fe) {}
-void draw_update(frontend *fe, int x, int y, int w, int h) {}
-void end_draw(frontend *fe) {}
-void midend_supersede_game_desc(midend_data *me, char *desc, char *privdesc) {}
-void status_bar(frontend *fe, char *text) {}
-
-void fatal(char *fmt, ...)
-{
- va_list ap;
-
- fprintf(stderr, "fatal error: ");
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- fprintf(stderr, "\n");
- exit(1);
-}
-
int main(int argc, char **argv)
{
game_params *p;