/* * 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 . */ #ifndef RRACE_GAME_H_ #define RRACE_GAME_H_ #include enum { TILE_EMPTY, TILE_RED, TILE_ORANGE, TILE_YELLOW, TILE_GREEN, TILE_BLUE, TILE_WHITE, TILE_MAX }; enum { GOAL_SHIFT = 6 }; struct board { /* * Bit planes representing the current game area. * * The 5x5 game board is represented by these four 25-bit values. * The bits are arranged in row-major order so, for example, bit 0 * corresponds to position (0,0), bit 4 is position (4,0) and bit 25 * is position (4, 4). * * 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. */ uint_least32_t game[4]; /* * Bit planes representing the goal area. * * These are encoded identically to the game area, except the values * are shifted right by 6 as only bits 6 through 18 are relevant. * * goal[0] - least significant bit of the tile's colour. * goal[2] - tile colour. * goal[3] - most significant bit of the tile's colour. */ uint_least16_t goal[3]; /* (x, y) position of the current empty position. */ uint_least8_t x, y; }; /* Return the board bitmap with all bits in column x set */ static inline uint_fast32_t board_column(int x) { return 0x108421ul << x; } /* Return the board bitmap with all bits in row y set */ static inline uint_fast32_t board_row(int y) { return 0x1ful << 5*y; } /* Return the board bitmap with the bit at position (x, y) set. */ static inline uint_fast32_t board_position(int x, int y) { return 1ul << x << 5*y; } /* * Return the board bitmap with set bits indicating tile locations * that change with the hole at (x0, y) and the play at (x1, y). */ static inline uint_fast32_t board_mask_h(int y, int x0, int x1) { uint_fast32_t row = board_row(y); if (x0 < x1) return (row << x0) & (row >> (4-x1)); return (row << x1) & (row >> (4-x0)); } /* * Return the board bitmap with set bits indicating tile locations * that change with the hole at (x, y0) and the play at (x, y1). */ static inline uint_fast32_t board_mask_v(int x, int y0, int y1) { uint_fast32_t col = board_column(x); if (y0 < y1) return (col << 5*y0) & (col >> 5*(4-y1)); return (col << 5*y1) & (col >> 5*(4-y0)); } /* * 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. */ 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. */ void game_reseed(unsigned long long seed); /* * Shuffle the game and goal tiles to produce a new game state. */ 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