]> git.draconx.ca Git - rrace.git/blob - src/game.h
6a02a428551db68e5cee0c4909901ccc95737c84
[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 #define GOAL_SHIFT 6
36 #define GOAL_MASK 0x739c0ul
37
38 struct board {
39         /*
40          * Bit planes representing the current game area.
41          *
42          * The 5x5 game board is represented by these four 25-bit values.
43          * The bits are arranged in row-major order so, for example, bit 0
44          * corresponds to position (0,0), bit 4 is position (4,0) and bit 25
45          * is position (4, 4).
46          *
47          *   game[0] - least significant bit of the tile's colour.
48          *   game[1] - tile colour.
49          *   game[2] - most significant bit of the tile's colour.
50          *   game[3] - No internal meaning.  The game_reset function will clear
51          *             the bit at the empty position and set all others, and
52          *             game_do_move will adjust it.
53          */
54         uint_least32_t game[4];
55
56         /*
57          * Bit planes representing the goal area.
58          *
59          * These are encoded identically to the game area, except the values
60          * are shifted right by 6 as only bits 6 through 18 are relevant.
61          *
62          *   goal[0] - least significant bit of the tile's colour.
63          *   goal[2] - tile colour.
64          *   goal[3] - most significant bit of the tile's colour.
65          */
66         uint_least16_t goal[3];
67
68         /* (x, y) position of the current empty position. */
69         uint_least8_t x, y;
70 };
71
72 /* Return the board bitmap with all bits in column x set */
73 static inline uint_fast32_t board_column(int x)
74 {
75         return 0x108421ul << x;
76 }
77
78 /* Return the board bitmap with all bits in row y set */
79 static inline uint_fast32_t board_row(int y)
80 {
81         return 0x1ful << 5*y;
82 }
83
84 /* Return the board bitmap with the bit at position (x, y) set. */
85 static inline uint_fast32_t board_position(int x, int y)
86 {
87         return 1ul << x << 5*y;
88 }
89
90 /*
91  * Return the board bitmap with set bits indicating tile locations
92  * that change with the hole at (x0, y) and the play at (x1, y).
93  */
94 static inline uint_fast32_t board_mask_h(int y, int x0, int x1)
95 {
96         uint_fast32_t row = board_row(y);
97
98         if (x0 < x1)
99                 return (row << x0) & (row >> (4-x1));
100         return (row << x1) & (row >> (4-x0));
101 }
102
103 /*
104  * Return the board bitmap with set bits indicating tile locations
105  * that change with the hole at (x, y0) and the play at (x, y1).
106  */
107 static inline uint_fast32_t board_mask_v(int x, int y0, int y1)
108 {
109         uint_fast32_t col = board_column(x);
110
111         if (y0 < y1)
112                 return (col << 5*y0) & (col >> 5*(4-y1));
113         return (col << 5*y1) & (col >> 5*(4-y0));
114 }
115
116 /*
117  * Return the board bitmap setting locations on or above row y.
118  */
119 static inline uint_fast32_t board_above(int y)
120 {
121         uint_fast32_t val = board_row(y);
122
123         return val | (val-1);
124 }
125
126 /*
127  * Return the board bitmap setting locations on or below row y.
128  */
129 static inline uint_fast32_t board_below(int y)
130 {
131         uint_fast32_t val = board_row(y);
132
133         return val | (~val + 1);
134 }
135
136 /*
137  * Return the board bitmap setting locations on or left of column x.
138  */
139 static inline uint_fast32_t board_left(int x)
140 {
141         uint_fast32_t val = board_column(x);
142
143         return val | (val - 0x108421);
144 }
145
146 /*
147  * Return the board bitmap setting locations on or right of column x.
148  */
149 static inline uint_fast32_t board_right(int x)
150 {
151         uint_fast32_t val = board_column(x);
152
153         return ~val + 0x108421;
154 }
155
156 /*
157  * Move the bits in the game bitmaps according to a move at position (x, y),
158  * and update the location of the empty position which, if the move was valid
159  * is now (x, y).
160  *
161  * Returns 0 if the move was valid (and board has been updated), -1 otherwise.
162  */
163 int game_do_move(struct board *board, int x, int y);
164
165 /*
166  * Returns 1 if the game is in a winning position, or 0 otherwise.
167  */
168 int game_check_goal(struct board *board);
169
170 /*
171  * Initialize the game RNG such that the next call to game_reset will produce a
172  * new board that is entirely dependent on the given seed value.
173  */
174 void game_reseed(unsigned long long seed);
175
176 /*
177  * Shuffle the game and goal tiles to produce a new game state.
178  */
179 void game_reset(struct board *board);
180
181 /*
182  * Disable new moves and clear all tile bits other than the 9 goal tiles.
183  */
184 void game_finish(struct board *board);
185
186 #endif