Index

ncurses-minesweeper / 14fa750

Terminal game of Minesweeper, implemented in C with ncurses.

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
1913 Sep 2020 14:2371d76abAdd majority of game logic, renderingJosh Stockin18045G

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

text/plain4128 bytesdownload raw
1#include <stdlib.h>
2#include <time.h>
3
4#include <ncurses.h>
5
6#include "../state.h"
7#include "nearest_cells.h"
8
9void new_game(game_board *board) {
10 // create board
11 board->status = Playing;
12 board->mines_left = board->mine_count;
13 if (board->cells) free(board->cells);
14 board->cells = (game_board_cell *)calloc(board->width * board->height, sizeof(game_board_cell));
15 if (board->cells == NULL) abort();
16
17 // open start
18 uint16_t s = board->current_cell;
19
20 int16_t *open_start_cells = list_nearby_cells(board, s);
21
22 for (int cell = 0; cell < 9; cell++) {
23 board->cells[open_start_cells[cell]].opened = 1;
24 board->cells[open_start_cells[cell]].is_bomb = 0;
25 }
26
27 // generate mines
28 int mines_generated = 0;
29 uint16_t end = board->width * board->height;
30
31 srand(time(0));
32
33 while (mines_generated < board->mine_count) {
34 int n = rand() % (end - 1);
35 game_board_cell *x = &board->cells[n];
36 if (!x->is_bomb && !x->opened) {
37 x->is_bomb = 1;
38 mines_generated++;
39 }
40 }
41
42 // get surrounding mine counts
43 for (int i = 0; i < end; i++) {
44 if (board->cells[i].is_bomb) continue;
45 int16_t *close_cells = list_nearby_cells(board, i);
46 for (int j = 0; j < 9; j++) {
47 int16_t close_cell = close_cells[j];
48 if (close_cell != i && board->cells[close_cell].is_bomb) board->cells[i].surrounding_bomb_count++;
49 }
50 free(close_cells);
51 }
52
53 // recursively open start
54 for (int cell = 0; cell < 9; cell++) {
55 if (board->cells[open_start_cells[cell]].surrounding_bomb_count == 0)
56 recursively_open_nearby_cells(board, open_start_cells[cell]);
57 }
58 free(open_start_cells);
59}
60
61void game(game_state *state, int ch) {
62 game_board *board = state->board;
63 if (ch == 0) { // create new game
64 new_game(board);
65 }
66 if (board->status == Kaboom) {
67 beep();
68 return;
69 }
70 if (ch == 'j' || ch == 'J') {
71 if (board->current_cell < board->width * (board->height - 1))
72 board->current_cell += board->width;
73 else
74 beep();
75 } else if (ch == 'k' || ch == 'K') {
76 if (board->current_cell >= board->width)
77 board->current_cell -= board->width;
78 else
79 beep();
80 } else if (ch == 'h' || ch == 'H') {
81 if (board->current_cell % board->width > 0)
82 board->current_cell -= 1;
83 else
84 beep();
85 } else if (ch == 'l' || ch == 'L') {
86 if ((board->current_cell + 1) % board->width > 0)
87 board->current_cell += 1;
88 else
89 beep();
90 } else if (ch == 'f' || ch == 'F') {
91 game_board_cell *cell = &board->cells[board->current_cell];
92 if (!cell->opened) {
93 cell->flagged = !cell->flagged;
94 board->mines_left -= cell->flagged * 2 - 1;
95 }
96 } else if (ch == 10 || ch == ' ') {
97 game_board_cell *cell = &board->cells[board->current_cell];
98 if (!cell->flagged) {
99 if (!cell->opened) {
100 cell->opened = 1;
101 if (cell->is_bomb) {
102 board->status = Kaboom;
103 for (int i = 0; i < board->width * board->height; i++) {
104 if (board->cells[i].is_bomb) { board->cells[i].opened = 1; }
105 }
106 } else if (!cell->surrounding_bomb_count)
107 recursively_open_nearby_cells(board, board->current_cell);
108 } else {
109 int16_t *close_cells = list_nearby_cells(board, board->current_cell);
110 int flag_count = 0;
111 for (int i = 0; i < 9; i++) {
112 int16_t close_cell = close_cells[i];
113 if (close_cell != board->current_cell && board->cells[close_cell].flagged) flag_count++;
114 }
115 free(close_cells);
116 if (flag_count == cell->surrounding_bomb_count) {
117 recursively_open_nearby_cells(board, board->current_cell);
118 }
119 }
120 }
121 }
122}
123