197
typedef struct game_grid game_grid;
200
struct grid_square *squares;
204
#define SET_SQUARE(state, i, val) \
205
((state)->bluemask[(i)/32] &= ~(1 << ((i)%32)), \
206
(state)->bluemask[(i)/32] |= ((!!val) << ((i)%32)))
207
#define GET_SQUARE(state, i) \
208
(((state)->bluemask[(i)/32] >> ((i)%32)) & 1)
198
210
struct game_state {
199
211
struct game_params params;
200
212
const struct solid *solid;
201
213
int *facecolours;
202
struct grid_square *squares;
215
unsigned long *bluemask;
204
216
int current; /* index of current grid square */
205
217
int sgkey[2]; /* key-point indices into grid sq */
206
218
int dgkey[2]; /* key-point indices into grid sq */
690
702
static void add_grid_square_callback(void *ctx, struct grid_square *sq)
692
game_state *state = (game_state *)ctx;
704
game_grid *grid = (game_grid *)ctx;
694
state->squares[state->nsquares] = *sq; /* structure copy */
695
state->squares[state->nsquares].blue = FALSE;
706
grid->squares[grid->nsquares++] = *sq; /* structure copy */
699
709
static int lowest_face(const struct solid *solid)
872
883
state->solid = solids[params->solid];
874
885
area = grid_area(params->d1, params->d2, state->solid->order);
875
state->squares = snewn(area, struct grid_square);
877
enum_grid_squares(params, add_grid_square_callback, state);
878
assert(state->nsquares == area);
886
grid->squares = snewn(area, struct grid_square);
888
enum_grid_squares(params, add_grid_square_callback, grid);
889
assert(grid->nsquares == area);
880
893
state->facecolours = snewn(state->solid->nfaces, int);
881
894
memset(state->facecolours, 0, state->solid->nfaces * sizeof(int));
896
state->bluemask = snewn((state->grid->nsquares + 31) / 32, unsigned long);
897
memset(state->bluemask, 0, (state->grid->nsquares + 31) / 32 *
898
sizeof(unsigned long));
884
901
* Set up the blue squares and polyhedron position according to
885
902
* the game description.
928
ret = align_poly(state->solid, &state->squares[state->current], pkey);
945
ret = align_poly(state->solid, &state->grid->squares[state->current], pkey);
931
948
state->dpkey[0] = state->spkey[0] = pkey[0];
951
968
ret->facecolours = snewn(ret->solid->nfaces, int);
952
969
memcpy(ret->facecolours, state->facecolours,
953
970
ret->solid->nfaces * sizeof(int));
954
ret->nsquares = state->nsquares;
955
971
ret->current = state->current;
956
ret->squares = snewn(ret->nsquares, struct grid_square);
957
memcpy(ret->squares, state->squares,
958
ret->nsquares * sizeof(struct grid_square));
972
ret->grid = state->grid;
973
ret->grid->refcount++;
974
ret->bluemask = snewn((ret->grid->nsquares + 31) / 32, unsigned long);
975
memcpy(ret->bluemask, state->bluemask, (ret->grid->nsquares + 31) / 32 *
976
sizeof(unsigned long));
959
977
ret->dpkey[0] = state->dpkey[0];
960
978
ret->dpkey[1] = state->dpkey[1];
961
979
ret->dgkey[0] = state->dgkey[0];
1031
1057
* Find the two points in the current grid square which
1032
1058
* correspond to this move.
1034
mask = from->squares[from->current].directions[direction];
1060
mask = from->grid->squares[from->current].directions[direction];
1037
for (i = j = 0; i < from->squares[from->current].npoints; i++)
1063
for (i = j = 0; i < from->grid->squares[from->current].npoints; i++)
1038
1064
if (mask & (1 << i)) {
1039
points[j*2] = from->squares[from->current].points[i*2];
1040
points[j*2+1] = from->squares[from->current].points[i*2+1];
1065
points[j*2] = from->grid->squares[from->current].points[i*2];
1066
points[j*2+1] = from->grid->squares[from->current].points[i*2+1];
1048
1074
* This is our move destination.
1051
for (i = 0; i < from->nsquares; i++)
1077
for (i = 0; i < from->grid->nsquares; i++)
1052
1078
if (i != from->current) {
1056
for (j = 0; j < from->squares[i].npoints; j++) {
1057
dist = (SQ(from->squares[i].points[j*2] - points[0]) +
1058
SQ(from->squares[i].points[j*2+1] - points[1]));
1082
for (j = 0; j < from->grid->squares[i].npoints; j++) {
1083
dist = (SQ(from->grid->squares[i].points[j*2] - points[0]) +
1084
SQ(from->grid->squares[i].points[j*2+1] - points[1]));
1059
1085
if (dist < 0.1)
1060
1086
dkey[match++] = j;
1061
dist = (SQ(from->squares[i].points[j*2] - points[2]) +
1062
SQ(from->squares[i].points[j*2+1] - points[3]));
1087
dist = (SQ(from->grid->squares[i].points[j*2] - points[2]) +
1088
SQ(from->grid->squares[i].points[j*2+1] - points[3]));
1063
1089
if (dist < 0.1)
1064
1090
dkey[match++] = j;
1113
cx = state->squares[state->current].x * GRID_SCALE + ds->ox;
1114
cy = state->squares[state->current].y * GRID_SCALE + ds->oy;
1139
cx = (int)(state->grid->squares[state->current].x * GRID_SCALE) + ds->ox;
1140
cy = (int)(state->grid->squares[state->current].y * GRID_SCALE) + ds->oy;
1116
1142
if (x == cx && y == cy)
1117
1143
return NULL; /* clicked in exact centre! */
1136
1162
* x-axis, not anticlockwise as most mathematicians would
1137
1163
* instinctively assume.
1139
if (state->squares[state->current].npoints == 4) {
1165
if (state->grid->squares[state->current].npoints == 4) {
1141
1167
if (fabs(angle) > 3*PI/4)
1142
1168
direction = LEFT;
1234
1260
int all_pkey[4];
1235
align_poly(from->solid, &from->squares[from->current], all_pkey);
1261
align_poly(from->solid, &from->grid->squares[from->current], all_pkey);
1236
1262
pkey[0] = all_pkey[skey[0]];
1237
1263
pkey[1] = all_pkey[skey[1]];
1292
1318
angle = -angle; /* HACK */
1294
1320
poly = transform_poly(from->solid,
1295
from->squares[from->current].flip,
1321
from->grid->squares[from->current].flip,
1296
1322
pkey[0], pkey[1], angle);
1297
flip_poly(poly, from->squares[ret->current].flip);
1298
success = align_poly(poly, &from->squares[ret->current], all_pkey);
1323
flip_poly(poly, from->grid->squares[ret->current].flip);
1324
success = align_poly(poly, &from->grid->squares[ret->current], all_pkey);
1300
1326
if (!success) {
1302
1328
angle = -angle;
1303
1329
poly = transform_poly(from->solid,
1304
from->squares[from->current].flip,
1330
from->grid->squares[from->current].flip,
1305
1331
pkey[0], pkey[1], angle);
1306
flip_poly(poly, from->squares[ret->current].flip);
1307
success = align_poly(poly, &from->squares[ret->current], all_pkey);
1332
flip_poly(poly, from->grid->squares[ret->current].flip);
1333
success = align_poly(poly, &from->grid->squares[ret->current], all_pkey);
1310
1336
assert(success);
1370
1396
if (!ret->completed) {
1371
1397
i = lowest_face(from->solid);
1372
1398
j = ret->facecolours[i];
1373
ret->facecolours[i] = ret->squares[ret->current].blue;
1374
ret->squares[ret->current].blue = j;
1399
ret->facecolours[i] = GET_SQUARE(ret, ret->current);
1400
SET_SQUARE(ret, ret->current, j);
1377
1403
* Detect game completion.
1472
1498
struct bbox bb = find_bbox(params);
1474
ds->gridscale = tilesize;
1500
ds->gridscale = (float)tilesize;
1475
1501
ds->ox = (int)(-(bb.l - solids[params->solid]->border) * ds->gridscale);
1476
1502
ds->oy = (int)(-(bb.u - solids[params->solid]->border) * ds->gridscale);
1555
1582
newstate = state;
1556
1583
state = oldstate;
1558
for (i = 0; i < state->nsquares; i++) {
1585
for (i = 0; i < state->grid->nsquares; i++) {
1561
for (j = 0; j < state->squares[i].npoints; j++) {
1562
coords[2*j] = ((int)(state->squares[i].points[2*j] * GRID_SCALE)
1588
for (j = 0; j < state->grid->squares[i].npoints; j++) {
1589
coords[2*j] = ((int)(state->grid->squares[i].points[2*j] * GRID_SCALE)
1564
coords[2*j+1] = ((int)(state->squares[i].points[2*j+1]*GRID_SCALE)
1591
coords[2*j+1] = ((int)(state->grid->squares[i].points[2*j+1]*GRID_SCALE)
1568
draw_polygon(dr, coords, state->squares[i].npoints,
1569
state->squares[i].blue ? COL_BLUE : COL_BACKGROUND,
1595
draw_polygon(dr, coords, state->grid->squares[i].npoints,
1596
GET_SQUARE(state, i) ? COL_BLUE : COL_BACKGROUND,
1574
1601
* Now compute and draw the polyhedron.
1576
poly = transform_poly(state->solid, state->squares[square].flip,
1603
poly = transform_poly(state->solid, state->grid->squares[square].flip,
1577
1604
pkey[0], pkey[1], angle);