Index

ncurses-minesweeper / 13c4747

Terminal game of Minesweeper, implemented in C with ncurses.

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
4717 Oct 2021 18:2013c4747Add about page; Update input methods; Add central strings fileJosh Stockin11311G

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

text/plain4131 bytesdownload raw
1/* ncurses-minesweeper Copyright (c) 2021 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 "../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 }
76
77 game(state, ch); // pass input to game controller
78
79 // draw board
80 attron(A_BOLD);
81 for (int cell = 0; cell < board->width * board->height; cell++) {
82 int x = bound_left + cell % board->width * 2;
83 int y = board_top + 1 + cell / board->width;
84 if (board->current_cell == cell) attron(A_STANDOUT); // highlight selected cell
85 game_board_cell *this_cell = &board->cells[cell];
86 if (!this_cell->flagged) {
87 if (!this_cell->opened) { // unopened unflagged, grey territory
88 attroff(A_BOLD);
89 mvaddch(y, x, '~');
90 attron(A_BOLD);
91 } else { // opened but unflagged
92 if (this_cell->is_bomb) { // bomb opened
93 attron(COLOR_PAIR(5));
94 mvaddch(y, x, 'X');
95 attroff(COLOR_PAIR(5));
96 } else if (this_cell->surrounding_bomb_count) { // surrounding bomb-count label
97 int count = this_cell->surrounding_bomb_count;
98 attron(COLOR_PAIR(count));
99 mvaddch(y, x, '0' + count);
100 attroff(COLOR_PAIR(count));
101 } else { // no surrounding bombs, open area
102 mvaddch(y, x, ' ');
103 }
104 }
105 } else { // flagged cell
106 attron(A_STANDOUT);
107 if (board->status != Kaboom)
108 mvaddch(y, x, 'X');
109 else {
110 if (!board->cells[cell].is_bomb) { // highlight false positives when done
111 attron(COLOR_PAIR(5));
112 mvaddch(y, x, 'X');
113 attroff(COLOR_PAIR(5));
114 } else
115 mvaddch(y, x, 'X');
116 }
117 attroff(A_STANDOUT);
118 }
119 if (board->current_cell == cell) attroff(A_STANDOUT); // un-highlight selected cell
120 }
121 attroff(A_BOLD);
122 return 0;
123}
124