| 1 | #include <stdlib.h> |
| 2 | #include <time.h> |
| 3 |
|
| 4 | #include "../state.h" |
| 5 |
|
| 6 | int16_t *nearby_cells(uint16_t s, uint8_t w, uint8_t h) { |
| 7 | int16_t *cells = malloc(sizeof(int16_t) * 9); |
| 8 | cells[0] = s - w - 1; |
| 9 | cells[1] = s - w; |
| 10 | cells[2] = s - w + 1; |
| 11 | cells[3] = s - 1; |
| 12 | cells[4] = s; |
| 13 | cells[5] = s + 1; |
| 14 | cells[6] = s + w - 1; |
| 15 | cells[7] = s + w; |
| 16 | cells[8] = s + w + 1; |
| 17 | if (s % w == 0) { // left edge |
| 18 | cells[0] = s; |
| 19 | cells[3] = s; |
| 20 | cells[6] = s; |
| 21 | } |
| 22 | if ((s + 1) % w == 0) { // right edge |
| 23 | cells[2] = s; |
| 24 | cells[5] = s; |
| 25 | cells[8] = s; |
| 26 | } |
| 27 | if (s < w) { // top edge |
| 28 | cells[0] = s; |
| 29 | cells[1] = s; |
| 30 | cells[2] = s; |
| 31 | } |
| 32 | if (s > w * (h - 1)) { // bottom edge |
| 33 | cells[6] = s; |
| 34 | cells[7] = s; |
| 35 | cells[8] = s; |
| 36 | } |
| 37 | return cells; |
| 38 | } |
| 39 |
|
| 40 | void new_game(game_board *board) { |
| 41 | // generate board |
| 42 | board->mines_left = board->mine_count; |
| 43 | board->cells = calloc(board->width * board->height, sizeof(game_board_cell)); |
| 44 |
|
| 45 | // open start |
| 46 | uint16_t s = board->current_cell; |
| 47 |
|
| 48 | int16_t *open_start_cells = nearby_cells(s, board->width, board->height); |
| 49 |
|
| 50 | for (int cell = 0; cell < 9; cell++) { |
| 51 | board->cells[open_start_cells[cell]].is_bomb = 0; |
| 52 | board->cells[open_start_cells[cell]].opened = 1; |
| 53 | } |
| 54 |
|
| 55 | free(open_start_cells); |
| 56 |
|
| 57 | // generate mines |
| 58 | int mines_generated = 0; |
| 59 | uint16_t end = board->width * board->height; |
| 60 |
|
| 61 | srand(time(0)); |
| 62 |
|
| 63 | while (mines_generated < board->mine_count) { |
| 64 | int n = rand() % end; |
| 65 | if (!board->cells[n].is_bomb && !board->cells[n].opened) { |
| 66 | board->cells[n].is_bomb = 1; |
| 67 | mines_generated++; |
| 68 | } |
| 69 | } |
| 70 |
|
| 71 | // get surrounding mine counts |
| 72 | for (int i = 0; i < end; i++) { |
| 73 | if (board->cells[i].is_bomb) continue; |
| 74 | int16_t *close_cells = nearby_cells(i, board->width, board->height); |
| 75 | for (int j = 0; j < 9; j++) { |
| 76 | int16_t close_cell = close_cells[j]; |
| 77 | if (close_cell != i && board->cells[close_cell].is_bomb) board->cells[i].surrounding_bomb_count++; |
| 78 | } |
| 79 | free(close_cells); |
| 80 | } |
| 81 | } |
| 82 |
|
| 83 | void game(game_state *state, int ch) { |
| 84 | if (ch == 0) { // create new game |
| 85 | new_game(state->board); |
| 86 | } |
| 87 | } |
| 88 |
|