mirror of
https://github.com/TheAlgorithms/C
synced 2024-11-24 14:29:42 +03:00
Create minesweeper.c
This commit is contained in:
parent
e5dad3fa8d
commit
6e56eb2bae
237
games/minesweeper.c
Normal file
237
games/minesweeper.c
Normal file
@ -0,0 +1,237 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Minesweeper Game Implementation in C
|
||||
* @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.
|
||||
*/
|
||||
|
||||
#include <stdio.h> ///< Standard I/O library for console input and output functions
|
||||
#include <stdlib.h> ///< Standard library for functions like malloc, free, rand, srand
|
||||
#include <time.h> ///< Time library for seeding random number generator with the current time
|
||||
|
||||
#define ROWS 9 ///< Number of rows in the board
|
||||
#define COLS 9 ///< Number of columns in the board
|
||||
#define MINES 10 ///< Number of mines to place on the board
|
||||
|
||||
/**
|
||||
* @brief Structure representing each cell in the board.
|
||||
* @param revealed Indicates if the cell is revealed.
|
||||
* @param isMine Indicates if the cell contains a mine.
|
||||
* @param flagged Indicates if the cell is flagged by the player.
|
||||
* @param adjacentMines Stores the count of mines adjacent to the cell.
|
||||
*/
|
||||
typedef struct {
|
||||
int revealed; ///< 1 if revealed, 0 otherwise
|
||||
int isMine; ///< 1 if it contains a mine, 0 otherwise
|
||||
int flagged; ///< 1 if flagged, 0 otherwise
|
||||
int adjacentMines; ///< Count of mines in adjacent cells
|
||||
} Cell;
|
||||
|
||||
Cell board[ROWS][COLS]; ///< The game board
|
||||
int cellsToReveal = ROWS * COLS - MINES; ///< Number of non-mine cells to be revealed to win
|
||||
|
||||
// Function prototypes
|
||||
void initializeBoard();
|
||||
void placeMines();
|
||||
void calculateAdjacentMines();
|
||||
void printBoard(int revealAll);
|
||||
void revealCell(int row, int col);
|
||||
void toggleFlag(int row, int col);
|
||||
int isInBounds(int row, int col);
|
||||
void checkWinCondition();
|
||||
|
||||
/**
|
||||
* @brief Main function for Minesweeper.
|
||||
* @returns 0 on successful game completion
|
||||
*/
|
||||
int main() {
|
||||
int row, col;
|
||||
char action;
|
||||
|
||||
initializeBoard(); ///< Initialize the board and set up mines
|
||||
printBoard(0); ///< Print the board for player
|
||||
|
||||
// Game loop
|
||||
while (cellsToReveal > 0) {
|
||||
printf("\nEnter row, column and action (r for reveal, f for flag/unflag, e.g., '2 3 r'): ");
|
||||
scanf("%d %d %c", &row, &col, &action);
|
||||
|
||||
// Validate cell bounds
|
||||
if (!isInBounds(row, col)) {
|
||||
printf("Invalid cell. Try again.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (action == 'r') { // Reveal cell action
|
||||
if (board[row][col].flagged) {
|
||||
printf("Cell is flagged. Unflag it first.\n");
|
||||
continue;
|
||||
}
|
||||
revealCell(row, col);
|
||||
if (board[row][col].isMine) { // If mine, game over
|
||||
printf("Game Over! You hit a mine.\n");
|
||||
printBoard(1); // Reveal entire board
|
||||
return 0;
|
||||
}
|
||||
} else if (action == 'f') { // Toggle flag action
|
||||
toggleFlag(row, col);
|
||||
} else {
|
||||
printf("Invalid action. Use 'r' for reveal or 'f' for flag.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
printBoard(0); ///< Print updated board state
|
||||
checkWinCondition(); ///< Check if player has won
|
||||
}
|
||||
|
||||
printf("Congratulations! You've cleared the board.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the board by setting each cell as hidden and empty.
|
||||
*/
|
||||
void initializeBoard() {
|
||||
srand(time(NULL)); // Seed random number generator
|
||||
|
||||
// Initialize each cell
|
||||
for (int i = 0; i < ROWS; i++) {
|
||||
for (int j = 0; j < COLS; j++) {
|
||||
board[i][j].revealed = 0;
|
||||
board[i][j].isMine = 0;
|
||||
board[i][j].flagged = 0;
|
||||
board[i][j].adjacentMines = 0;
|
||||
}
|
||||
}
|
||||
|
||||
placeMines(); ///< Place random mines on the board
|
||||
calculateAdjacentMines(); ///< Calculate adjacent mine counts for each cell
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Randomly places mines on the board.
|
||||
*/
|
||||
void placeMines() {
|
||||
int placedMines = 0;
|
||||
while (placedMines < MINES) {
|
||||
int row = rand() % ROWS;
|
||||
int col = rand() % COLS;
|
||||
|
||||
if (!board[row][col].isMine) { // Only place mine if cell is empty
|
||||
board[row][col].isMine = 1;
|
||||
placedMines++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates the number of adjacent mines for each cell.
|
||||
*/
|
||||
void calculateAdjacentMines() {
|
||||
int directions[8][2] = { // Define 8 possible neighbor positions
|
||||
{-1, -1}, {-1, 0}, {-1, 1},
|
||||
{0, -1}, {0, 1},
|
||||
{1, -1}, {1, 0}, {1, 1}
|
||||
};
|
||||
|
||||
// Iterate over each cell
|
||||
for (int i = 0; i < ROWS; i++) {
|
||||
for (int j = 0; j < COLS; j++) {
|
||||
if (board[i][j].isMine) continue;
|
||||
|
||||
int count = 0;
|
||||
// Check adjacent cells for mines
|
||||
for (int k = 0; k < 8; k++) {
|
||||
int newRow = i + directions[k][0];
|
||||
int newCol = j + directions[k][1];
|
||||
|
||||
if (isInBounds(newRow, newCol) && board[newRow][newCol].isMine) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
board[i][j].adjacentMines = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a cell is within the board boundaries.
|
||||
* @param row Row index
|
||||
* @param col Column index
|
||||
* @returns 1 if in bounds, 0 otherwise
|
||||
*/
|
||||
int isInBounds(int row, int col) {
|
||||
return row >= 0 && row < ROWS && col >= 0 && col < COLS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prints the board to the console.
|
||||
* @param revealAll If true, reveals all cells including mines
|
||||
*/
|
||||
void printBoard(int revealAll) {
|
||||
printf(" ");
|
||||
for (int j = 0; j < COLS; j++) printf("%d ", j);
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < ROWS; i++) {
|
||||
printf("%d |", i);
|
||||
for (int j = 0; j < COLS; j++) {
|
||||
if (revealAll || board[i][j].revealed) {
|
||||
if (board[i][j].isMine) printf("* ");
|
||||
else printf("%d ", board[i][j].adjacentMines);
|
||||
} else if (board[i][j].flagged) {
|
||||
printf("F ");
|
||||
} else {
|
||||
printf(". ");
|
||||
}
|
||||
}
|
||||
printf("|\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reveals a cell, recursively revealing neighbors if no adjacent mines.
|
||||
* @param row Row index
|
||||
* @param col Column index
|
||||
*/
|
||||
void revealCell(int row, int col) {
|
||||
if (!isInBounds(row, col) || board[row][col].revealed || board[row][col].flagged) return;
|
||||
|
||||
board[row][col].revealed = 1;
|
||||
if (!board[row][col].isMine) cellsToReveal--;
|
||||
|
||||
if (board[row][col].adjacentMines == 0 && !board[row][col].isMine) {
|
||||
int directions[8][2] = {
|
||||
{-1, -1}, {-1, 0}, {-1, 1},
|
||||
{0, -1}, {0, 1},
|
||||
{1, -1}, {1, 0}, {1, 1}
|
||||
};
|
||||
|
||||
for (int k = 0; k < 8; k++) {
|
||||
int newRow = row + directions[k][0];
|
||||
int newCol = col + directions[k][1];
|
||||
revealCell(newRow, newCol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Toggles the flag status of a cell.
|
||||
* @param row Row index
|
||||
* @param col Column index
|
||||
*/
|
||||
void toggleFlag(int row, int col) {
|
||||
if (!board[row][col].revealed) {
|
||||
board[row][col].flagged = !board[row][col].flagged;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the win condition.
|
||||
*/
|
||||
void checkWinCondition() {
|
||||
if (cellsToReveal == 0) {
|
||||
printf("Congratulations! You've cleared the board.\n");
|
||||
printBoard(1);
|
||||
exit(0);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user