Miscellaneous fixes from James Harvey's PalmOS porting work:

- fixed numerous memory leaks (not Palm-specific)
 - corrected a couple of 32-bit-int assumptions (vital for Palm but
   generally a good thing anyway)
 - lifted a few function pointer types into explicit typedefs
   (neutral for me but convenient for the source-munging Perl
   scripts he uses to deal with Palm code segment rules)
 - lifted a few function-level static arrays into global static
   arrays (neutral for me but apparently works round a Palm tools
   bug)
 - a couple more presets in Rectangles (so that Palm, or any other
   slow platform which can't handle the larger sizes easily, can
   still have some variety available)
 - in Solo, arranged a means of sharing scratch space between calls
   to nsolve to prevent a lot of redundant malloc/frees (gives a 10%
   speed increase even on existing platforms)

[originally from svn r5897]
This commit is contained in:
Simon Tatham
2005-06-01 17:47:56 +00:00
parent ad3abd9867
commit 50edaa578b
15 changed files with 237 additions and 174 deletions

12
cube.c
View File

@ -300,10 +300,9 @@ static char *encode_params(game_params *params, int full)
return dupstr(data);
}
typedef void (*egc_callback)(void *, struct grid_square *);
static void enum_grid_squares(game_params *params,
void (*callback)(void *, struct grid_square *),
void *ctx)
static void enum_grid_squares(game_params *params, egc_callback callback, void *ctx)
{
const struct solid *solid = solids[params->solid];
@ -979,6 +978,8 @@ static game_state *dup_game(game_state *state)
static void free_game(game_state *state)
{
sfree(state->squares);
sfree(state->facecolours);
sfree(state);
}
@ -1233,6 +1234,7 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
success = align_poly(poly, &from->squares[ret->current], all_pkey);
if (!success) {
sfree(poly);
angle = -angle;
poly = transform_poly(from->solid,
from->squares[from->current].flip,
@ -1572,8 +1574,8 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
}
sfree(poly);
draw_update(fe, 0, 0, (int)((bb.r-bb.l+2.0F) * GRID_SCALE),
(int)((bb.d-bb.u+2.0F) * GRID_SCALE));
game_size(&state->params, &i, &j);
draw_update(fe, 0, 0, i, j);
/*
* Update the status bar.

View File

@ -130,7 +130,7 @@ static game_params *custom_params(config_item *cfg)
static char *validate_params(game_params *params)
{
if (params->w < 2 && params->h < 2)
if (params->w < 2 || params->h < 2)
return "Width and height must both be at least two";
return NULL;
@ -374,6 +374,7 @@ static game_state *dup_game(game_state *state)
static void free_game(game_state *state)
{
sfree(state->tiles);
sfree(state);
}

View File

@ -10,7 +10,7 @@
* smalloc should guarantee to return a useful pointer - Halibut
* can do nothing except die when it's out of memory anyway.
*/
void *smalloc(int size) {
void *smalloc(size_t size) {
void *p;
p = malloc(size);
if (!p)
@ -30,7 +30,7 @@ void sfree(void *p) {
/*
* srealloc should guaranteeably be able to realloc NULL
*/
void *srealloc(void *p, int size) {
void *srealloc(void *p, size_t size) {
void *q;
if (p) {
q = realloc(p, size);

View File

@ -96,15 +96,38 @@ midend_data *midend_new(frontend *fe, const game *ourgame)
return me;
}
static void midend_free_game(midend_data *me)
{
while (me->nstates > 0)
me->ourgame->free_game(me->states[--me->nstates].state);
if (me->drawstate)
me->ourgame->free_drawstate(me->drawstate);
}
void midend_free(midend_data *me)
{
int i;
midend_free_game(me);
random_free(me->random);
sfree(me->states);
sfree(me->desc);
sfree(me->seedstr);
random_free(me->random);
if (me->aux_info)
me->ourgame->free_aux_info(me->aux_info);
me->ourgame->free_params(me->params);
if (me->npresets) {
for (i = 0; i < me->npresets; i++) {
sfree(me->presets[i]);
sfree(me->preset_names[i]);
}
sfree(me->presets);
sfree(me->preset_names);
}
if (me->ui)
me->ourgame->free_ui(me->ui);
if (me->curparams)
me->ourgame->free_params(me->curparams);
sfree(me->laststatus);
@ -142,11 +165,7 @@ void midend_force_redraw(midend_data *me)
void midend_new_game(midend_data *me)
{
while (me->nstates > 0)
me->ourgame->free_game(me->states[--me->nstates].state);
if (me->drawstate)
me->ourgame->free_drawstate(me->drawstate);
midend_free_game(me);
assert(me->nstates == 0);
@ -259,7 +278,7 @@ static void midend_finish_move(midend_data *me)
midend_set_timer(me);
}
static void midend_stop_anim(midend_data *me)
void midend_stop_anim(midend_data *me)
{
if (me->oldstate || me->anim_time) {
midend_finish_move(me);
@ -299,29 +318,29 @@ static int midend_really_process_key(midend_data *me, int x, int y, int button)
{
game_state *oldstate =
me->ourgame->dup_game(me->states[me->statepos - 1].state);
int special = FALSE, gotspecial = FALSE;
int special = FALSE, gotspecial = FALSE, ret = 1;
float anim_time;
if (button == 'n' || button == 'N' || button == '\x0E') {
midend_stop_anim(me);
midend_new_game(me);
midend_redraw(me);
return 1; /* never animate */
goto done; /* never animate */
} else if (button == 'u' || button == 'u' ||
button == '\x1A' || button == '\x1F') {
midend_stop_anim(me);
special = me->states[me->statepos-1].special;
gotspecial = TRUE;
if (!midend_undo(me))
return 1;
goto done;
} else if (button == 'r' || button == 'R' ||
button == '\x12' || button == '\x19') {
midend_stop_anim(me);
if (!midend_redo(me))
return 1;
goto done;
} else if (button == 'q' || button == 'Q' || button == '\x11') {
me->ourgame->free_game(oldstate);
return 0;
ret = 0;
goto done;
} else {
game_state *s =
me->ourgame->make_move(me->states[me->statepos-1].state,
@ -334,7 +353,7 @@ static int midend_really_process_key(midend_data *me, int x, int y, int button)
* state has been updated and a redraw is called for.
*/
midend_redraw(me);
return 1;
goto done;
} else if (s) {
midend_stop_anim(me);
while (me->nstates > me->statepos)
@ -345,8 +364,7 @@ static int midend_really_process_key(midend_data *me, int x, int y, int button)
me->statepos = ++me->nstates;
me->dir = +1;
} else {
me->ourgame->free_game(oldstate);
return 1;
goto done;
}
}
@ -364,7 +382,7 @@ static int midend_really_process_key(midend_data *me, int x, int y, int button)
me->dir, me->ui);
}
me->oldstate = oldstate;
me->oldstate = oldstate; oldstate = NULL;
if (anim_time > 0) {
me->anim_time = anim_time;
} else {
@ -377,7 +395,9 @@ static int midend_really_process_key(midend_data *me, int x, int y, int button)
midend_set_timer(me);
return 1;
done:
if (oldstate) me->ourgame->free_game(oldstate);
return ret;
}
int midend_process_key(midend_data *me, int x, int y, int button)
@ -687,21 +707,27 @@ void midend_supersede_game_desc(midend_data *me, char *desc)
config_item *midend_get_config(midend_data *me, int which, char **wintitle)
{
char *titlebuf, *parstr;
char *titlebuf, *parstr, *rest;
config_item *ret;
char sep;
assert(wintitle);
titlebuf = snewn(40 + strlen(me->ourgame->name), char);
switch (which) {
case CFG_SETTINGS:
sprintf(titlebuf, "%s configuration", me->ourgame->name);
*wintitle = dupstr(titlebuf);
*wintitle = titlebuf;
return me->ourgame->configure(me->params);
case CFG_SEED:
case CFG_DESC:
if (!me->curparams) {
sfree(titlebuf);
return NULL;
}
sprintf(titlebuf, "%s %s selection", me->ourgame->name,
which == CFG_SEED ? "random" : "game");
*wintitle = dupstr(titlebuf);
*wintitle = titlebuf;
ret = snewn(2, config_item);
@ -721,21 +747,16 @@ config_item *midend_get_config(midend_data *me, int which, char **wintitle)
* changes).
*/
parstr = me->ourgame->encode_params(me->curparams, which == CFG_SEED);
assert(parstr);
if (which == CFG_DESC) {
ret[0].sval = snewn(strlen(parstr) + strlen(me->desc) + 2, char);
sprintf(ret[0].sval, "%s:%s", parstr, me->desc);
} else if (me->seedstr) {
ret[0].sval = snewn(strlen(parstr) + strlen(me->seedstr) + 2, char);
sprintf(ret[0].sval, "%s#%s", parstr, me->seedstr);
rest = me->desc ? me->desc : "";
sep = ':';
} else {
/*
* If the current game was not randomly generated, the
* best we can do is to give a template for typing a
* new seed in.
*/
ret[0].sval = snewn(strlen(parstr) + 2, char);
sprintf(ret[0].sval, "%s#", parstr);
rest = me->seedstr ? me->seedstr : "";
sep = '#';
}
ret[0].sval = snewn(strlen(parstr) + strlen(rest) + 2, char);
sprintf(ret[0].sval, "%s%c%s", parstr, sep, rest);
sfree(parstr);
ret[1].type = C_END;

35
mines.c
View File

@ -95,24 +95,22 @@ static game_params *default_params(void)
return ret;
}
static const struct game_params mines_presets[] = {
{9, 9, 10, TRUE},
{16, 16, 40, TRUE},
{30, 16, 99, TRUE},
};
static int game_fetch_preset(int i, char **name, game_params **params)
{
game_params *ret;
char str[80];
static const struct { int w, h, n; } values[] = {
{9, 9, 10},
{16, 16, 40},
{30, 16, 99},
};
if (i < 0 || i >= lenof(values))
if (i < 0 || i >= lenof(mines_presets))
return FALSE;
ret = snew(game_params);
ret->w = values[i].w;
ret->h = values[i].h;
ret->n = values[i].n;
ret->unique = TRUE;
*ret = mines_presets[i];
sprintf(str, "%dx%d, %d mines", ret->w, ret->h, ret->n);
@ -558,9 +556,11 @@ static void std_add(struct squaretodo *std, int i)
std->next[i] = -1;
}
typedef int (*open_cb)(void *, int, int);
static void known_squares(int w, int h, struct squaretodo *std,
signed char *grid,
int (*open)(void *ctx, int x, int y), void *openctx,
open_cb open, void *openctx,
int x, int y, int mask, int mine)
{
int xx, yy, bit;
@ -626,11 +626,12 @@ struct perturbations {
* steps were required; the exact return value is the number of
* perturb calls.
*/
typedef struct perturbations *(*perturb_cb) (void *, signed char *, int, int, int);
static int minesolve(int w, int h, int n, signed char *grid,
int (*open)(void *ctx, int x, int y),
struct perturbations *(*perturb)(void *ctx,
signed char *grid,
int x, int y, int mask),
open_cb open,
perturb_cb perturb,
void *ctx, random_state *rs)
{
struct setstore *ss = ss_new();
@ -2071,7 +2072,7 @@ static char *new_game_desc(game_params *params, random_state *rs,
rsdesc = random_state_encode(rs);
desc = snewn(strlen(rsdesc) + 100, char);
sprintf(desc, "r%d,%c,%s", params->n, params->unique ? 'u' : 'a', rsdesc);
sprintf(desc, "r%d,%c,%s", params->n, (char)(params->unique ? 'u' : 'a'), rsdesc);
sfree(rsdesc);
return desc;
}
@ -2258,6 +2259,7 @@ static game_state *new_game(midend_data *me, game_params *params, char *desc)
wh = state->w * state->h;
state->layout = snew(struct mine_layout);
memset(state->layout, 0, sizeof(struct mine_layout));
state->layout->refcount = 1;
state->grid = snewn(wh, char);
@ -2334,6 +2336,7 @@ static game_state *new_game(midend_data *me, game_params *params, char *desc)
}
ret = open_square(state, x, y);
sfree(bmp);
}
return state;

45
net.c
View File

@ -149,32 +149,29 @@ static game_params *default_params(void)
return ret;
}
static const struct game_params net_presets[] = {
{5, 5, FALSE, TRUE, 0.0},
{7, 7, FALSE, TRUE, 0.0},
{9, 9, FALSE, TRUE, 0.0},
{11, 11, FALSE, TRUE, 0.0},
{13, 11, FALSE, TRUE, 0.0},
{5, 5, TRUE, TRUE, 0.0},
{7, 7, TRUE, TRUE, 0.0},
{9, 9, TRUE, TRUE, 0.0},
{11, 11, TRUE, TRUE, 0.0},
{13, 11, TRUE, TRUE, 0.0},
};
static int game_fetch_preset(int i, char **name, game_params **params)
{
game_params *ret;
char str[80];
static const struct { int x, y, wrap; } values[] = {
{5, 5, FALSE},
{7, 7, FALSE},
{9, 9, FALSE},
{11, 11, FALSE},
{13, 11, FALSE},
{5, 5, TRUE},
{7, 7, TRUE},
{9, 9, TRUE},
{11, 11, TRUE},
{13, 11, TRUE},
};
if (i < 0 || i >= lenof(values))
if (i < 0 || i >= lenof(net_presets))
return FALSE;
ret = snew(game_params);
ret->width = values[i].x;
ret->height = values[i].y;
ret->wrapping = values[i].wrap;
ret->unique = TRUE;
ret->barrier_probability = 0.0;
*ret = net_presets[i];
sprintf(str, "%dx%d%s", ret->width, ret->height,
ret->wrapping ? " wrapping" : "");
@ -302,12 +299,8 @@ static game_params *custom_params(config_item *cfg)
static char *validate_params(game_params *params)
{
if (params->width <= 0 && params->height <= 0)
if (params->width <= 0 || params->height <= 0)
return "Width and height must both be greater than zero";
if (params->width <= 0)
return "Width must be greater than zero";
if (params->height <= 0)
return "Height must be greater than zero";
if (params->width <= 1 && params->height <= 1)
return "At least one of width and height must be greater than one";
if (params->barrier_probability < 0)
@ -968,6 +961,7 @@ static void perturb(int w, int h, unsigned char *tiles, int wrapping,
break;
}
sfree(perim2);
if (i == nperim)
return; /* nothing we can do! */
@ -1944,7 +1938,10 @@ static game_state *make_move(game_state *state, game_ui *ui,
ret->last_rotate_dir = 0; /* suppress animation */
ret->last_rotate_x = ret->last_rotate_y = 0;
} else assert(0);
} else {
ret = NULL; /* placate optimisers which don't understand assert(0) */
assert(0);
}
/*
* Check whether the game has been completed.

View File

@ -161,11 +161,8 @@ static game_params *default_params(void)
return ret;
}
static int game_fetch_preset(int i, char **name, game_params **params)
{
game_params *ret;
char str[80];
static const struct { int x, y, wrap, bprob; const char* desc; } values[] = {
static const struct { int x, y, wrap, bprob; const char* desc; }
netslide_presets[] = {
{3, 3, FALSE, 1.0, " easy"},
{3, 3, FALSE, 0.0, " medium"},
{3, 3, TRUE, 0.0, " hard"},
@ -175,20 +172,24 @@ static int game_fetch_preset(int i, char **name, game_params **params)
{5, 5, FALSE, 1.0, " easy"},
{5, 5, FALSE, 0.0, " medium"},
{5, 5, TRUE, 0.0, " hard"},
};
};
if (i < 0 || i >= lenof(values))
static int game_fetch_preset(int i, char **name, game_params **params)
{
game_params *ret;
char str[80];
if (i < 0 || i >= lenof(netslide_presets))
return FALSE;
ret = snew(game_params);
ret->width = values[i].x;
ret->height = values[i].y;
ret->wrapping = values[i].wrap;
ret->barrier_probability = values[i].bprob;
ret->width = netslide_presets[i].x;
ret->height = netslide_presets[i].y;
ret->wrapping = netslide_presets[i].wrap;
ret->barrier_probability = netslide_presets[i].bprob;
ret->movetarget = 0;
sprintf(str, "%dx%d%s", ret->width, ret->height,
values[i].desc);
sprintf(str, "%dx%d%s", ret->width, ret->height, netslide_presets[i].desc);
*name = dupstr(str);
*params = ret;
@ -314,12 +315,8 @@ static game_params *custom_params(config_item *cfg)
static char *validate_params(game_params *params)
{
if (params->width <= 1 && params->height <= 1)
if (params->width <= 1 || params->height <= 1)
return "Width and height must both be greater than one";
if (params->width <= 1)
return "Width must be greater than one";
if (params->height <= 1)
return "Height must be greater than one";
if (params->barrier_probability < 0)
return "Barrier probability may not be negative";
if (params->barrier_probability > 1)

View File

@ -11,9 +11,6 @@
#include "puzzles.h"
#define max(x,y) ( (x)>(y) ? (x):(y) )
#define min(x,y) ( (x)<(y) ? (x):(y) )
enum {
COL_BACKGROUND,
COL_EMPTY,
@ -62,24 +59,26 @@ static game_params *default_params(void)
return ret;
}
static const struct game_params pattern_presets[] = {
{10, 10},
{15, 15},
{20, 20},
#ifndef SLOW_SYSTEM
{25, 25},
{30, 30},
#endif
};
static int game_fetch_preset(int i, char **name, game_params **params)
{
game_params *ret;
char str[80];
static const struct { int x, y; } values[] = {
{10, 10},
{15, 15},
{20, 20},
{25, 25},
{30, 30},
};
if (i < 0 || i >= lenof(values))
if (i < 0 || i >= lenof(pattern_presets))
return FALSE;
ret = snew(game_params);
ret->w = values[i].x;
ret->h = values[i].y;
*ret = pattern_presets[i];
sprintf(str, "%dx%d", ret->w, ret->h);
@ -166,12 +165,8 @@ static game_params *custom_params(config_item *cfg)
static char *validate_params(game_params *params)
{
if (params->w <= 0 && params->h <= 0)
if (params->w <= 0 || params->h <= 0)
return "Width and height must both be greater than zero";
if (params->w <= 0)
return "Width must be greater than zero";
if (params->h <= 0)
return "Height must be greater than zero";
return NULL;
}
@ -494,8 +489,7 @@ static char *new_game_desc(game_params *params, random_state *rs,
ai->w = params->w;
ai->h = params->h;
ai->grid = snewn(ai->w * ai->h, unsigned char);
memcpy(ai->grid, grid, ai->w * ai->h);
ai->grid = grid;
*aux = ai;
}

View File

@ -5,6 +5,8 @@
#ifndef PUZZLES_PUZZLES_H
#define PUZZLES_PUZZLES_H
#include <stdlib.h> /* for size_t */
#ifndef TRUE
#define TRUE 1
#endif
@ -19,8 +21,12 @@
#define STR_INT(x) #x
#define STR(x) STR_INT(x)
/* NB not perfect because they evaluate arguments multiple times. */
#define max(x,y) ( (x)>(y) ? (x) : (y) )
#define min(x,y) ( (x)<(y) ? (x) : (y) )
enum {
LEFT_BUTTON = 0x1000,
LEFT_BUTTON = 0x0200,
MIDDLE_BUTTON,
RIGHT_BUTTON,
LEFT_DRAG,
@ -34,10 +40,11 @@ enum {
CURSOR_LEFT,
CURSOR_RIGHT,
MOD_CTRL = 0x10000000,
MOD_SHFT = 0x20000000,
MOD_NUM_KEYPAD = 0x40000000,
MOD_MASK = 0x70000000 /* mask for all modifiers */
/* made smaller because of 'limited range of datatype' errors. */
MOD_CTRL = 0x1000,
MOD_SHFT = 0x2000,
MOD_NUM_KEYPAD = 0x4000,
MOD_MASK = 0x7000 /* mask for all modifiers */
};
#define IS_MOUSE_DOWN(m) ( (unsigned)((m) - LEFT_BUTTON) <= \
@ -108,6 +115,14 @@ struct config_item {
/*
* Platform routines
*/
#ifdef DEBUG
#define debug(x) (debug_printf x)
void debug_printf(char *fmt, ...);
#else
#define debug(x)
#endif
void fatal(char *fmt, ...);
void frontend_default_colour(frontend *fe, float *output);
void draw_text(frontend *fe, int x, int y, int fonttype, int fontsize,
@ -135,6 +150,7 @@ void midend_set_params(midend_data *me, game_params *params);
void midend_size(midend_data *me, int *x, int *y);
void midend_new_game(midend_data *me);
void midend_restart_game(midend_data *me);
void midend_stop_anim(midend_data *me);
int midend_process_key(midend_data *me, int x, int y, int button);
void midend_force_redraw(midend_data *me);
void midend_redraw(midend_data *me);
@ -156,8 +172,8 @@ char *midend_rewrite_statusbar(midend_data *me, char *text);
/*
* malloc.c
*/
void *smalloc(int size);
void *srealloc(void *p, int size);
void *smalloc(size_t size);
void *srealloc(void *p, size_t size);
void sfree(void *p);
char *dupstr(const char *s);
#define snew(type) \

View File

@ -264,7 +264,7 @@ unsigned long random_upto(random_state *state, unsigned long limit)
bits += 3;
assert(bits < 32);
max = 1 << bits;
max = 1L << bits;
divisor = max / limit;
max = limit * divisor;

32
rect.c
View File

@ -98,9 +98,14 @@ static int game_fetch_preset(int i, char **name, game_params **params)
switch (i) {
case 0: w = 7, h = 7; break;
case 1: w = 11, h = 11; break;
case 2: w = 15, h = 15; break;
case 3: w = 19, h = 19; break;
case 1: w = 9, h = 9; break;
case 2: w = 11, h = 11; break;
case 3: w = 13, h = 13; break;
case 4: w = 15, h = 15; break;
#ifndef SLOW_SYSTEM
case 5: w = 17, h = 17; break;
case 6: w = 19, h = 19; break;
#endif
default: return FALSE;
}
@ -212,9 +217,9 @@ static game_params *custom_params(config_item *cfg)
static char *validate_params(game_params *params)
{
if (params->w <= 0 && params->h <= 0)
if (params->w <= 0 || params->h <= 0)
return "Width and height must both be greater than zero";
if (params->w < 2 && params->h < 2)
if (params->w*params->h < 2)
return "Grid area must be greater than one";
if (params->expandfactor < 0.0F)
return "Expansion factor may not be negative";
@ -2277,16 +2282,15 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
* Drawing routines.
*/
#define CORRECT 65536
#define CORRECT (1L<<16)
#define COLOUR(k) ( (k)==1 ? COL_LINE : COL_DRAG )
#define MAX(x,y) ( (x)>(y) ? (x) : (y) )
#define MAX4(x,y,z,w) ( MAX(MAX(x,y),MAX(z,w)) )
#define MAX4(x,y,z,w) ( max(max(x,y),max(z,w)) )
struct game_drawstate {
int started;
int w, h;
unsigned int *visible;
unsigned long *visible;
};
static void game_size(game_params *params, int *x, int *y)
@ -2333,7 +2337,7 @@ static game_drawstate *game_new_drawstate(game_state *state)
ds->started = FALSE;
ds->w = state->w;
ds->h = state->h;
ds->visible = snewn(ds->w * ds->h, unsigned int);
ds->visible = snewn(ds->w * ds->h, unsigned long);
for (i = 0; i < ds->w * ds->h; i++)
ds->visible[i] = 0xFFFF;
@ -2459,7 +2463,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
for (x = 0; x < state->w; x++)
for (y = 0; y < state->h; y++) {
unsigned int c = 0;
unsigned long c = 0;
if (HRANGE(state,x,y))
c |= index(state,hedge,x,y);
@ -2475,12 +2479,14 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
if (y+1 < state->h)
c |= index(state,corners,x,y+1) << 12;
if (x+1 < state->w && y+1 < state->h)
c |= index(state,corners,x+1,y+1) << 14;
/* cast to prevent 2<<14 sign-extending on promotion to long */
c |= (unsigned long)index(state,corners,x+1,y+1) << 14;
if (index(state, correct, x, y) && !flashtime)
c |= CORRECT;
if (index(ds,ds->visible,x,y) != c) {
draw_tile(fe, state, x, y, hedge, vedge, corners, c & CORRECT);
draw_tile(fe, state, x, y, hedge, vedge, corners,
(c & CORRECT) ? 1 : 0);
index(ds,ds->visible,x,y) = c;
}
}

View File

@ -173,7 +173,7 @@ static game_params *custom_params(config_item *cfg)
static char *validate_params(game_params *params)
{
if (params->w < 2 && params->h < 2)
if (params->w < 2 || params->h < 2)
return "Width and height must both be at least two";
return NULL;
@ -505,6 +505,7 @@ static game_state *dup_game(game_state *state)
static void free_game(game_state *state)
{
sfree(state->tiles);
sfree(state);
}

67
solo.c
View File

@ -96,8 +96,6 @@ int solver_show_working;
#include "puzzles.h"
#define max(x,y) ((x)>(y)?(x):(y))
/*
* To save space, I store digits internally as unsigned char. This
* imposes a hard limit of 255 on the order of the puzzle. Since
@ -177,8 +175,10 @@ static int game_fetch_preset(int i, char **name, game_params **params)
{ "3x3 Intermediate", { 3, 3, SYMM_ROT2, DIFF_INTERSECT } },
{ "3x3 Advanced", { 3, 3, SYMM_ROT2, DIFF_SET } },
{ "3x3 Unreasonable", { 3, 3, SYMM_ROT2, DIFF_RECURSIVE } },
#ifndef SLOW_SYSTEM
{ "3x4 Basic", { 3, 4, SYMM_ROT2, DIFF_SIMPLE } },
{ "4x4 Basic", { 4, 4, SYMM_ROT2, DIFF_SIMPLE } },
#endif
};
if (i < 0 || i >= lenof(presets))
@ -844,7 +844,12 @@ static int nsolve_intersect(struct nsolve_usage *usage,
return ret;
}
struct nsolve_scratch {
unsigned char *grid, *rowidx, *colidx, *set;
};
static int nsolve_set(struct nsolve_usage *usage,
struct nsolve_scratch *scratch,
int start, int step1, int step2
#ifdef STANDALONE_SOLVER
, char *fmt, ...
@ -853,10 +858,10 @@ static int nsolve_set(struct nsolve_usage *usage,
{
int c = usage->c, r = usage->r, cr = c*r;
int i, j, n, count;
unsigned char *grid = snewn(cr*cr, unsigned char);
unsigned char *rowidx = snewn(cr, unsigned char);
unsigned char *colidx = snewn(cr, unsigned char);
unsigned char *set = snewn(cr, unsigned char);
unsigned char *grid = scratch->grid;
unsigned char *rowidx = scratch->rowidx;
unsigned char *colidx = scratch->colidx;
unsigned char *set = scratch->set;
/*
* We are passed a cr-by-cr matrix of booleans. Our first job
@ -999,10 +1004,6 @@ static int nsolve_set(struct nsolve_usage *usage,
}
if (progress) {
sfree(set);
sfree(colidx);
sfree(rowidx);
sfree(grid);
return TRUE;
}
}
@ -1021,17 +1022,33 @@ static int nsolve_set(struct nsolve_usage *usage,
break; /* done */
}
sfree(set);
sfree(colidx);
sfree(rowidx);
sfree(grid);
return FALSE;
}
static struct nsolve_scratch *nsolve_new_scratch(struct nsolve_usage *usage)
{
struct nsolve_scratch *scratch = snew(struct nsolve_scratch);
int cr = usage->cr;
scratch->grid = snewn(cr*cr, unsigned char);
scratch->rowidx = snewn(cr, unsigned char);
scratch->colidx = snewn(cr, unsigned char);
scratch->set = snewn(cr, unsigned char);
return scratch;
}
static void nsolve_free_scratch(struct nsolve_scratch *scratch)
{
sfree(scratch->set);
sfree(scratch->colidx);
sfree(scratch->rowidx);
sfree(scratch->grid);
sfree(scratch);
}
static int nsolve(int c, int r, digit *grid)
{
struct nsolve_usage *usage;
struct nsolve_scratch *scratch;
int cr = c*r;
int x, y, n;
int diff = DIFF_BLOCK;
@ -1055,6 +1072,8 @@ static int nsolve(int c, int r, digit *grid)
memset(usage->col, FALSE, cr * cr);
memset(usage->blk, FALSE, cr * cr);
scratch = nsolve_new_scratch(usage);
/*
* Place all the clue numbers we are given.
*/
@ -1204,7 +1223,7 @@ static int nsolve(int c, int r, digit *grid)
*/
for (x = 0; x < cr; x += r)
for (y = 0; y < r; y++)
if (nsolve_set(usage, cubepos(x,y,1), r*cr, 1
if (nsolve_set(usage, scratch, cubepos(x,y,1), r*cr, 1
#ifdef STANDALONE_SOLVER
, "set elimination, block (%d,%d)", 1+x/r, 1+y
#endif
@ -1217,7 +1236,7 @@ static int nsolve(int c, int r, digit *grid)
* Row-wise set elimination.
*/
for (y = 0; y < cr; y++)
if (nsolve_set(usage, cubepos(0,y,1), cr*cr, 1
if (nsolve_set(usage, scratch, cubepos(0,y,1), cr*cr, 1
#ifdef STANDALONE_SOLVER
, "set elimination, row %d", 1+YUNTRANS(y)
#endif
@ -1230,7 +1249,7 @@ static int nsolve(int c, int r, digit *grid)
* Column-wise set elimination.
*/
for (x = 0; x < cr; x++)
if (nsolve_set(usage, cubepos(x,0,1), cr, 1
if (nsolve_set(usage, scratch, cubepos(x,0,1), cr, 1
#ifdef STANDALONE_SOLVER
, "set elimination, column %d", 1+x
#endif
@ -1246,6 +1265,8 @@ static int nsolve(int c, int r, digit *grid)
break;
}
nsolve_free_scratch(scratch);
sfree(usage->cube);
sfree(usage->row);
sfree(usage->col);
@ -1448,6 +1469,16 @@ static char *new_game_desc(game_params *params, random_state *rs,
ai->r = r;
ai->grid = snewn(cr * cr, digit);
memcpy(ai->grid, grid, cr * cr * sizeof(digit));
/*
* We might already have written *aux the last time we
* went round this loop, in which case we should free
* the old aux_info before overwriting it with the new
* one.
*/
if (*aux) {
sfree((*aux)->grid);
sfree(*aux);
}
*aux = ai;
}

View File

@ -409,7 +409,7 @@ static char *new_game_desc(game_params *params, random_state *rs,
int k;
k = sprintf(buf, "%d%c", grid[i] / 4,
params->orientable ? "uldr"[grid[i] & 3] : ',');
(char)(params->orientable ? "uldr"[grid[i] & 3] : ','));
ret = sresize(ret, retlen + k + 1, char);
strcpy(ret + retlen, buf);
@ -764,6 +764,7 @@ static game_drawstate *game_new_drawstate(game_state *state)
static void game_free_drawstate(game_drawstate *ds)
{
sfree(ds->grid);
sfree(ds);
}

View File

@ -77,13 +77,6 @@ void debug_printf(char *fmt, ...)
dputs(buf);
va_end(ap);
}
#define debug(x) (debug_printf x)
#else
#define debug(x)
#endif
struct font {