Index

ncurses-minesweeper / a58d838

Terminal game of Minesweeper, implemented in C with ncurses.

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
3530 Sep 2020 15:36cde78e2Use microsecond precision for stopwatch timeJosh Stockin122G

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

text/plain3991 bytesdownload raw
1/* ncurses-minesweeper Copyright (c) 2020 Joshua 'joshuas3' Stockin
2 * <https://joshstock.in>
3 * <https://github.com/JoshuaS3/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 "pages.h"
19#include "text.h"
20
21static int elapsed = 0;
22void render_topbar(int left, int right, game_board *board) {
23 if (board->status == Waiting) {
24 elapsed = 0;
25 } else if (board->status == Playing) {
26 elapsed = 1 + (time_us() - board->time) / 1000000;
27 }
28 attron(A_BOLD);
29 if (elapsed < 999)
30 mvprintw(0, right - 4, "%03d", elapsed);
31 else
32 mvaddstr(0, right - 4, "999");
33 mvprintw(0, left, "%03d", board->mines_left);
34 attroff(A_BOLD);
35 int center = (int)(COLS / 2 - 1);
36 switch (board->status) {
37 case Waiting:
38 case Playing:
39 mvaddstr(0, center, "._.");
40 break;
41 case Done:
42 mvaddstr(0, center, "^-^");
43 break;
44 case Kaboom:
45 mvaddstr(0, center, "x_x");
46 break;
47 }
48}
49
50int draw_game(game_state *state, int ch) {
51 game_board *board = state->board;
52 int bound_left = (int)(COLS / 2) - board->width;
53 int bound_right = (int)(COLS / 2) + board->width;
54 render_topbar(bound_left, bound_right, board);
55
56 // handle input
57 switch (ch) {
58 case -1: {
59 return 0;
60 }
61 case KEY_RESIZE: {
62 clear();
63 break;
64 }
65 case 'q':
66 case 'Q': {
67 clear();
68 reset_board(state->board);
69 state->page = Title;
70 state->page_selection = 0;
71 return draw_title_screen(state, 0);
72 }
73 }
74
75 game(state, ch); // pass input to game controller
76
77 // draw board
78 attron(A_BOLD);
79 for (int cell = 0; cell < board->width * board->height; cell++) {
80 int x = bound_left + cell % board->width * 2;
81 int y = 1 + cell / board->width;
82 if (board->current_cell == cell) attron(A_STANDOUT); // highlight selected cell
83 game_board_cell *this_cell = &board->cells[cell];
84 if (!this_cell->flagged) {
85 if (!this_cell->opened) { // unopened unflagged, grey territory
86 attroff(A_BOLD);
87 mvaddch(y, x, '~');
88 attron(A_BOLD);
89 } else { // opened but unflagged
90 if (this_cell->is_bomb) { // bomb opened
91 attron(COLOR_PAIR(5));
92 mvaddch(y, x, 'X');
93 attroff(COLOR_PAIR(5));
94 } else if (this_cell->surrounding_bomb_count) { // surrounding bomb-count label
95 int count = this_cell->surrounding_bomb_count;
96 attron(COLOR_PAIR(count));
97 mvaddch(y, x, '0' + count);
98 attroff(COLOR_PAIR(count));
99 } else { // no surrounding bombs, open area
100 mvaddch(y, x, ' ');
101 }
102 }
103 } else { // flagged cell
104 attron(A_STANDOUT);
105 if (board->status != Kaboom)
106 mvaddch(y, x, 'X');
107 else {
108 if (!board->cells[cell].is_bomb) { // highlight false positives when done
109 attron(COLOR_PAIR(5));
110 mvaddch(y, x, 'X');
111 attroff(COLOR_PAIR(5));
112 } else
113 mvaddch(y, x, 'X');
114 }
115 attroff(A_STANDOUT);
116 }
117 if (board->current_cell == cell) attroff(A_STANDOUT); // un-highlight selected cell
118 }
119 attroff(A_BOLD);
120 return 0;
121}
122