void mm_look(MazeMap *mm, const char *line, RelDir rel_dir) { Dir front = TURN(mm->dir, rel_dir), left = TURN(front, LEFT), right = TURN(front, RIGHT), back = TURN(front, BACK); int r = mm->loc.r, c = mm->loc.c; while (*line) { bool open_left = false, open_right = false; switch (*line++) { case 'B': /* opening on both sides */ open_left = open_right = true; break; case 'L': /* opening on left side */ open_left = true; break; case 'R': /* opening on right side */ open_right = true; break; case 'N': /* no opening on either side */ break; case 'W': /* wall immediately ahead: */ SET_WALL(mm, r, c, front, PRESENT); assert(*line == '\0'); return; default: /* invalid char */ assert(0); } push_border(mm, r, c, front); r = RDR(r, front); c = CDC(c, front); SET_SQUARE(mm, r, c, PRESENT); SET_WALL(mm, r, c, back, ABSENT); SET_WALL(mm, r, c, left, open_left ? ABSENT : PRESENT); SET_WALL(mm, r, c, right, open_right ? ABSENT : PRESENT); if (open_left) { SET_SQUARE(mm, RDR(r, left), CDC(c, left), PRESENT); push_border(mm, r, c, left); } if (open_right) { SET_SQUARE(mm, RDR(r, right), CDC(c, right), PRESENT); push_border(mm, r, c, right); } } assert(0); /* shouldn't get here: every line must end with W */ return; }
void mm_initialize(MazeMap *mm, int r, int c, Dir dir) { mm_clear(mm); mm->loc.r = r; mm->loc.c = c; mm->dir = dir; mm->border.top = r; mm->border.left = c; mm->border.bottom = (r + 1)%WIDTH; mm->border.right = (c + 1)%HEIGHT; SET_SQUARE(mm, r, c, PRESENT); }
static bool mark_dead_end(MazeMap *mm, bool dead_end[HEIGHT][WIDTH], int r, int c) { int num_walls = 0, num_dead_adjacent = 0, dir; bool changed = false; if (dead_end[r][c]) return false; for (dir = 0; dir < 4; ++dir) { int w = WALL(mm, r, c, dir); if (w == PRESENT) ++num_walls; else if (w == ABSENT && dead_end[RDR(r, dir)][CDC(c, dir)]) ++num_dead_adjacent; } assert(num_walls + num_dead_adjacent < 4); if (num_walls + num_dead_adjacent == 3) { dead_end[r][c] = true; if (SQUARE(mm, r, c) == UNKNOWN) { SET_SQUARE(mm, r, c, PRESENT); changed = true; } for (dir = 0; dir < 4; ++dir) { if (WALL(mm, r, c, dir) == UNKNOWN) { SET_WALL(mm, r, c, dir, ABSENT); changed = true; } } for (dir = 0; dir < 4; ++dir) { if (WALL(mm, r, c, dir) == ABSENT) { if (mark_dead_end(mm, dead_end, RDR(r, dir), CDC(c, dir))) changed = true; } } } return changed; }
void mm_move(MazeMap *mm, char move) { RelDir rel_dir; switch (move) { case 'F': rel_dir = FRONT; break; case 'T': rel_dir = BACK; break; case 'L': rel_dir = LEFT; break; case 'R': rel_dir = RIGHT; break; default: assert(0); /* invalid char */ } mm->dir = TURN(mm->dir, rel_dir); push_border(mm, mm->loc.r, mm->loc.c, mm->dir); mm->loc.r = RDR(mm->loc.r, mm->dir); mm->loc.c = CDC(mm->loc.c, mm->dir); SET_SQUARE(mm, mm->loc.r, mm->loc.c, PRESENT); }
static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_grid *grid = snew(game_grid); game_state *state = snew(game_state); int area; state->params = *params; /* structure copy */ state->solid = solids[params->solid]; area = grid_area(params->d1, params->d2, state->solid->order); grid->squares = snewn(area, struct grid_square); grid->nsquares = 0; enum_grid_squares(params, add_grid_square_callback, grid); assert(grid->nsquares == area); state->grid = grid; grid->refcount = 1; state->facecolours = snewn(state->solid->nfaces, int); memset(state->facecolours, 0, state->solid->nfaces * sizeof(int)); state->bluemask = snewn((state->grid->nsquares + 31) / 32, unsigned long); memset(state->bluemask, 0, (state->grid->nsquares + 31) / 32 * sizeof(unsigned long)); /* * Set up the blue squares and polyhedron position according to * the game description. */ { const char *p = desc; int i, j, v; j = 8; v = 0; for (i = 0; i < state->grid->nsquares; i++) { if (j == 8) { v = *p++; if (v >= '0' && v <= '9') v -= '0'; else if (v >= 'A' && v <= 'F') v -= 'A' - 10; else if (v >= 'a' && v <= 'f') v -= 'a' - 10; else break; } if (v & j) SET_SQUARE(state, i, TRUE); j >>= 1; if (j == 0) j = 8; } if (*p == ',') p++; state->current = atoi(p); if (state->current < 0 || state->current >= state->grid->nsquares) state->current = 0; /* got to do _something_ */ } /* * Align the polyhedron with its grid square and determine * initial key points. */ { int pkey[4]; int ret; ret = align_poly(state->solid, &state->grid->squares[state->current], pkey); assert(ret); state->dpkey[0] = state->spkey[0] = pkey[0]; state->dpkey[1] = state->spkey[0] = pkey[1]; state->dgkey[0] = state->sgkey[0] = 0; state->dgkey[1] = state->sgkey[0] = 1; } state->previous = state->current; state->angle = 0.0; state->completed = 0; state->movecount = 0; return state; }
static game_state *execute_move(const game_state *from, const char *move) { game_state *ret; float angle; struct solid *poly; int pkey[2]; int skey[2], dkey[2]; int i, j, dest; int direction; switch (*move) { case 'L': direction = LEFT; break; case 'R': direction = RIGHT; break; case 'U': direction = UP; break; case 'D': direction = DOWN; break; default: return NULL; } dest = find_move_dest(from, direction, skey, dkey); if (dest < 0) return NULL; ret = dup_game(from); ret->current = dest; /* * So we know what grid square we're aiming for, and we also * know the two key points (as indices in both the source and * destination grid squares) which are invariant between source * and destination. * * Next we must roll the polyhedron on to that square. So we * find the indices of the key points within the polyhedron's * vertex array, then use those in a call to transform_poly, * and align the result on the new grid square. */ { int all_pkey[4]; align_poly(from->solid, &from->grid->squares[from->current], all_pkey); pkey[0] = all_pkey[skey[0]]; pkey[1] = all_pkey[skey[1]]; /* * Now pkey[0] corresponds to skey[0] and dkey[0], and * likewise [1]. */ } /* * Now find the angle through which to rotate the polyhedron. * Do this by finding the two faces that share the two vertices * we've found, and taking the dot product of their normals. */ { int f[2], nf = 0; float dp; for (i = 0; i < from->solid->nfaces; i++) { int match = 0; for (j = 0; j < from->solid->order; j++) if (from->solid->faces[i*from->solid->order + j] == pkey[0] || from->solid->faces[i*from->solid->order + j] == pkey[1]) match++; if (match == 2) { assert(nf < 2); f[nf++] = i; } } assert(nf == 2); dp = 0; for (i = 0; i < 3; i++) dp += (from->solid->normals[f[0]*3+i] * from->solid->normals[f[1]*3+i]); angle = (float)acos(dp); } /* * Now transform the polyhedron. We aren't entirely sure * whether we need to rotate through angle or -angle, and the * simplest way round this is to try both and see which one * aligns successfully! * * Unfortunately, _both_ will align successfully if this is a * cube, which won't tell us anything much. So for that * particular case, I resort to gross hackery: I simply negate * the angle before trying the alignment, depending on the * direction. Which directions work which way is determined by * pure trial and error. I said it was gross :-/ */ { int all_pkey[4]; int success; if (from->solid->order == 4 && direction == UP) angle = -angle; /* HACK */ poly = transform_poly(from->solid, from->grid->squares[from->current].flip, pkey[0], pkey[1], angle); flip_poly(poly, from->grid->squares[ret->current].flip); success = align_poly(poly, &from->grid->squares[ret->current], all_pkey); if (!success) { sfree(poly); angle = -angle; poly = transform_poly(from->solid, from->grid->squares[from->current].flip, pkey[0], pkey[1], angle); flip_poly(poly, from->grid->squares[ret->current].flip); success = align_poly(poly, &from->grid->squares[ret->current], all_pkey); } assert(success); } /* * Now we have our rotated polyhedron, which we expect to be * exactly congruent to the one we started with - but with the * faces permuted. So we map that congruence and thereby figure * out how to permute the faces as a result of the polyhedron * having rolled. */ { int *newcolours = snewn(from->solid->nfaces, int); for (i = 0; i < from->solid->nfaces; i++) newcolours[i] = -1; for (i = 0; i < from->solid->nfaces; i++) { int nmatch = 0; /* * Now go through the transformed polyhedron's faces * and figure out which one's normal is approximately * equal to this one. */ for (j = 0; j < poly->nfaces; j++) { float dist; int k; dist = 0; for (k = 0; k < 3; k++) dist += SQ(poly->normals[j*3+k] - from->solid->normals[i*3+k]); if (APPROXEQ(dist, 0)) { nmatch++; newcolours[i] = ret->facecolours[j]; } } assert(nmatch == 1); } for (i = 0; i < from->solid->nfaces; i++) assert(newcolours[i] != -1); sfree(ret->facecolours); ret->facecolours = newcolours; } ret->movecount++; /* * And finally, swap the colour between the bottom face of the * polyhedron and the face we've just landed on. * * We don't do this if the game is already complete, since we * allow the user to roll the fully blue polyhedron around the * grid as a feeble reward. */ if (!ret->completed) { i = lowest_face(from->solid); j = ret->facecolours[i]; ret->facecolours[i] = GET_SQUARE(ret, ret->current); SET_SQUARE(ret, ret->current, j); /* * Detect game completion. */ j = 0; for (i = 0; i < ret->solid->nfaces; i++) if (ret->facecolours[i]) j++; if (j == ret->solid->nfaces) { ret->completed = ret->movecount; } } sfree(poly); /* * Align the normal polyhedron with its grid square, to get key * points for non-animated display. */ { int pkey[4]; int success; success = align_poly(ret->solid, &ret->grid->squares[ret->current], pkey); assert(success); ret->dpkey[0] = pkey[0]; ret->dpkey[1] = pkey[1]; ret->dgkey[0] = 0; ret->dgkey[1] = 1; } ret->spkey[0] = pkey[0]; ret->spkey[1] = pkey[1]; ret->sgkey[0] = skey[0]; ret->sgkey[1] = skey[1]; ret->previous = from->current; ret->angle = angle; return ret; }
bool Board::Set_Piece_onSquare(pieces pc, squares sq) { switch(pc) { case wP: White_Pawns |= SET_SQUARE(sq); White_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = wP; break; case wN: White_Knights |= SET_SQUARE(sq); White_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = wN; break; case wB: White_Bishops |= SET_SQUARE(sq); White_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = wB; break; case wR: White_Rooks |= SET_SQUARE(sq); White_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = wR; break; case wQ: White_Queens |= SET_SQUARE(sq); White_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = wQ; break; case wK: White_King |= SET_SQUARE(sq); White_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = wK; KingSquare[WHITE] = sq; break; case bP: Black_Pawns |= SET_SQUARE(sq); Black_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = bP; break; case bN: Black_Knights |= SET_SQUARE(sq); Black_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = bN; break; case bB: Black_Bishops |= SET_SQUARE(sq); Black_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = bB; break; case bR: Black_Rooks |= SET_SQUARE(sq); Black_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = bR; break; case bQ: Black_Queens |= SET_SQUARE(sq); Black_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = bQ; break; case bK: Black_King |= SET_SQUARE(sq); Black_Pieces |= SET_SQUARE(sq); Piece_Type_By_Square[sq] = bK; KingSquare[BLACK] = sq; break; default: return false; } All_Pieces |= SET_SQUARE(sq); return true; }