From 384c634555c6c65635abfcb819e37221d236b410 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 6 Dec 2022 22:40:10 -0500 Subject: [PATCH] Improve game_check_goal implementation slightly. It seems that, at least on x86, GCC can generate very slightly more compact code by "expanding" the goal bitmap to match the game format, rather what is currently done ("shrinking" the game bitmap to match the goal format). Add a sanity test case that checks the result of this function, which makes such a change straightforward to do. --- Makefile.am | 6 +++++- src/game.c | 4 ++-- t/.gitignore | 1 + t/checkgoal.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ tests/game.at | 30 ++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 t/checkgoal.c diff --git a/Makefile.am b/Makefile.am index b475a79..1d55ab7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -87,7 +87,7 @@ EXTRA_DIST += $(DX_BASEDIR)/scripts/gen-tree.awk DISTCLEANFILES += $(TREEFILES:.dat=.h) EXTRA_DIST += $(TREEFILES) -check_PROGRAMS = t/boardmove t/boardbit t/ewmhicon t/rng-test +check_PROGRAMS = t/boardmove t/boardbit t/checkgoal t/ewmhicon t/rng-test EXTRA_DIST += t/xos256ss.c t_boardmove_SOURCES = t/boardmove.c src/game.c @@ -102,6 +102,10 @@ t_ewmhicon_SOURCES = t/ewmhicon.c src/ewmhicon.c src/icon.c common/src/help.c t_ewmhicon_LDADD = libgnu.a $(MOTIF_LIBS) $(t_ewmhicon_OBJECTS): $(gnulib_headers) +t_checkgoal_SOURCES = t/checkgoal.c src/game.c +t_checkgoal_LDADD = libgnu.a +$(t_checkgoal_OBJECTS): $(gnulib_headers) + t_rng_test_LDADD = libgnu.a $(t_rng_test_OBJECTS): $(gnulib_headers) diff --git a/src/game.c b/src/game.c index 4946f8d..47adc9f 100644 --- a/src/game.c +++ b/src/game.c @@ -236,8 +236,8 @@ uint_fast32_t game_check_goal(struct board *board) 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) diff --git a/t/.gitignore b/t/.gitignore index 52f3776..9ecb975 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -1,4 +1,5 @@ /boardbit /boardmove +/checkgoal /ewmhicon /rng-test diff --git a/t/checkgoal.c b/t/checkgoal.c new file mode 100644 index 0000000..0941e91 --- /dev/null +++ b/t/checkgoal.c @@ -0,0 +1,59 @@ +/* + * Helper to test game_check_goal function. + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include "game.h" + +#define X3(x) x x x + +static const char *progname = "checkgoal"; + +int main(int argc, char **argv) +{ + struct board board; + int rc; + + if (argc > 0) + progname = argv[0]; + + while ((rc = scanf(X3("%" SCNxLEAST32) X3("%" SCNxLEAST16), + &board.game[0], &board.game[1], + &board.game[2], &board.goal[0], + &board.goal[1], &board.goal[2])) == 6) + { + printf("%.5" PRIxFAST32 "\n", game_check_goal(&board)); + } + + if (rc == EOF) { + if (ferror(stdin)) { + fprintf(stderr, "%s: read error: %s\n", progname, + strerror(errno)); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; + } + + fprintf(stderr, "%s: invalid input sequence\n", progname); + return EXIT_FAILURE; +} diff --git a/tests/game.at b/tests/game.at index b607cf6..76c802a 100644 --- a/tests/game.at +++ b/tests/game.at @@ -597,3 +597,33 @@ grep -v '^ok' out], [0], [1..200 ]) AT_CLEANUP + +AT_SETUP([game_check_goal]) + +AT_DATA([boards.dat], +[[0 0 0 0 0 0 +1f8c63f 1f8c63f 1f8c63f 0000 0000 0000 +1f8c63f 1f8c63f 1f8c63f ffff 0000 0000 +1f8c63f 1f8c63f 1f8c63f 0000 ffff 0000 +1f8c63f 1f8c63f 1f8c63f 0000 0000 ffff +00739c0 1f8c63f 1f8c63f ffff 0000 0000 +1f8c63f 00739c0 1f8c63f 0000 ffff 0000 +1f8c63f 1f8c63f 00739c0 0000 0000 ffff +0000000 0000000 0000000 0001 0020 0400 +]]) + +AT_DATA([expout], +[[00000 +00000 +739c0 +739c0 +739c0 +00000 +00000 +00000 +10840 +]]) + +AT_CHECK([checkgoal result.dat && cat result.dat], [0], [expout]) + +AT_CLEANUP -- 2.43.2