Instead of a bunch of if statements, add a macro to extract an
individual tile value from the game/goal bitmaps using bitwise
arithmetic, and restructure the drawing paths to use it.
A similar change is made to populate the bitmaps during game board
initialization. This simplifies the code a bit and also seems to
reduce the compiled size somewhat.
static int
redraw_tile(WINDOW **win, unsigned x, unsigned y, unsigned start_column,
static int
redraw_tile(WINDOW **win, unsigned x, unsigned y, unsigned start_column,
- uint_fast32_t bit0, uint_fast32_t bit1, uint_fast32_t bit2,
- unsigned selected)
+ uint_least32_t *gp, unsigned selected)
- uint_fast32_t pos = board_position(x, y);
- unsigned char tile = 0;
+ unsigned tile = board_tile(gp, 5*y+x);
- if (bit0 & pos) tile |= 1;
- if (bit1 & pos) tile |= 2;
- if (bit2 & pos) tile |= 4;
draw_tile(win, tile, selected, x, y, start_column);
return tile;
}
draw_tile(win, tile, selected, x, y, start_column);
return tile;
}
for (i = 0; i < 25; i++) {
if (mask & 1) {
redraw_tile(state->gamewin, i%5, i/5,
for (i = 0; i < 25; i++) {
if (mask & 1) {
redraw_tile(state->gamewin, i%5, i/5,
- 4, gp[0], gp[1], gp[2],
- i == state->cursor);
+ 4, gp, i == state->cursor);
static void curs_redraw_goal(struct app_state *state, uint_fast32_t mask)
{
static void curs_redraw_goal(struct app_state *state, uint_fast32_t mask)
{
- uint_least16_t *gp = state->board.goal;
+ uint_least32_t gp[3] = {
+ state->board.goal[0],
+ state->board.goal[1],
+ state->board.goal[2]
+ };
int i, x, y;
if (!state->goalwin[PLAYWIN_AREA])
int i, x, y;
if (!state->goalwin[PLAYWIN_AREA])
for (i = 0; i < 9; i++) {
if (mask & 1) {
for (i = 0; i < 9; i++) {
if (mask & 1) {
- redraw_tile(state->goalwin, i%3, i/3,
- x+2, gp[0], gp[1], gp[2], 0);
+ redraw_tile(state->goalwin, i%3, i/3, x+2, gp, 0);
rng_state[3] = splitmix64(&seed);
}
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];
void game_reset(struct board *board)
{
unsigned char tiles[25];
shuffle(tiles, 24);
memset(board->goal, 0, sizeof board->goal);
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);
}
tiles[24] = TILE_EMPTY;
shuffle(tiles, 25);
memset(board->game, 0, sizeof board->game);
memset(board->game, 0, sizeof board->game);
for (i = 0; i < 25; i++) {
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;
return (board_left(x2-x1) << x1) & (board_above(y2-y1) << 5*y1);
}
return (board_left(x2-x1) << x1) & (board_above(y2-y1) << 5*y1);
}
+/*
+ * Extract the tile colour from a specific position of one of the
+ * arrays of tile bitmaps. The position is a bit index. So for
+ * example, game the tile at a given (x, y) position can be extracted
+ * by board_tile(board.game, 5*y+x).
+ */
+#define board_tile(planes, bit) (((0[planes]<<0) >> (bit)) & 1) \
+ | (((1[planes]<<1) >> (bit)) & 2) \
+ | (((2[planes]<<2) >> (bit)) & 4)
+
/*
* Move the bits in the game bitmaps according to a move at position (x, y),
* and update the location of the empty position which, if the move was valid
/*
* Move the bits in the game bitmaps according to a move at position (x, y),
* and update the location of the empty position which, if the move was valid
static int
redraw_tile(struct app_state *state, Display *display, Drawable d,
static int
redraw_tile(struct app_state *state, Display *display, Drawable d,
- uint_fast32_t bit0, uint_fast32_t bit1, uint_fast32_t bit2,
- int x, int y, Dimension w, Dimension h)
+ uint_least32_t *gp, int x, int y, Dimension w, Dimension h)
- uint_fast32_t pos = board_position(x, y);
- unsigned char tile = 0;
+ unsigned tile = board_tile(gp, 5*y+x);
#if X11_RENDER_DEBUG
if (d == XtWindow(state->game) || d == XtWindow(state->goal)) {
#if X11_RENDER_DEBUG
if (d == XtWindow(state->game) || d == XtWindow(state->goal)) {
-
- if (bit0 & pos) tile |= 1;
- if (bit1 & pos) tile |= 2;
- if (bit2 & pos) tile |= 4;
if (tile == TILE_EMPTY) {
XClearArea(display, d, x*w, y*h, w, h, 0);
} else {
if (tile == TILE_EMPTY) {
XClearArea(display, d, x*w, y*h, w, h, 0);
} else {
redraw_goal_tile(struct app_state *state, Display *display, Drawable d,
int x, int y, Dimension w, Dimension h)
{
redraw_goal_tile(struct app_state *state, Display *display, Drawable d,
int x, int y, Dimension w, Dimension h)
{
- uint_least16_t *gp = state->board.goal;
+ uint_least32_t gp[3] = {
+ state->board.goal[0],
+ state->board.goal[1],
+ state->board.goal[2]
+ };
- return redraw_tile(state, display, d, gp[0], gp[1], gp[2], x, y, w, h);
+ return redraw_tile(state, display, d, gp, x, y, w, h);
}
void x11_redraw_goal(struct app_state *state, uint_fast32_t mask)
}
void x11_redraw_goal(struct app_state *state, uint_fast32_t mask)
for (i = 0; i < 9; i++) {
int x = i%3, y = i/3;
for (i = 0; i < 9; i++) {
int x = i%3, y = i/3;
redraw_goal_tile(state, display, goal, x, y, w, h);
redraw_goal_tile(state, display, goal, x, y, w, h);
/*
* Goal bitmaps have a gap of 2 tiles between each row.
/*
* Goal bitmaps have a gap of 2 tiles between each row.
}
for (i = 0; i < 25; i++) {
}
for (i = 0; i < 25; i++) {
- if (mask & 1) {
- redraw_tile(state, display, game,
- gp[0], gp[1], gp[2],
- i%5, i/5, w, h);
- }
+ if (mask & 1)
+ redraw_tile(state, display, game, gp, i%5, i/5, w, h);