Implement the overlay goal view and make the game stop when the
the puzzle is solved.
WINDOW *gamewin[WINDOW_MAX], *goalwin[WINDOW_MAX];
WINDOW *timer;
WINDOW *gamewin[WINDOW_MAX], *goalwin[WINDOW_MAX];
WINDOW *timer;
+
+ /* Most recently displayed timer value, for screen redraw. */
+ uint_least32_t timer_ms;
+
+ /* Location of the keyboard cursor */
+ int_least8_t cursor;
+
+ /* If true, the goal will be displayed over the main play area. */
+ uint_least8_t view_goal_on_game;
+
+ /* Clicked toolbar item */
+ uint_least8_t toolbar_click;
} state;
static void print_version(void)
} state;
static void print_version(void)
static void curs_redraw_game(struct app_state *state, uint_fast32_t mask)
{
static void curs_redraw_game(struct app_state *state, uint_fast32_t mask)
{
- uint_least32_t *gp = state->board.game;
+ uint_least32_t buf[3], *gp = state->board.game;
int i;
if (mask == -1)
redraw_area_border(state->gamewin, 2, 5);
int i;
if (mask == -1)
redraw_area_border(state->gamewin, 2, 5);
+ if (state->view_goal_on_game) {
+ for (i = 0; i < 3; i++) {
+ buf[i] = state->board.goal[i];
+ buf[i] = (gp[i] & ~GOAL_MASK) | (buf[i] << GOAL_SHIFT);
+ }
+ gp = buf;
+ }
+
for (i = 0; i < 25; i++) {
if (mask & 1) {
redraw_tile(state->gamewin, i%5, i/5,
for (i = 0; i < 25; i++) {
if (mask & 1) {
redraw_tile(state->gamewin, i%5, i/5,
+static void update_timer(struct app_state *state, uint_fast32_t ms)
+{
+ unsigned sec, min;
+
+ state->timer_ms = ms;
+ sec = ms / 1000; ms %= 1000;
+ min = sec / 60; sec %= 60;
+ mvwprintw(state->timer, 0, 0, "Time: %u:%.2u.%.3u",
+ min, sec, (unsigned)ms);
+ wclrtoeol(state->timer);
+ wrefresh(state->timer);
+}
+
static uint_fast32_t do_move(struct app_state *state, int x, int y)
{
uint_fast32_t mask;
if ((mask = game_do_move(&state->board, x, y)) != 0) {
static uint_fast32_t do_move(struct app_state *state, int x, int y)
{
uint_fast32_t mask;
if ((mask = game_do_move(&state->board, x, y)) != 0) {
+ uint_fast32_t goal = game_check_goal(&state->board);
+
+ if (state->view_goal_on_game) {
+ state->view_goal_on_game = 0;
+ mask |= goal;
+ }
+
+ if (goal == 0) {
+ /* Solved! */
+ update_timer(state, game_finish(&state->board));
+ mask |= ~GOAL_MASK;
+ state->cursor = -1;
+ timeout(-1);
+ }
+
curs_redraw_game(state, mask);
doupdate();
}
curs_redraw_game(state, mask);
doupdate();
}
state->cursor = 5*state->board.y + state->board.x;
}
state->cursor = 5*state->board.y + state->board.x;
}
-static void update_timer(struct app_state *state, uint_fast32_t ms)
-{
- unsigned sec, min;
-
- sec = ms / 1000; ms %= 1000;
- min = sec / 60; sec %= 60;
- mvwprintw(state->timer, 0, 0, "Time: %u:%.2u.%.3u",
- min, sec, (unsigned)ms);
- wclrtoeol(state->timer);
- wrefresh(state->timer);
-}
-
static void do_new_game(struct app_state *state)
{
game_reset(&state->board);
static void do_new_game(struct app_state *state)
{
game_reset(&state->board);
set_bstate_helper(1);
set_bstate_helper(3);
#endif
set_bstate_helper(1);
set_bstate_helper(3);
#endif
- if (bstate == BUTTON1_PRESSED) {
+ if (bstate & BUTTON3_PRESSED) {
+ state->view_goal_on_game = 1;
+ curs_redraw_game(state, game_check_goal(&state->board));
+ doupdate();
+ }
+
+ if (bstate & BUTTON3_RELEASED) {
+ state->view_goal_on_game = 0;
+ curs_redraw_game(state, game_check_goal(&state->board));
+ doupdate();
+ }
+
+ if (!state->view_goal_on_game && bstate & BUTTON1_PRESSED) {
uint_fast32_t cursor_mask, move_mask;
int w, h;
uint_fast32_t cursor_mask, move_mask;
int w, h;
static void do_move_cursor(struct app_state *state, int c)
{
static void do_move_cursor(struct app_state *state, int c)
{
- uint_fast32_t mask = 1ul << state->cursor;
+ uint_fast32_t mask = 0;
if (state->cursor < 0) {
/* Cursor was hidden; reset it */
do_reset_cursor(state);
if (state->cursor < 0) {
/* Cursor was hidden; reset it */
do_reset_cursor(state);
+ } else {
+ mask = 1ul << state->cursor;
+ }
+
+ if (state->view_goal_on_game) {
+ state->view_goal_on_game = 0;
+ mask |= game_check_goal(&state->board);
}
curs_redraw_game(state, mask | 1ul << state->cursor);
}
curs_redraw_game(state, mask | 1ul << state->cursor);
}
static void do_keystroke(struct app_state *state, int c)
}
static void do_keystroke(struct app_state *state, int c)
case KEY_DOWN: case KEY_UP: case KEY_LEFT: case KEY_RIGHT:
do_move_cursor(state, c);
break;
case KEY_DOWN: case KEY_UP: case KEY_LEFT: case KEY_RIGHT:
do_move_cursor(state, c);
break;
+ case '\t':
+ state->view_goal_on_game ^= 2u;
+ curs_redraw_game(state, game_check_goal(&state->board));
+ doupdate();
+ break;
- if (state->cursor >= 0)
+ if (!(state->view_goal_on_game & 1) && state->cursor >= 0)
do_move(state, state->cursor%5, state->cursor/5);
break;
}
do_move(state, state->cursor%5, state->cursor/5);
break;
}
refresh();
curs_redraw_game(&state, -1);
curs_redraw_goal(&state, -1);
refresh();
curs_redraw_game(&state, -1);
curs_redraw_goal(&state, -1);
+ update_timer(&state, state.timer_ms);
break;
#endif
#if HAVE_CURSES_MOUSE_SUPPORT
break;
#endif
#if HAVE_CURSES_MOUSE_SUPPORT
- update_timer(&state, game_elapsed(&state.board));
+ if (state.board.x <= 4)
+ update_timer(&state, game_elapsed(&state.board));