]> git.draconx.ca Git - rrace.git/commitdiff
curses: Make the game winnable.
authorNick Bowler <nbowler@draconx.ca>
Sun, 12 Jun 2022 02:02:44 +0000 (22:02 -0400)
committerNick Bowler <nbowler@draconx.ca>
Sun, 12 Jun 2022 15:56:26 +0000 (11:56 -0400)
Implement the overlay goal view and make the game stop when the
the puzzle is solved.

src/curses.c

index 6d86101c41f354236ce6f82fe3a694916613ae84..06ec3519c87e530bcaa4837c7ff7276c882bab47 100644 (file)
@@ -50,7 +50,18 @@ static struct app_state {
 
        WINDOW *gamewin[WINDOW_MAX], *goalwin[WINDOW_MAX];
        WINDOW *timer;
-       int cursor;
+
+       /* 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)
@@ -171,12 +182,20 @@ static void redraw_area_border(WINDOW **win, unsigned x, unsigned sz)
 
 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);
 
+       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,
@@ -379,11 +398,39 @@ static void app_initialize(int argc, char **argv)
        refresh();
 }
 
+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) {
+               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();
        }
@@ -396,18 +443,6 @@ static void do_reset_cursor(struct app_state *state)
        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);
@@ -453,7 +488,19 @@ static void do_mouse(struct app_state *state)
        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;
 
@@ -479,11 +526,18 @@ static void do_mouse(struct app_state *state)
 
 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);
+       } else {
+               mask = 1ul << state->cursor;
+       }
+
+       if (state->view_goal_on_game) {
+               state->view_goal_on_game = 0;
+               mask |= game_check_goal(&state->board);
        }
 
        switch (c) {
@@ -506,7 +560,7 @@ static void do_move_cursor(struct app_state *state, int c)
        }
 
        curs_redraw_game(state, mask | 1ul << state->cursor);
-       refresh();
+       doupdate();
 }
 
 static void do_keystroke(struct app_state *state, int c)
@@ -515,8 +569,13 @@ 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 '\t':
+               state->view_goal_on_game ^= 2u;
+               curs_redraw_game(state, game_check_goal(&state->board));
+               doupdate();
+               break;
        case ' ':
-               if (state->cursor >= 0)
+               if (!(state->view_goal_on_game & 1) && state->cursor >= 0)
                        do_move(state, state->cursor%5, state->cursor/5);
                break;
        }
@@ -540,7 +599,7 @@ int main(int argc, char **argv)
                        refresh();
                        curs_redraw_game(&state, -1);
                        curs_redraw_goal(&state, -1);
-                       refresh();
+                       update_timer(&state, state.timer_ms);
                        break;
 #endif
 #if HAVE_CURSES_MOUSE_SUPPORT
@@ -553,6 +612,7 @@ int main(int argc, char **argv)
                case ERR:;
                }
 
-               update_timer(&state, game_elapsed(&state.board));
+               if (state.board.x <= 4)
+                       update_timer(&state, game_elapsed(&state.board));
        }
 }