Index

ncurses-minesweeper / 34925b1

Terminal game of Minesweeper, implemented in C with ncurses.

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
2417 Sep 2020 22:4163b24cbFix copyright disclaimerJosh Stockin111G

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

text/plain3961 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#include <time.h>
14
15#include "../game/game.h"
16#include "../game/reset.h"
17#include "../state.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 = time(NULL) - board->time;
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 case 'q':
65 case 'Q': {
66 clear();
67 reset_board(state->board);
68 state->page = Title;
69 state->page_selection = 0;
70 return draw_title_screen(state, 0);
71 }
72 }
73
74 game(state, ch); // pass input to game controller
75
76 // draw board
77 attron(A_BOLD);
78 for (int cell = 0; cell < board->width * board->height; cell++) {
79 int x = bound_left + cell % board->width * 2;
80 int y = 1 + cell / board->width;
81 if (board->current_cell == cell) attron(A_STANDOUT); // highlight selected cell
82 game_board_cell *this_cell = &board->cells[cell];
83 if (!this_cell->flagged) {
84 if (!this_cell->opened) { // unopened unflagged, grey territory
85 attroff(A_BOLD);
86 mvaddch(y, x, '~');
87 attron(A_BOLD);
88 } else { // opened but unflagged
89 if (this_cell->is_bomb) { // bomb opened
90 attron(COLOR_PAIR(5));
91 mvaddch(y, x, 'X');
92 attroff(COLOR_PAIR(5));
93 } else if (this_cell->surrounding_bomb_count) { // surrounding bomb-count label
94 int count = this_cell->surrounding_bomb_count;
95 attron(COLOR_PAIR(count));
96 mvaddch(y, x, '0' + count);
97 attroff(COLOR_PAIR(count));
98 } else { // no surrounding bombs, open area
99 mvaddch(y, x, ' ');
100 }
101 }
102 } else { // flagged cell
103 attron(A_STANDOUT);
104 if (board->status != Kaboom)
105 mvaddch(y, x, 'X');
106 else {
107 if (!board->cells[cell].is_bomb) { // highlight false positives when done
108 attron(COLOR_PAIR(5));
109 mvaddch(y, x, 'X');
110 attroff(COLOR_PAIR(5));
111 } else
112 mvaddch(y, x, 'X');
113 }
114 attroff(A_STANDOUT);
115 }
116 if (board->current_cell == cell) attroff(A_STANDOUT); // un-highlight selected cell
117 }
118 attroff(A_BOLD);
119 return 0;
120}
121