Index

ncurses-minesweeper / 5abfbc6

Terminal game of Minesweeper, implemented in C with ncurses.

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
4918 Oct 2021 15:555abfbc6Add functionality to enter help screen during gameJosh Stockin1100G

Blob @ ncurses-minesweeper / src / draw / game.c

text/plain4396 bytesdownload raw
1/* ncurses-minesweeper Copyright (c) 2021 Joshua 'joshuas3' Stockin
2 * <https://joshstock.in>
3 * <https://git.joshstock.in/ncurses-minesweeper>
4 *
5 * This software is licensed and distributed under the terms of the MIT License.
6 * See the MIT License in the LICENSE file of this project's root folder.
7 *
8 * This comment block and its contents, including this disclaimer, MUST be
9 * preserved in all copies or distributions of this software's source.
10 */
11
12#include <ncurses.h>
13
14#include "../game/game.h"
15#include "../game/reset.h"
16#include "../state.h"
17#include "../time.h"
18#include "../strings.h"
19#include "pages.h"
20#include "text.h"
21
22static int elapsed = 0;
23void render_topbar(int top, int left, int right, game_board *board) {
24 if (board->status == Waiting) {
25 elapsed = 0;
26 } else if (board->status == Playing) {
27 elapsed = 1 + (time_us() - board->time) / 1000000;
28 }
29 attron(A_BOLD);
30 if (elapsed < 999)
31 mvprintw(top, right - 4, "%03d", elapsed);
32 else
33 mvaddstr(top, right - 4, "999");
34 mvprintw(top, left, "%03d", board->mines_left);
35 attroff(A_BOLD);
36 int center = (int)(COLS / 2 - 1);
37 switch (board->status) {
38 case Waiting:
39 case Playing:
40 mvaddstr(top, center, "._.");
41 break;
42 case Done:
43 mvaddstr(top, center, "^-^");
44 break;
45 case Kaboom:
46 mvaddstr(top, center, "x_x");
47 break;
48 }
49}
50
51int draw_game(game_state *state, int ch) {
52 game_board *board = state->board;
53 int board_top = centery() - board->height/2 - 1;
54 if (board_top < 0) board_top = 0;
55 int bound_left = (int)(COLS / 2) - board->width;
56 int bound_right = (int)(COLS / 2) + board->width;
57 render_topbar(board_top, bound_left, bound_right, board);
58
59 // handle input
60 switch (ch) {
61 case -1: {
62 return 0;
63 }
64 case KEY_RESIZE: {
65 clear();
66 break;
67 }
68 case 27: {
69 clear();
70 reset_board(state->board);
71 state->page = Title;
72 state->page_selection = 0;
73 return draw_title_screen(state, 0);
74 }
75 case '?': {
76 clear();
77 state->page = Help;
78 state->last_page = Game;
79 return draw_help_screen(state, 0);
80 }
81 }
82
83 game(state, ch); // pass input to game controller
84
85 // draw board
86 attron(A_BOLD);
87 for (int cell = 0; cell < board->width * board->height; cell++) {
88 int x = bound_left + cell % board->width * 2;
89 int y = board_top + 1 + cell / board->width;
90 if (board->current_cell == cell) attron(A_STANDOUT); // highlight selected cell
91 game_board_cell *this_cell = &board->cells[cell];
92 if (!this_cell->flagged) {
93 if (!this_cell->opened) { // unopened unflagged, grey territory
94 attroff(A_BOLD);
95 mvaddch(y, x, '~');
96 attron(A_BOLD);
97 } else { // opened but unflagged
98 if (this_cell->is_bomb) { // bomb opened
99 attron(COLOR_PAIR(5));
100 mvaddch(y, x, 'X');
101 attroff(COLOR_PAIR(5));
102 } else if (this_cell->surrounding_bomb_count) { // surrounding bomb-count label
103 int count = this_cell->surrounding_bomb_count;
104 attron(COLOR_PAIR(count));
105 mvaddch(y, x, '0' + count);
106 attroff(COLOR_PAIR(count));
107 } else { // no surrounding bombs, open area
108 mvaddch(y, x, ' ');
109 }
110 }
111 } else { // flagged cell
112 attron(A_STANDOUT);
113 if (board->status != Kaboom)
114 mvaddch(y, x, 'X');
115 else {
116 if (!board->cells[cell].is_bomb) { // highlight false positives when done
117 attron(COLOR_PAIR(5));
118 mvaddch(y, x, 'X');
119 attroff(COLOR_PAIR(5));
120 } else
121 mvaddch(y, x, 'X');
122 }
123 attroff(A_STANDOUT);
124 }
125 if (board->current_cell == cell) attroff(A_STANDOUT); // un-highlight selected cell
126 }
127 attroff(A_BOLD);
128
129 // write help note at bottom
130 mvprintw(LINES - 1, centerx(game_help_note), game_help_note);
131
132 return 0;
133}
134