mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 08:01:30 -07:00
The `Solve' operation now rotates and/or reflects the solution grid
to bring it as close as possible to the current game state. This means that if you request `Solve' after solving a puzzle yourself, with the intention of finding out how similar your solution is to the program's, then you will mostly see the differences in _shape_ rather than those being masked by the fact that yours happened to be the other way up. [originally from svn r6126]
This commit is contained in:
137
untangle.c
137
untangle.c
@ -726,12 +726,147 @@ static void free_game(game_state *state)
|
|||||||
static char *solve_game(game_state *state, game_state *currstate,
|
static char *solve_game(game_state *state, game_state *currstate,
|
||||||
char *aux, char **error)
|
char *aux, char **error)
|
||||||
{
|
{
|
||||||
|
int n = state->params.n;
|
||||||
|
int matrix[4];
|
||||||
|
point *pts;
|
||||||
|
int i, j, besti;
|
||||||
|
float bestd;
|
||||||
|
char buf[80], *ret;
|
||||||
|
int retlen, retsize;
|
||||||
|
|
||||||
if (!aux) {
|
if (!aux) {
|
||||||
*error = "Solution not known for this puzzle";
|
*error = "Solution not known for this puzzle";
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dupstr(aux);
|
/*
|
||||||
|
* Decode the aux_info to get the original point positions.
|
||||||
|
*/
|
||||||
|
pts = snewn(n, point);
|
||||||
|
aux++; /* eat 'S' */
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
int p, k;
|
||||||
|
long x, y, d;
|
||||||
|
int ret = sscanf(aux, ";P%d:%ld,%ld/%ld%n", &p, &x, &y, &d, &k);
|
||||||
|
if (ret != 4 || p != i) {
|
||||||
|
*error = "Internal error: aux_info badly formatted";
|
||||||
|
sfree(pts);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pts[i].x = x;
|
||||||
|
pts[i].y = y;
|
||||||
|
pts[i].d = d;
|
||||||
|
aux += k;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now go through eight possible symmetries of the point set.
|
||||||
|
* For each one, work out the sum of the Euclidean distances
|
||||||
|
* between the points' current positions and their new ones.
|
||||||
|
*
|
||||||
|
* We're squaring distances here, which means we're at risk of
|
||||||
|
* integer overflow. Fortunately, there's no real need to be
|
||||||
|
* massively careful about rounding errors, since this is a
|
||||||
|
* non-essential bit of the code; so I'll just work in floats
|
||||||
|
* internally.
|
||||||
|
*/
|
||||||
|
besti = -1;
|
||||||
|
bestd = 0.0F;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
float d;
|
||||||
|
|
||||||
|
matrix[0] = matrix[1] = matrix[2] = matrix[3] = 0;
|
||||||
|
matrix[i & 1] = (i & 2) ? +1 : -1;
|
||||||
|
matrix[3-(i&1)] = (i & 4) ? +1 : -1;
|
||||||
|
|
||||||
|
d = 0.0F;
|
||||||
|
for (j = 0; j < n; j++) {
|
||||||
|
float px = (float)pts[j].x / pts[j].d;
|
||||||
|
float py = (float)pts[j].y / pts[j].d;
|
||||||
|
float sx = (float)currstate->pts[j].x / currstate->pts[j].d;
|
||||||
|
float sy = (float)currstate->pts[j].y / currstate->pts[j].d;
|
||||||
|
float cx = (float)currstate->w / 2;
|
||||||
|
float cy = (float)currstate->h / 2;
|
||||||
|
float ox, oy, dx, dy;
|
||||||
|
|
||||||
|
px -= cx;
|
||||||
|
py -= cy;
|
||||||
|
|
||||||
|
ox = matrix[0] * px + matrix[1] * py;
|
||||||
|
oy = matrix[2] * px + matrix[3] * py;
|
||||||
|
|
||||||
|
ox += cx;
|
||||||
|
oy += cy;
|
||||||
|
|
||||||
|
dx = ox - sx;
|
||||||
|
dy = oy - sy;
|
||||||
|
|
||||||
|
d += dx*dx + dy*dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (besti < 0 || bestd > d) {
|
||||||
|
besti = i;
|
||||||
|
bestd = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(besti >= 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we know which symmetry is closest to the points' current
|
||||||
|
* positions. Use it.
|
||||||
|
*/
|
||||||
|
matrix[0] = matrix[1] = matrix[2] = matrix[3] = 0;
|
||||||
|
matrix[besti & 1] = (besti & 2) ? +1 : -1;
|
||||||
|
matrix[3-(besti&1)] = (besti & 4) ? +1 : -1;
|
||||||
|
|
||||||
|
retsize = 256;
|
||||||
|
ret = snewn(retsize, char);
|
||||||
|
retlen = 0;
|
||||||
|
ret[retlen++] = 'S';
|
||||||
|
ret[retlen] = '\0';
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
float px = (float)pts[i].x / pts[i].d;
|
||||||
|
float py = (float)pts[i].y / pts[i].d;
|
||||||
|
float cx = (float)currstate->w / 2;
|
||||||
|
float cy = (float)currstate->h / 2;
|
||||||
|
float ox, oy;
|
||||||
|
int extra;
|
||||||
|
|
||||||
|
px -= cx;
|
||||||
|
py -= cy;
|
||||||
|
|
||||||
|
ox = matrix[0] * px + matrix[1] * py;
|
||||||
|
oy = matrix[2] * px + matrix[3] * py;
|
||||||
|
|
||||||
|
ox += cx;
|
||||||
|
oy += cy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use a fixed denominator of 2, because we know the
|
||||||
|
* original points were on an integer grid offset by 1/2.
|
||||||
|
*/
|
||||||
|
pts[i].d = 2;
|
||||||
|
ox *= pts[i].d;
|
||||||
|
oy *= pts[i].d;
|
||||||
|
pts[i].x = ox + 0.5;
|
||||||
|
pts[i].y = oy + 0.5;
|
||||||
|
|
||||||
|
extra = sprintf(buf, ";P%d:%ld,%ld/%ld", i,
|
||||||
|
pts[i].x, pts[i].y, pts[i].d);
|
||||||
|
if (retlen + extra >= retsize) {
|
||||||
|
retsize = retlen + extra + 256;
|
||||||
|
ret = sresize(ret, retsize, char);
|
||||||
|
}
|
||||||
|
strcpy(ret + retlen, buf);
|
||||||
|
retlen += extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
sfree(pts);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *game_text_format(game_state *state)
|
static char *game_text_format(game_state *state)
|
||||||
|
Reference in New Issue
Block a user