]> git.draconx.ca Git - rrace.git/blobdiff - src/game.h
Fix bitmap generation in goal overlay feature.
[rrace.git] / src / game.h
index f4473a71ae8d64e332e3bd5690c1f0cc1310ea3c..56fb4427fcc18abb2b3d99abdfe98006b7143fbd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Slide puzzle core game logic
- * Copyright © 2022 Nick Bowler
+ * Copyright © 2022-2023 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
@@ -20,6 +20,7 @@
 #define RRACE_GAME_H_
 
 #include <inttypes.h>
+#include <xtime.h>
 
 enum {
        TILE_EMPTY,
@@ -32,7 +33,10 @@ enum {
        TILE_MAX
 };
 
-enum { GOAL_SHIFT = 6 };
+#define GOAL_SHIFT 6
+#define GOAL_MASK 0x739c0ul
+#define GAME_MASK 0x1fffffful
+
 struct board {
        /*
         * Bit planes representing the current game area.
@@ -42,11 +46,12 @@ 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
-        *             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.
+        *   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] - No internal meaning.  The game_reset function will clear
+        *             the bit at the empty position and set all others, and
+        *             game_do_move will adjust it.
         */
        uint_least32_t game[4];
 
@@ -62,8 +67,10 @@ struct board {
         */
        uint_least16_t goal[3];
 
-       /* (x, y) position of the current empty position. */
+       /* (x, y) position of the current empty space. */
        uint_least8_t x, y;
+
+       xtime_t time_start;
 };
 
 /* Return the board bitmap with all bits in column x set */
@@ -110,14 +117,82 @@ static inline uint_fast32_t board_mask_v(int x, int y0, int y1)
        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)
+{
+       return ( 0x20ul << 5*y ) - 1;
+}
+
+/*
+ * Return the board bitmap setting locations on or below row y.
+ */
+static inline uint_fast32_t board_below(int y)
+{
+       return ~( 1ul << 5*y ) + 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;
+}
+
+/*
+ * Return the board bitmap setting the rectangle of locations that are:
+ *
+ *   - on or right of column x1, and
+ *   - on or left of column x2, and
+ *   - on or below row y1, and
+ *   - on or above row y2.
+ *
+ * It must be the case that x2 >= x1 and y2 >= y1.
+ */
+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
  * is now (x, y).
  *
- * Returns 0 if the move was valid (and board has been updated), -1 otherwise.
+ * Returns the board bitmap indicating which positions changed.  A return
+ * value of 0 therefore indicates an invalid move.
  */
-int game_do_move(struct board *board, int x, int y);
+uint_fast32_t game_do_move(struct board *board, int x, int y);
+
+/*
+ * Returns the board bitmap setting game locations that differ from the goal.
+ * A return value of 0 therefore indicates a winning position.
+ */
+uint_fast32_t game_check_goal(struct board *board);
 
 /*
  * Initialize the game RNG such that the next call to game_reset will produce a
@@ -130,4 +205,37 @@ void game_reseed(unsigned long long seed);
  */
 void game_reset(struct board *board);
 
+/*
+ * Reset the game start time.
+ */
+void game_begin(struct board *board);
+
+/*
+ * Return the total elapsed time (in ms) since the last call to game_begin.
+ */
+int_fast32_t game_elapsed(struct board *board);
+
+/*
+ * Disable new moves and clear all tile bits other than the 9 goal tiles.
+ * Returns the total elapsed time (in ms).
+ */
+int_fast32_t game_finish(struct board *board);
+
+/*
+ * Constructs a new set of game bitmaps into buf, with tiles in the
+ * objective area replaced by the goal tile colours, and returns buf.
+ */
+static inline uint_least32_t *
+game_overlay_goal(struct board *board, uint_least32_t *buf)
+{
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               buf[i] = (unsigned long)board->goal[i] << GOAL_SHIFT;
+               buf[i] = (buf[i] & GOAL_MASK) | (board->game[i] & ~GOAL_MASK);
+       }
+
+       return buf;
+}
+
 #endif