DISTCLEANFILES += $(GUIFILES:.dat=.h)
EXTRA_DIST += $(DX_BASEDIR)/scripts/gen-tree.awk $(GUIFILES)
-check_PROGRAMS = t/boardmove t/ewmhicon t/rng-test
+check_PROGRAMS = t/boardmove t/boardbit t/ewmhicon t/rng-test
EXTRA_DIST += t/xos256ss.c
t_boardmove_SOURCES = t/boardmove.c src/game.c
t_boardmove_LDADD = libgnu.a
$(t_boardmove_OBJECTS): $(gnulib_headers)
+t_boardbit_SOURCES = t/boardbit.c
+t_boardbit_LDADD = libgnu.a
+$(t_boardbit_OBJECTS): $(gnulib_headers)
+
t_ewmhicon_SOURCES = t/ewmhicon.c src/ewmhicon.c common/src/help.c
t_ewmhicon_LDADD = libgnu.a $(MOTIF_LIBS)
$(t_ewmhicon_OBJECTS): $(gnulib_headers)
return (col << 5*y1) & (col >> 5*(4-y0));
}
+/*
+ * Return the board bitmap setting locations on or above row y.
+ */
+static inline uint_fast32_t board_above(int y)
+{
+ uint_fast32_t val = board_row(y);
+
+ return val | (val-1);
+}
+
+/*
+ * Return the board bitmap setting locations on or below row y.
+ */
+static inline uint_fast32_t board_below(int y)
+{
+ uint_fast32_t val = board_row(y);
+
+ return val | (~val + 1);
+}
+
+/*
+ * Return the board bitmap setting locations on or left of column x.
+ */
+static inline uint_fast32_t board_left(int x)
+{
+ uint_fast32_t val = board_column(x);
+
+ return val | (val - 0x108421);
+}
+
+/*
+ * Return the board bitmap setting locations on or right of column x.
+ */
+static inline uint_fast32_t board_right(int x)
+{
+ uint_fast32_t val = board_column(x);
+
+ return ~val + 0x108421;
+}
+
/*
* 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
game_reset(&state.board);
x11_redraw_goal(&state);
- x11_redraw_game(&state);
+ x11_redraw_game(&state, -1);
x11_redraw_icon(&state, shell);
}
void x11_initialize(struct app_state *state, Screen *screen);
void x11_redraw_icon(struct app_state *state, Widget shell);
void x11_redraw_goal(struct app_state *state);
-void x11_redraw_game(struct app_state *state);
+void x11_redraw_game(struct app_state *state, uint_fast32_t mask);
#endif
static void game_resize(Widget w, void *data, void *cb_data)
{
if (XtIsRealized(w))
- x11_redraw_game(data);
+ x11_redraw_game(data, -1);
}
static void goal_resize(Widget w, void *data, void *cb_data)
x11_redraw_goal(data);
}
+static void do_input_move(struct app_state *state, int x, int y)
+{
+ uint_least32_t *gp = state->board.game, prev[4];
+
+ memcpy(prev, gp, sizeof prev);
+ if (game_do_move(&state->board, x, y) == 0) {
+ uint_least32_t mask;
+
+ if (game_check_goal(&state->board)) {
+ printf("You win!\n");
+ game_finish(&state->board);
+ }
+
+ /* Figure out which tiles changed */
+ prev[0] ^= gp[0];
+ prev[1] ^= gp[1];
+ prev[2] ^= gp[2];
+ mask = prev[0] | prev[1] | prev[2];
+
+ x11_redraw_game(state, mask);
+ }
+}
+
static void game_input(Widget w, void *data, void *cb_data)
{
XmDrawingAreaCallbackStruct *cbs = cb_data;
XmNheight, &height,
(char *)NULL);
x = click->x / (width/5);
- y = click->y / (width/5);
+ y = click->y / (height/5);
}
if (x > 4 || y > 4)
return;
- if (game_do_move(&state->board, x, y) == 0) {
- if (game_check_goal(&state->board)) {
- printf("You win!\n");
- game_finish(&state->board);
- }
+ do_input_move(state, x, y);
+}
- x11_redraw_game(state);
- }
+static void game_expose(Widget w, void *data, void *cb_data)
+{
+ XmDrawingAreaCallbackStruct *cbs = cb_data;
+ XExposeEvent *e = &cbs->event->xexpose;
+ uint_fast32_t tile_mask;
+ Dimension width, height;
+
+ XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, (char *)NULL);
+ if (!(width /= 5) || !(height /= 5))
+ return;
+
+ /* Figure out which tiles have been uncovered */
+ tile_mask = board_right(e->x / width);
+ tile_mask &= board_below(e->y / height);
+ tile_mask &= board_above((e->y + e->height - 1) / height);
+ tile_mask &= board_left((e->x + e->width - 1) / width);
+
+ x11_redraw_game(data, tile_mask);
}
void ui_initialize(struct app_state *state, Widget shell)
state->game = XtNameToWidget(shell, "*gameCanvas");
XtAddCallback(state->game, XmNresizeCallback, game_resize, state);
- XtAddCallback(state->game, XmNexposeCallback, game_resize, state);
+ XtAddCallback(state->game, XmNexposeCallback, game_expose, state);
XtAddCallback(state->game, XmNinputCallback, game_input, state);
state->goal = XtNameToWidget(shell, "*goalCanvas");
}
}
-void x11_redraw_game(struct app_state *state)
+void x11_redraw_game(struct app_state *state, uint_fast32_t mask)
{
Display *display = XtDisplay(state->goal);
Window game = XtWindow(state->game);
+ uint_least32_t *gp = state->board.game;
Dimension w, h;
int i;
w /= 5; h /= 5;
for (i = 0; i < 25; i++) {
- uint_least32_t *gp = state->board.game;
-
- 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[0], gp[1], gp[2],
+ i%5, i/5, w, h);
+ }
+ mask >>= 1;
}
}
+/boardbit
/boardmove
/ewmhicon
/rng-test
--- /dev/null
+/*
+ * Test board mask calculation functions.
+ * Copyright © 2022 Nick Bowler
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include "game.h"
+
+enum { display_width = 12 };
+
+static void show_patterns(const char *name, uint_fast32_t func(int))
+{
+ unsigned long vals[5];
+ int i, row, labelw = display_width;
+
+ for (i = 0; i < 5; i++) {
+ printf("%*s", display_width-labelw, "");
+ labelw = printf("%2s(%d)", name, i);
+ vals[i] = func(i);
+ }
+ putchar('\n');
+
+ for (row = 0; row < 5; row++) {
+ putchar(' ');
+ for (i = 0; i < 25; i++) {
+ unsigned long val;
+
+ val = vals[i/5];
+ vals[i/5] >>= 1;
+
+ if (i && i % 5 == 0)
+ printf("%*s", display_width-5, "");
+ putchar(val & 1 ? '@' : '.');
+ if (i == 24)
+ putchar('\n');
+ }
+ }
+}
+
+int main(void)
+{
+ show_patterns("left", board_left);
+ putchar('\n');
+ show_patterns("right", board_right);
+ putchar('\n');
+ show_patterns("above", board_above);
+ putchar('\n');
+ show_patterns("below", board_below);
+}
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
+AT_SETUP([board bitmap functions])
+
+AT_CHECK([boardbit], [0],
+[[left(0) left(1) left(2) left(3) left(4)
+ @.... @@... @@@.. @@@@. @@@@@
+ @.... @@... @@@.. @@@@. @@@@@
+ @.... @@... @@@.. @@@@. @@@@@
+ @.... @@... @@@.. @@@@. @@@@@
+ @.... @@... @@@.. @@@@. @@@@@
+
+right(0) right(1) right(2) right(3) right(4)
+ @@@@@ .@@@@ ..@@@ ...@@ ....@
+ @@@@@ .@@@@ ..@@@ ...@@ ....@
+ @@@@@ .@@@@ ..@@@ ...@@ ....@
+ @@@@@ .@@@@ ..@@@ ...@@ ....@
+ @@@@@ .@@@@ ..@@@ ...@@ ....@
+
+above(0) above(1) above(2) above(3) above(4)
+ @@@@@ @@@@@ @@@@@ @@@@@ @@@@@
+ ..... @@@@@ @@@@@ @@@@@ @@@@@
+ ..... ..... @@@@@ @@@@@ @@@@@
+ ..... ..... ..... @@@@@ @@@@@
+ ..... ..... ..... ..... @@@@@
+
+below(0) below(1) below(2) below(3) below(4)
+ @@@@@ ..... ..... ..... .....
+ @@@@@ @@@@@ ..... ..... .....
+ @@@@@ @@@@@ @@@@@ ..... .....
+ @@@@@ @@@@@ @@@@@ @@@@@ .....
+ @@@@@ @@@@@ @@@@@ @@@@@ @@@@@
+]])
+
+AT_CLEANUP
+
AT_SETUP([game_do_move zigzag])
AT_CHECK([boardmove m4_do(