rng_state[3] = splitmix64(&seed);
}
+#define assign_tile(planes, tile, bit) do { \
+ 0[planes] |= (((tile)>>0) & 1ul) << (bit); \
+ 1[planes] |= (((tile)>>1) & 1ul) << (bit); \
+ 2[planes] |= (((tile)>>2) & 1ul) << (bit); \
+} while (0)
+
void game_reset(struct board *board)
{
unsigned char tiles[25];
shuffle(tiles, 24);
memset(board->goal, 0, sizeof board->goal);
- for (i = 0; i < 9; i++) {
- uint_fast32_t position = board_position(i/3+1, i%3+1) >> 6;
-
- if (tiles[i] & 1) board->goal[0] |= position;
- if (tiles[i] & 2) board->goal[1] |= position;
- if (tiles[i] & 4) board->goal[2] |= position;
+ /*
+ * Goal bitmap has 2-tile "gaps" between rows; it doesn't matter what
+ * these are set to and since we have a random permutation it doesn't
+ * matter which of the 24 nonempty tiles we pick for the actual goal.
+ */
+ for (i = 0; i < 13; i++) {
+ assign_tile(board->goal, tiles[i], i);
}
tiles[24] = TILE_EMPTY;
shuffle(tiles, 25);
-
memset(board->game, 0, sizeof board->game);
+
for (i = 0; i < 25; i++) {
- unsigned x = i/5, y = i%5;
- uint_fast32_t position;
-
- position = board_position(x, y);
- if (tiles[i] != TILE_EMPTY) {
- if (tiles[i] & 1) board->game[0] |= position;
- if (tiles[i] & 2) board->game[1] |= position;
- if (tiles[i] & 4) board->game[2] |= position;
- } else {
- board->game[3] = ~position;
- board->x = x;
- board->y = y;
+ assign_tile(board->game, tiles[i], i);
+
+ if (tiles[i] == TILE_EMPTY) {
+ board->game[3] = (1ul<<i);
+ board->x = i%5;
+ board->y = i/5;
+ }
+ }
+
+/* Uncomment to make every game stupidly easy -- winnable in 1 move */
+#if 0
+ /* Force empty space to the border */
+ if (board_position(board->x, board->y) & GOAL_MASK) {
+ switch (rng_uniform_int(4)) {
+ case 0: game_do_move(board, board->x, 0); break;
+ case 1: game_do_move(board, board->x, 4); break;
+ case 2: game_do_move(board, 0, board->y); break;
+ case 3: game_do_move(board, 4, board->y); break;
}
}
+
+ /* Force goal to match the current board */
+ for (i = 0; i < 3; i++) {
+ board->goal[i] = (board->game[i] & GOAL_MASK) >> GOAL_SHIFT;
+ }
+
+ /* Move empty space back to the centre */
+ if (board->x == 0 || board->x == 4) {
+ game_do_move(board, 1+rng_uniform_int(3), board->y);
+ }
+
+ if (board->y == 0 || board->y == 4) {
+ game_do_move(board, board->x, 1+rng_uniform_int(3));
+ }
+#endif
}
uint_fast32_t game_do_move(struct board *board, int x, int y)
int i;
for (i = 0; i < 3; i++)
- mask |= goal[i] ^ (game[i] >> GOAL_SHIFT);
- return (mask << GOAL_SHIFT) & GOAL_MASK;
+ mask |= game[i] ^ ((0ul+goal[i]) << GOAL_SHIFT);
+ return mask & GOAL_MASK;
}
void game_begin(struct board *board)
board->time_start = gethrxtime();
}
-static int_fast32_t elapsed(struct board *board)
+int_fast32_t game_elapsed(struct board *board)
{
return (gethrxtime() - board->time_start) / 1000000;
}
int_fast32_t game_finish(struct board *board)
{
- int_fast32_t t = elapsed(board);
+ int_fast32_t t = game_elapsed(board);
int i;
for (i = 0; i < 4; i++) {