]> git.draconx.ca Git - rrace.git/commitdiff
Check victory condition so the game is winnable.
authorNick Bowler <nbowler@draconx.ca>
Sat, 5 Mar 2022 07:58:34 +0000 (02:58 -0500)
committerNick Bowler <nbowler@draconx.ca>
Sat, 5 Mar 2022 21:58:37 +0000 (16:58 -0500)
src/game.c
src/game.h
src/motif_ui.c
src/x11.c

index bd1fef98eb5e209d2797868524857743ce99eb30..ca03830545b7ee76392ce3087b66e8da9c417883 100644 (file)
@@ -1,8 +1,25 @@
 /*
+ * Slide puzzle core game logic
+ * 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/>.
+ *
  * The RNG implementation is adapted from xoshiro256** and splitmix64
  * by David Blackman and Sebastiano Vigna, originally distributed under
  * the Creative Commons Zero public domain dedication.
  */
+
 #include <config.h>
 #include <limits.h>
 #include <string.h>
@@ -136,17 +153,17 @@ void game_reset(struct board *board)
                uint_fast32_t position;
 
                position = board_position(x, y);
-               if (tiles[i] == TILE_EMPTY) {
-                       board->game[0] = 0x1ffffff ^ position;
-                       board->x = x;
-                       board->y = y;
-               } else {
+               if (tiles[i] != TILE_EMPTY) {
                        if (tiles[i] & 1)
-                               board->game[1] |= position;
+                               board->game[0] |= position;
                        if (tiles[i] & 2)
-                               board->game[2] |= position;
+                               board->game[1] |= position;
                        if (tiles[i] & 4)
-                               board->game[3] |= position;
+                               board->game[2] |= position;
+               } else {
+                       board->game[3] = 0x1ffffff ^ position;
+                       board->x = x;
+                       board->y = y;
                }
        }
 }
@@ -179,3 +196,29 @@ int game_do_move(struct board *board, int x, int y)
        board->y = y;
        return 0;
 }
+
+#define GOAL_MASK 0x739c0
+
+int game_check_goal(struct board *board)
+{
+       int i, ret = 1;
+
+       for (i = 0; i < 3; i++)
+               ret &= ((board->game[i] & GOAL_MASK) >> 6) == board->goal[i];
+       return ret;
+}
+
+void game_finish(struct board *board)
+{
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               board->game[i] &= GOAL_MASK;
+       }
+
+       /*
+        * Setting both x and y hole location to a bogus value will effectively
+        * disable the game since there will be no valid moves.
+        */
+       board->x = board->y = -1;
+}
index f4473a71ae8d64e332e3bd5690c1f0cc1310ea3c..d17eb992f7fd3d86d19d521b537588c4e1dbe2c5 100644 (file)
@@ -42,11 +42,11 @@ struct board {
         * corresponds to position (0,0), bit 4 is position (4,0) and bit 25
         * is position (4, 4).
         *
-        *   game[0] - the board mask, all bits set except one indicating the
+        *   game[0] - least significant bit of the tile's colour.
+        *   game[1] - tile colour.
+        *   game[2] - most significant bit of the tile's colour.
+        *   game[3] - the board mask, all bits set except one indicating the
         *             absense of a tile at this position.
-        *   game[1] - least significant bit of the tile's colour.
-        *   game[2] - tile colour.
-        *   game[3] - most significant bit of the tile's colour.
         */
        uint_least32_t game[4];
 
@@ -119,6 +119,11 @@ static inline uint_fast32_t board_mask_v(int x, int y0, int y1)
  */
 int game_do_move(struct board *board, int x, int y);
 
+/*
+ * Returns 1 if the game is in a winning position, or 0 otherwise.
+ */
+int game_check_goal(struct board *board);
+
 /*
  * Initialize the game RNG such that the next call to game_reset will produce a
  * new board that is entirely dependent on the given seed value.
@@ -130,4 +135,9 @@ void game_reseed(unsigned long long seed);
  */
 void game_reset(struct board *board);
 
+/*
+ * Disable new moves and clear all tile bits other than the 9 goal tiles.
+ */
+void game_finish(struct board *board);
+
 #endif
index 40f463289ca12db1bc72f5658abd564dc1a91e95..279f550ffc80bd1806636e552ed0673adaaab47f 100644 (file)
@@ -239,6 +239,11 @@ static void game_input(Widget w, void *data, void *cb_data)
                return;
 
        if (game_do_move(&state->board, x, y) == 0) {
+               if (game_check_goal(&state->board)) {
+                       printf("You win!\n");
+                       game_finish(&state->board);
+               }
+
                x11_redraw_game(state);
        }
 }
index 9ded09ea75765c96d6ec8a5731864dcdedfc627b..598b11542fd3705772bd603fcece267bb8298a3f 100644 (file)
--- a/src/x11.c
+++ b/src/x11.c
@@ -143,7 +143,7 @@ void x11_redraw_game(struct app_state *state)
        w /= 5; h /= 5;
 
        for (i = 0; i < 25; i++) {
-               uint_least32_t *gp = state->board.game+1;
+               uint_least32_t *gp = state->board.game;
 
                redraw_tile(state, display, game,
                            gp[0], gp[1], gp[2],