]> git.draconx.ca Git - rrace.git/blob - src/game.h
d17eb992f7fd3d86d19d521b537588c4e1dbe2c5
[rrace.git] / src / game.h
1 /*
2  * Slide puzzle core game logic
3  * Copyright © 2022 Nick Bowler
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  */
18
19 #ifndef RRACE_GAME_H_
20 #define RRACE_GAME_H_
21
22 #include <inttypes.h>
23
24 enum {
25         TILE_EMPTY,
26         TILE_RED,
27         TILE_ORANGE,
28         TILE_YELLOW,
29         TILE_GREEN,
30         TILE_BLUE,
31         TILE_WHITE,
32         TILE_MAX
33 };
34
35 enum { GOAL_SHIFT = 6 };
36 struct board {
37         /*
38          * Bit planes representing the current game area.
39          *
40          * The 5x5 game board is represented by these four 25-bit values.
41          * The bits are arranged in row-major order so, for example, bit 0
42          * corresponds to position (0,0), bit 4 is position (4,0) and bit 25
43          * is position (4, 4).
44          *
45          *   game[0] - least significant bit of the tile's colour.
46          *   game[1] - tile colour.
47          *   game[2] - most significant bit of the tile's colour.
48          *   game[3] - the board mask, all bits set except one indicating the
49          *             absense of a tile at this position.
50          */
51         uint_least32_t game[4];
52
53         /*
54          * Bit planes representing the goal area.
55          *
56          * These are encoded identically to the game area, except the values
57          * are shifted right by 6 as only bits 6 through 18 are relevant.
58          *
59          *   goal[0] - least significant bit of the tile's colour.
60          *   goal[2] - tile colour.
61          *   goal[3] - most significant bit of the tile's colour.
62          */
63         uint_least16_t goal[3];
64
65         /* (x, y) position of the current empty position. */
66         uint_least8_t x, y;
67 };
68
69 /* Return the board bitmap with all bits in column x set */
70 static inline uint_fast32_t board_column(int x)
71 {
72         return 0x108421ul << x;
73 }
74
75 /* Return the board bitmap with all bits in row y set */
76 static inline uint_fast32_t board_row(int y)
77 {
78         return 0x1ful << 5*y;
79 }
80
81 /* Return the board bitmap with the bit at position (x, y) set. */
82 static inline uint_fast32_t board_position(int x, int y)
83 {
84         return 1ul << x << 5*y;
85 }
86
87 /*
88  * Return the board bitmap with set bits indicating tile locations
89  * that change with the hole at (x0, y) and the play at (x1, y).
90  */
91 static inline uint_fast32_t board_mask_h(int y, int x0, int x1)
92 {
93         uint_fast32_t row = board_row(y);
94
95         if (x0 < x1)
96                 return (row << x0) & (row >> (4-x1));
97         return (row << x1) & (row >> (4-x0));
98 }
99
100 /*
101  * Return the board bitmap with set bits indicating tile locations
102  * that change with the hole at (x, y0) and the play at (x, y1).
103  */
104 static inline uint_fast32_t board_mask_v(int x, int y0, int y1)
105 {
106         uint_fast32_t col = board_column(x);
107
108         if (y0 < y1)
109                 return (col << 5*y0) & (col >> 5*(4-y1));
110         return (col << 5*y1) & (col >> 5*(4-y0));
111 }
112
113 /*
114  * Move the bits in the game bitmaps according to a move at position (x, y),
115  * and update the location of the empty position which, if the move was valid
116  * is now (x, y).
117  *
118  * Returns 0 if the move was valid (and board has been updated), -1 otherwise.
119  */
120 int game_do_move(struct board *board, int x, int y);
121
122 /*
123  * Returns 1 if the game is in a winning position, or 0 otherwise.
124  */
125 int game_check_goal(struct board *board);
126
127 /*
128  * Initialize the game RNG such that the next call to game_reset will produce a
129  * new board that is entirely dependent on the given seed value.
130  */
131 void game_reseed(unsigned long long seed);
132
133 /*
134  * Shuffle the game and goal tiles to produce a new game state.
135  */
136 void game_reset(struct board *board);
137
138 /*
139  * Disable new moves and clear all tile bits other than the 9 goal tiles.
140  */
141 void game_finish(struct board *board);
142
143 #endif