Skip to content

Commit 6e56eb2

Browse files
authored
Create minesweeper.c
1 parent e5dad3f commit 6e56eb2

File tree

1 file changed

+237
-0
lines changed

1 file changed

+237
-0
lines changed

games/minesweeper.c

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/**
2+
* @file
3+
* @brief Minesweeper Game Implementation in C
4+
* @details This console-based Minesweeper initializes a 9x9 grid, places 10 random mines, calculates adjacent mine counts, and allows players to reveal cells until they hit a mine or clear all safe cells.
5+
*/
6+
7+
#include <stdio.h> ///< Standard I/O library for console input and output functions
8+
#include <stdlib.h> ///< Standard library for functions like malloc, free, rand, srand
9+
#include <time.h> ///< Time library for seeding random number generator with the current time
10+
11+
#define ROWS 9 ///< Number of rows in the board
12+
#define COLS 9 ///< Number of columns in the board
13+
#define MINES 10 ///< Number of mines to place on the board
14+
15+
/**
16+
* @brief Structure representing each cell in the board.
17+
* @param revealed Indicates if the cell is revealed.
18+
* @param isMine Indicates if the cell contains a mine.
19+
* @param flagged Indicates if the cell is flagged by the player.
20+
* @param adjacentMines Stores the count of mines adjacent to the cell.
21+
*/
22+
typedef struct {
23+
int revealed; ///< 1 if revealed, 0 otherwise
24+
int isMine; ///< 1 if it contains a mine, 0 otherwise
25+
int flagged; ///< 1 if flagged, 0 otherwise
26+
int adjacentMines; ///< Count of mines in adjacent cells
27+
} Cell;
28+
29+
Cell board[ROWS][COLS]; ///< The game board
30+
int cellsToReveal = ROWS * COLS - MINES; ///< Number of non-mine cells to be revealed to win
31+
32+
// Function prototypes
33+
void initializeBoard();
34+
void placeMines();
35+
void calculateAdjacentMines();
36+
void printBoard(int revealAll);
37+
void revealCell(int row, int col);
38+
void toggleFlag(int row, int col);
39+
int isInBounds(int row, int col);
40+
void checkWinCondition();
41+
42+
/**
43+
* @brief Main function for Minesweeper.
44+
* @returns 0 on successful game completion
45+
*/
46+
int main() {
47+
int row, col;
48+
char action;
49+
50+
initializeBoard(); ///< Initialize the board and set up mines
51+
printBoard(0); ///< Print the board for player
52+
53+
// Game loop
54+
while (cellsToReveal > 0) {
55+
printf("\nEnter row, column and action (r for reveal, f for flag/unflag, e.g., '2 3 r'): ");
56+
scanf("%d %d %c", &row, &col, &action);
57+
58+
// Validate cell bounds
59+
if (!isInBounds(row, col)) {
60+
printf("Invalid cell. Try again.\n");
61+
continue;
62+
}
63+
64+
if (action == 'r') { // Reveal cell action
65+
if (board[row][col].flagged) {
66+
printf("Cell is flagged. Unflag it first.\n");
67+
continue;
68+
}
69+
revealCell(row, col);
70+
if (board[row][col].isMine) { // If mine, game over
71+
printf("Game Over! You hit a mine.\n");
72+
printBoard(1); // Reveal entire board
73+
return 0;
74+
}
75+
} else if (action == 'f') { // Toggle flag action
76+
toggleFlag(row, col);
77+
} else {
78+
printf("Invalid action. Use 'r' for reveal or 'f' for flag.\n");
79+
continue;
80+
}
81+
82+
printBoard(0); ///< Print updated board state
83+
checkWinCondition(); ///< Check if player has won
84+
}
85+
86+
printf("Congratulations! You've cleared the board.\n");
87+
return 0;
88+
}
89+
90+
/**
91+
* @brief Initializes the board by setting each cell as hidden and empty.
92+
*/
93+
void initializeBoard() {
94+
srand(time(NULL)); // Seed random number generator
95+
96+
// Initialize each cell
97+
for (int i = 0; i < ROWS; i++) {
98+
for (int j = 0; j < COLS; j++) {
99+
board[i][j].revealed = 0;
100+
board[i][j].isMine = 0;
101+
board[i][j].flagged = 0;
102+
board[i][j].adjacentMines = 0;
103+
}
104+
}
105+
106+
placeMines(); ///< Place random mines on the board
107+
calculateAdjacentMines(); ///< Calculate adjacent mine counts for each cell
108+
}
109+
110+
/**
111+
* @brief Randomly places mines on the board.
112+
*/
113+
void placeMines() {
114+
int placedMines = 0;
115+
while (placedMines < MINES) {
116+
int row = rand() % ROWS;
117+
int col = rand() % COLS;
118+
119+
if (!board[row][col].isMine) { // Only place mine if cell is empty
120+
board[row][col].isMine = 1;
121+
placedMines++;
122+
}
123+
}
124+
}
125+
126+
/**
127+
* @brief Calculates the number of adjacent mines for each cell.
128+
*/
129+
void calculateAdjacentMines() {
130+
int directions[8][2] = { // Define 8 possible neighbor positions
131+
{-1, -1}, {-1, 0}, {-1, 1},
132+
{0, -1}, {0, 1},
133+
{1, -1}, {1, 0}, {1, 1}
134+
};
135+
136+
// Iterate over each cell
137+
for (int i = 0; i < ROWS; i++) {
138+
for (int j = 0; j < COLS; j++) {
139+
if (board[i][j].isMine) continue;
140+
141+
int count = 0;
142+
// Check adjacent cells for mines
143+
for (int k = 0; k < 8; k++) {
144+
int newRow = i + directions[k][0];
145+
int newCol = j + directions[k][1];
146+
147+
if (isInBounds(newRow, newCol) && board[newRow][newCol].isMine) {
148+
count++;
149+
}
150+
}
151+
board[i][j].adjacentMines = count;
152+
}
153+
}
154+
}
155+
156+
/**
157+
* @brief Checks if a cell is within the board boundaries.
158+
* @param row Row index
159+
* @param col Column index
160+
* @returns 1 if in bounds, 0 otherwise
161+
*/
162+
int isInBounds(int row, int col) {
163+
return row >= 0 && row < ROWS && col >= 0 && col < COLS;
164+
}
165+
166+
/**
167+
* @brief Prints the board to the console.
168+
* @param revealAll If true, reveals all cells including mines
169+
*/
170+
void printBoard(int revealAll) {
171+
printf(" ");
172+
for (int j = 0; j < COLS; j++) printf("%d ", j);
173+
printf("\n");
174+
175+
for (int i = 0; i < ROWS; i++) {
176+
printf("%d |", i);
177+
for (int j = 0; j < COLS; j++) {
178+
if (revealAll || board[i][j].revealed) {
179+
if (board[i][j].isMine) printf("* ");
180+
else printf("%d ", board[i][j].adjacentMines);
181+
} else if (board[i][j].flagged) {
182+
printf("F ");
183+
} else {
184+
printf(". ");
185+
}
186+
}
187+
printf("|\n");
188+
}
189+
}
190+
191+
/**
192+
* @brief Reveals a cell, recursively revealing neighbors if no adjacent mines.
193+
* @param row Row index
194+
* @param col Column index
195+
*/
196+
void revealCell(int row, int col) {
197+
if (!isInBounds(row, col) || board[row][col].revealed || board[row][col].flagged) return;
198+
199+
board[row][col].revealed = 1;
200+
if (!board[row][col].isMine) cellsToReveal--;
201+
202+
if (board[row][col].adjacentMines == 0 && !board[row][col].isMine) {
203+
int directions[8][2] = {
204+
{-1, -1}, {-1, 0}, {-1, 1},
205+
{0, -1}, {0, 1},
206+
{1, -1}, {1, 0}, {1, 1}
207+
};
208+
209+
for (int k = 0; k < 8; k++) {
210+
int newRow = row + directions[k][0];
211+
int newCol = col + directions[k][1];
212+
revealCell(newRow, newCol);
213+
}
214+
}
215+
}
216+
217+
/**
218+
* @brief Toggles the flag status of a cell.
219+
* @param row Row index
220+
* @param col Column index
221+
*/
222+
void toggleFlag(int row, int col) {
223+
if (!board[row][col].revealed) {
224+
board[row][col].flagged = !board[row][col].flagged;
225+
}
226+
}
227+
228+
/**
229+
* @brief Checks the win condition.
230+
*/
231+
void checkWinCondition() {
232+
if (cellsToReveal == 0) {
233+
printf("Congratulations! You've cleared the board.\n");
234+
printBoard(1);
235+
exit(0);
236+
}
237+
}

0 commit comments

Comments
 (0)