1 | #include <stdlib.h> |
2 | #include <time.h> |
3 |
|
4 | #include <ncurses.h> |
5 |
|
6 | #include "../state.h" |
7 | #include "nearest_cells.h" |
8 |
|
9 | void 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 |
|
61 | void 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 |
|