Skip to content

Commit

Permalink
Simplify tile storage using bitfields
Browse files Browse the repository at this point in the history
Instead of storing tiles as uint8_t, they are now stored as a
struct minesweeper_tile, which still should only be 8 bits wide,
but each property is addressable without bitmasking.

This is a breaking API change, since some functions that were
previously used to access data encoded in the tiles are no longer
needed. All data can be accessed in the tile directly.
  • Loading branch information
joelekstrom committed Feb 12, 2018
1 parent 93a42e3 commit f84b974
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 114 deletions.
39 changes: 17 additions & 22 deletions include/minesweeper.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@
#include <stdbool.h>
#include <stddef.h>

enum {
TILE_OPENED = 1,
TILE_MINE = 1 << 1,
TILE_FLAG = 1 << 2
};

enum direction {
LEFT,
RIGHT,
Expand All @@ -25,8 +19,15 @@ enum minesweeper_game_state {
MINESWEEPER_GAME_OVER
};

struct minesweeper_tile {
uint8_t adjacent_mine_count : 4;
bool has_flag : 1;
bool has_mine : 1;
bool is_opened : 1;
};

struct minesweeper_game;
typedef void (*minesweeper_callback) (struct minesweeper_game *game, uint8_t *tile, void *user_info);
typedef void (*minesweeper_callback) (struct minesweeper_game *game, struct minesweeper_tile *tile, void *user_info);

/**
* Contains data for a single minesweeper game.
Expand All @@ -42,8 +43,8 @@ struct minesweeper_game {
unsigned mine_count;
unsigned opened_tile_count;
unsigned flag_count;
uint8_t *selected_tile; /* Pointer to the tile under the cursor */
uint8_t *data; /* Tile buffer */
struct minesweeper_tile *selected_tile; /* Pointer to the tile under the cursor */
struct minesweeper_tile *tiles;
enum minesweeper_game_state state;
minesweeper_callback tile_update_callback; /* Optional function pointer to receive tile state updates */
void *user_info; /* Can be used for anything, will be passed as a parameter to tile_update_callback */
Expand Down Expand Up @@ -87,44 +88,38 @@ void minesweeper_move_cursor(struct minesweeper_game *game, enum direction direc
* be opened instead, to imitate the quick-open functionality of most
* minesweeper games.
*/
void minesweeper_open_tile(struct minesweeper_game *game, uint8_t *tile);
void minesweeper_open_tile(struct minesweeper_game *game, struct minesweeper_tile *tile);

/**
* Toggles a flag on an unopened tile.
*/
void minesweeper_toggle_flag(struct minesweeper_game *game, uint8_t *tile);
void minesweeper_toggle_flag(struct minesweeper_game *game, struct minesweeper_tile *tile);

/**
* Get pointer to tile at location. Returns NULL if location if out of bounds.
*/
uint8_t *minesweeper_get_tile_at(struct minesweeper_game *game, unsigned x, unsigned y);
struct minesweeper_tile *minesweeper_get_tile_at(struct minesweeper_game *game, unsigned x, unsigned y);

/**
* Get location of a tile.
*
* x/y: Pointers to integers which the result will be written to.
*/
void minesweeper_get_tile_location(struct minesweeper_game *game, uint8_t *tile, unsigned *x, unsigned *y);
void minesweeper_get_tile_location(struct minesweeper_game *game, struct minesweeper_tile *tile, unsigned *x, unsigned *y);

/**
* Get all tiles adjacent to tile. A tile can have at most 8 adjacent tiles,
* but tiles adjacent to edges of the game area will have fewer.
*
* adjacent_tiles: A pointer to an array of 8 uint8_t pointers. The resulting tiles will
* adjacent_tiles: A pointer to an array of 8 tile pointers. Pointers to the resulting tiles will
* be written to this array. Some tiles may be NULL, if tile is adjacent to an edge.
*/
void minesweeper_get_adjacent_tiles(struct minesweeper_game *game, uint8_t *tile, uint8_t *adjacent_tiles[8]);

/**
* Returns the number of adjacent mines for a tile. This is
* the colored number that is shown on tiles in most minesweepers.
*/
uint8_t minesweeper_get_adjacent_mine_count(uint8_t *tile);
void minesweeper_get_adjacent_tiles(struct minesweeper_game *game, struct minesweeper_tile *tile, struct minesweeper_tile *adjacent_tiles[8]);

/**
* Toggles a mine on a tile, and adjusts the adjacent mine counts for all
* adjacent tiles.
*/
void minesweeper_toggle_mine(struct minesweeper_game *game, uint8_t *tile);
void minesweeper_toggle_mine(struct minesweeper_game *game, struct minesweeper_tile *tile);

#endif
22 changes: 11 additions & 11 deletions include/minesweeper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ namespace Minesweeper {
}

private:
Tile(uint8_t *internal, minesweeper_game *game): internal(internal), game(game) {}
uint8_t *internal;
Tile(minesweeper_tile *internal, minesweeper_game *game): internal(internal), game(game) {}
minesweeper_tile *internal;
minesweeper_game *game;
};

Expand All @@ -55,7 +55,7 @@ namespace Minesweeper {
minesweeper_game *internal;
};

extern "C" void callbackHandler(minesweeper_game *game, uint8_t *tile, void *context) {
extern "C" void callbackHandler(minesweeper_game *game, struct minesweeper_tile *tile, void *context) {
Game *gameObject = (Game *)context;
unsigned x, y; minesweeper_get_tile_location(game, tile, &x, &y);
Tile tileObject = gameObject->tileAt(x, y);
Expand Down Expand Up @@ -106,14 +106,14 @@ namespace Minesweeper {
}

inline Tile Game::selectedTile() {
uint8_t *tilePtr = internal->selected_tile;
minesweeper_tile *tilePtr = internal->selected_tile;
if (tilePtr == NULL)
throw std::logic_error("No tile is selected. Call setCursor() first.");
return Tile(tilePtr, this->internal);
}

inline Tile Game::tileAt(unsigned x, unsigned y) {
uint8_t *tilePtr = minesweeper_get_tile_at(internal, x, y);
minesweeper_tile *tilePtr = minesweeper_get_tile_at(internal, x, y);
if (tilePtr == NULL)
throw std::out_of_range("Tile is out of bounds for this game.");
return Tile(tilePtr, this->internal);
Expand All @@ -128,32 +128,32 @@ namespace Minesweeper {
}

inline uint8_t Tile::adjacentMineCount() {
return minesweeper_get_adjacent_mine_count(internal);
return internal->adjacent_mine_count;
}

inline void Tile::toggleMine() {
minesweeper_toggle_mine(game, internal);
}

inline bool Tile::hasMine() {
return *internal & TILE_MINE;
return internal->has_mine;
}

inline bool Tile::hasFlag() {
return *internal & TILE_FLAG;
return internal->has_flag;
}

inline bool Tile::isOpened() {
return *internal & TILE_OPENED;
return internal->is_opened;
}

inline std::vector<Tile> Tile::adjacentTiles() {
uint8_t *tiles[8];
minesweeper_tile *tiles[8];
minesweeper_get_adjacent_tiles(game, internal, tiles);
std::vector<Tile> list;

for (int i = 0; i < 8; i++) {
uint8_t *tilePtr = tiles[i];
minesweeper_tile *tilePtr = tiles[i];
if (tilePtr != NULL) {
list.push_back(Tile(tilePtr, this->game));
}
Expand Down
Loading

0 comments on commit f84b974

Please sign in to comment.