From: Nick Bowler Date: Sat, 5 Mar 2022 07:58:34 +0000 (-0500) Subject: Check victory condition so the game is winnable. X-Git-Url: http://git.draconx.ca/gitweb/rrace.git/commitdiff_plain/a3f2189bfac7e5b1acdf3640cd3b50a7a6636906 Check victory condition so the game is winnable. --- diff --git a/src/game.c b/src/game.c index bd1fef9..ca03830 100644 --- a/src/game.c +++ b/src/game.c @@ -1,8 +1,25 @@ /* + * 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 . + * * The RNG implementation is adapted from xoshiro256** and splitmix64 * by David Blackman and Sebastiano Vigna, originally distributed under * the Creative Commons Zero public domain dedication. */ + #include #include #include @@ -136,17 +153,17 @@ void game_reset(struct board *board) uint_fast32_t position; position = board_position(x, y); - if (tiles[i] == TILE_EMPTY) { - board->game[0] = 0x1ffffff ^ position; - board->x = x; - board->y = y; - } else { + if (tiles[i] != TILE_EMPTY) { if (tiles[i] & 1) - board->game[1] |= position; + board->game[0] |= position; if (tiles[i] & 2) - board->game[2] |= position; + board->game[1] |= position; if (tiles[i] & 4) - board->game[3] |= position; + board->game[2] |= position; + } else { + board->game[3] = 0x1ffffff ^ position; + board->x = x; + board->y = y; } } } @@ -179,3 +196,29 @@ int game_do_move(struct board *board, int x, int y) board->y = y; return 0; } + +#define GOAL_MASK 0x739c0 + +int game_check_goal(struct board *board) +{ + int i, ret = 1; + + for (i = 0; i < 3; i++) + ret &= ((board->game[i] & GOAL_MASK) >> 6) == board->goal[i]; + return ret; +} + +void game_finish(struct board *board) +{ + int i; + + for (i = 0; i < 4; i++) { + board->game[i] &= GOAL_MASK; + } + + /* + * Setting both x and y hole location to a bogus value will effectively + * disable the game since there will be no valid moves. + */ + board->x = board->y = -1; +} diff --git a/src/game.h b/src/game.h index f4473a7..d17eb99 100644 --- a/src/game.h +++ b/src/game.h @@ -42,11 +42,11 @@ 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 + * 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. - * game[1] - least significant bit of the tile's colour. - * game[2] - tile colour. - * game[3] - most significant bit of the tile's colour. */ uint_least32_t game[4]; @@ -119,6 +119,11 @@ static inline uint_fast32_t board_mask_v(int x, int y0, int y1) */ 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. @@ -130,4 +135,9 @@ void game_reseed(unsigned long long seed); */ 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 diff --git a/src/motif_ui.c b/src/motif_ui.c index 40f4632..279f550 100644 --- a/src/motif_ui.c +++ b/src/motif_ui.c @@ -239,6 +239,11 @@ static void game_input(Widget w, void *data, void *cb_data) return; if (game_do_move(&state->board, x, y) == 0) { + if (game_check_goal(&state->board)) { + printf("You win!\n"); + game_finish(&state->board); + } + x11_redraw_game(state); } } diff --git a/src/x11.c b/src/x11.c index 9ded09e..598b115 100644 --- a/src/x11.c +++ b/src/x11.c @@ -143,7 +143,7 @@ void x11_redraw_game(struct app_state *state) w /= 5; h /= 5; for (i = 0; i < 25; i++) { - uint_least32_t *gp = state->board.game+1; + uint_least32_t *gp = state->board.game; redraw_tile(state, display, game, gp[0], gp[1], gp[2],