From f6be82664a5b8e8bc34c048b56417b591dcd5a5e Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 13 Dec 2022 22:10:15 -0500 Subject: [PATCH] Pack/unpack the tile planes arithmetically. 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. --- src/curses.c | 22 +++++++++------------- src/game.c | 39 ++++++++++++++++++++------------------- src/game.h | 10 ++++++++++ src/x11.c | 29 +++++++++++------------------ 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/curses.c b/src/curses.c index 5cf8882..f66589e 100644 --- a/src/curses.c +++ b/src/curses.c @@ -115,17 +115,11 @@ static void draw_tile(WINDOW **win, unsigned colour, unsigned selected, 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; assert(tile < TILE_MAX); - draw_tile(win, tile, selected, x, y, start_column); return tile; } @@ -173,8 +167,7 @@ static void curs_redraw_game(struct app_state *state, uint_fast32_t mask) 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); } mask >>= 1; } @@ -182,7 +175,11 @@ static void curs_redraw_game(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]) @@ -194,8 +191,7 @@ static void curs_redraw_goal(struct app_state *state, uint_fast32_t mask) 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); } mask >>= 1; } diff --git a/src/game.c b/src/game.c index 47adc9f..eefafe5 100644 --- a/src/game.c +++ b/src/game.c @@ -119,6 +119,12 @@ void game_reseed(unsigned long long 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]; @@ -141,31 +147,26 @@ void game_reset(struct board *board) 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<x = i%5; + board->y = i/5; } } diff --git a/src/game.h b/src/game.h index 7640b41..e5b9cbe 100644 --- a/src/game.h +++ b/src/game.h @@ -167,6 +167,16 @@ static inline uint_fast32_t board_rect(int x1, int y1, int x2, int y2) 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 diff --git a/src/x11.c b/src/x11.c index b098d0e..34f43a9 100644 --- a/src/x11.c +++ b/src/x11.c @@ -174,11 +174,9 @@ static void clear_border(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)) { @@ -189,12 +187,7 @@ redraw_tile(struct app_state *state, Display *display, Drawable d, usleep(70000); } #endif - - if (bit0 & pos) tile |= 1; - if (bit1 & pos) tile |= 2; - if (bit2 & pos) tile |= 4; assert(tile < TILE_MAX); - if (tile == TILE_EMPTY) { XClearArea(display, d, x*w, y*h, w, h, 0); } else { @@ -208,9 +201,13 @@ static int 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) @@ -226,9 +223,8 @@ 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; - if (mask & 1) { + if (mask & 1) redraw_goal_tile(state, display, goal, x, y, w, h); - } /* * Goal bitmaps have a gap of 2 tiles between each row. @@ -310,11 +306,8 @@ void x11_redraw_game(struct app_state *state, uint_fast32_t mask) } 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); mask >>= 1; } } -- 2.43.2