# C language from getting started to giving up the array to realize the game - Minesweeper (nearly 10,000-character commentary, realization of expansion, flag planting)

Minesweeper, a classic casual game, most people would secretly play one or two games in the computer class. It was a good memory at that time, so let me lead you to use C language to realize minesweeper today.

With the experience of realizing the game of backgammon last time, minesweeping is the same this time, and the project is divided into three parts.

# 1. Function realization

## 1. Print the start menu

Like the three chess, we first need a start menu to decide whether we start the game or exit the game,

```void is_start()
{
printf("**********************\n");
printf("*****   1: start  *****\n");
printf("*****   0: quit  *****\n");
printf("**********************\n");
}```

## 2. Realize selection

The realization of the choice is the same as our backgammon. If you don’t understand it, you can go to my backgammon blog to have a look.

```int i = 0;
do
{
is_start();
scanf_s("%d", &i);
if (i == 1)
{
game();
printf("start the game\n");
}
else if (i == 0)
{
printf("exit the game\n");
}
else
{
printf("Wrong choice, choose again\n");
}
} while (i);```

## 3. Game implementation

### (1) How to lay mines on the game board and make them invisible?

We know that we only need a chessboard in the three-dimensional chess, and we can directly see what the "pieces" are inside, but we can't see where the "mines" are in minesweeping, so can we create two two-dimensional arrays? , one for our players to see, and one for our buried "mines".

```//There are two arrays, one for the player to see, and one for laying mines
char mine[ROWS][LINS];//thunder
char board[ROWS][LINS];//player```

The usage of ROWS and LINS used here is the same as that of backgammon, but does our minesweeping board have corners, but when we want to check a circle later, we will cause the array to go out of bounds when we check the corners, so our ROWS and LINS are 2 longer than the ranks of our real chessboard. For example, our minesweeper is normally 9×9, and our ROWS and LINS are 11 here.

```#define ROWS 11
#define LINS 11
#define ROW 9
#define LIN 9```

### (2) Initialize the chessboard

For minesweeper, when the two of us are initializing, the chessboard that a player sees is different from the real chessboard. Here I choose to initialize the chessboard we see to "*", and the real chessboard is initialized to "0", note that here is the character 0, because our array is of char type, when we do not include '', our 0 will be defaulted to the corresponding character in ASCII code, which is NULL, and the initialization is also It is to go through each row and column, and replace each element with what we want to replace.

```void init_board(char mb[ROWS][LINS], int row, int lin, char str)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < lin; j++)
{
mb[i][j] = str;
}
}
}```

### (3) Print the chessboard

Our minesweeping chessboard is very simple, but because it is 9×9, we can’t count every time we enter the coordinates of minesweeping, which is very troublesome and inconvenient, so we can mark a row of numbers horizontally and a row of numbers vertically. They are all from 1 to 9, and when we print the chessboard, we also print subscripts 1 to 9, so that the coordinates we input and the subscripts of the elements corresponding to the coordinates are consistent.

```void print_board(char mb[ROWS][LINS], int row, int lin)
{
int j = 0;
for (j = 0; j <=lin; j++)
{
printf("%d ",j);
}
printf("\n");
int i = 0;
for (i = 1; i <= row; i++)
{
printf("%d ", i);
j = 0;
for (j = 1; j <= lin; j++)
{
printf("%c ", mb[i][j]);
}
printf("\n");
}
}```

### (4) Mining

Landing mines is the same as before our computer game chess optimization of three-moon chess. It uses the characteristics of time stamps that are always changing, uses rand and srand to generate random numbers, and then uses ROW and LIN to take modulo. Note the modulo results here. +1, because our mine needs to be between subscript 1~9, if this 1 is not added, the range of modulo is 0~8, and we also need to judge whether this random subscript has been buried Thunder, after writing this, we can see if there are any mines on our real chessboard after the mines are buried.

```void bury_mine(char mine[ROWS][LINS], int row, int lin)
{
int count = 0;
while (1)
{
int i = rand() % row + 1;
int j = rand() % lin + 1;
if (mine[i][j] == '0')
{
mine[i][j] = '1';
count++;
}
if (count == MINE)
{
break;
}
}
}
//srand
int i = 0;
srand((unsigned int)time(NULL));
do
{
is_start();
scanf_s("%d", &i);
if (i == 1)
{
game();
printf("start the game\n");
}
else if (i == 0)
{
printf("exit the game\n");
}
else
{
printf("Wrong choice, choose again\n");
}
} while (i);```

### (5) Judging whether the demining coordinates are legal

After we planted the mines, we started to clear mines. Before clearing mines, we need to determine whether the coordinates we input are legal, whether they are within our range of 1~9, whether they have been checked, whether they are legal or not, and return a value. Write a selection statement outside. If it is illegal, tell us that the coordinates are illegal. Then we re-enter a coordinate and judge again. If it is legal, then proceed to the next step.

```int brush_legal(char board[ROWS][LINS], int row, int lin)
{
if (row < 10 && row>0&& lin < 10 && lin>0&& board[row][lin] == '*')
{
return 1;
}
else
{
return 0;
}
}
//
int i = 0;
int j = 0;
scanf("%d%d", &i, &j);
int legal = brush_legal(board, i, j);
if (legal == 1)
{
//proceed to the next step;
}

else
{
printf("This coordinate has been checked or is beyond the scope of checking, please select again.\n");
}```

### (6) Check whether the coordinates are Lei

After our coordinates are legal, we need to judge whether the coordinates are our "thunder". If it is thunder, the game ends directly. If it is not thunder, we can proceed to the next step. Then here is the same as our above judgment whether the coordinates are legal, and it is also outside A select statement, and the function returns a value.

```int is_or_no(char mine[ROWS][LINS], int row, int lin)
{
if (mine[row][lin] == '1')
{
return 0;
}
else
{
return 1;
}
}
//
int n = is_or_no(mine, i, j);
if (n == 1)
{
//next step;
}
else
{
printf("You are killed, game over\n");
break;
}```

### (7) Check the number of mines around

If we haven't stepped on a "thunder", the next step is to check the number of mines in a circle around the coordinates we choose. We only need to check all the elements in a circle to see if it is a mine. If it is not a mine, add one to the counter , and finally return the number of our counters.

```int num_mine(char mine[ROWS][LINS], int row, int lin)
{
int count = 0;
int i = 0;
for (i = row + 1; i > row - 2; i--)
{
int j = 0;
for (j = lin - 1; j < lin + 2; j++)
{
if (mine[i][j] == '1')
{
count++;
}
}
}
return count;
}```

### (8) Recursive expansion

Unfolding is actually not difficult. When there is no thunder around us, that is, the counter is 0, and the return value is also 0, then we start to unfold with the eight coordinates around us as the center coordinates, stop when we encounter thunder, and then we Add a "0" to the counter, and then replace the original "*" on our chessboard, which is used to indicate how many mines are around, and replace it with " " in other places without mines.

```void brush_mine(char board[ROWS][LINS], char mine[ROWS][LINS], int row, int lin)
{
int count = num_mine(mine, row, lin);
if (row > 0 && row <= ROW && lin>0 && lin <= LIN)
{
if (count == 0)
{
board[row][lin] = ' ';
int i = 0;
for (i = row + 1; i > row - 2; i--)
{
int j = 0;
for (j = lin - 1; j < lin + 2; j++)
{
if (board[i][j] == '*')
{
brush_mine(board, mine, row, lin);
}
}

}
}
else
{
board[row][lin] = '0' + count;
}
}
}```

### (9) Judging whether to win

When judging whether we are victorious, we only need to traverse the entire array we can see, and add one to the counter every time we encounter a "*". When the entire array counter is equal to ten, it proves that we have won. If not Then continue to investigate.

```int win_mine(char board[ROWS][LINS], int row, int lin)
{
int count = 0;
int i = 0;
for (i = 1; i < row - 1; i++)
{
int j = 0;
for (j = 1; j < lin - 1; j++)
{
if (board[i][j] == '*')
{
count++;
}
}
}
if (count == 10)
{
return 1;
}
else
{
return 0;
}
}
//
if (win == 1)
{
printf("successful demining\n");
break;
}```

### (10) Flags

Because of the function of inserting the flag, we need to add an option before we choose to check, that is, whether we want to insert the flag or check. When inserting the flag, because we have already judged the coordinates, we need to change the place where we want to insert the flag. Icon, which means to insert a flag, and then check whether the coordinates of the flag are our mines, if so, then return 1, and then we will add one after we receive it outside, and after we insert ten mines, we will Also won.

```int flag(char board[ROWS][LINS],char mine[ROWS][LINS], int row, int lin)
{
int count = 0;
board[row][lin] = "|>";
if (mine[row][lin] == '1')
{
return 1;
}
return 0;
}
//
int win = 0;
int i = 0;
int j = 0;
scanf("%d%d", &i, &j);
int legal = brush_legal(board, i, j);
if (legal == 1)
{
int n = flag(board, mine, i, j);
if (n == 1)
{
win++;
}
if (win == 10)
{
printf("successful demining\n");
break;
}
}
else
{
printf("This coordinate has been checked or is beyond the scope of checking, please select again.\n");
}```

# 2. Program module call

We have implemented all the functions, so we should call them in the above order? Before playing the game, the start menu will be printed first, and it will be printed, so here we use the do while loop, and then call our start menu to print After printing the menu, choose whether to start the game or exit. After entering the game, the first thing we need is our initialization board. Only after the initialization of the board can we proceed to the next series of operations. The initialized chessboard is printed out, let us choose the coordinates, and the next step is to print the chessboard. After printing the chessboard, we can choose whether to check or insert the flag. No matter which of the two is selected, we will judge whether the coordinates are legal. These actions Including the following actions need to be repeated all the time, so here we write these things into the infinite loop. When we win or fail and jump out, then after checking the coordinates and the coordinates are legal, what needs to be judged is our coordinates. Is it "thunder", if not, then start our search for the number of mines and recursive expansion, every time after checking or flagging, we need to check whether we have won now, the general idea is to only , we put them together as follows:

```//Game Implementation Module
void game()
{
//There are two arrays, one for the player to see, and one for laying mines
char mine[ROWS][LINS];//thunder
char board[ROWS][LINS];//player
//Initialize the board
init_board(mine, ROWS, LINS, '0');
init_board(board, ROWS, LINS, '*');
//print checkerboard
print_board(board, ROW, LIN);
//mine
bury_mine(mine, ROW, LIN);
//print_board(mine, ROWS, LINS);
//Check if the coordinates are legal
while (1)
{
int x = 0;
printf("Choose to check (1) or flag (2):>");
scanf("%d", &x);
if (x == 1)
{
int win = 0;
int i = 0;
int j = 0;
scanf("%d%d", &i, &j);
int legal = brush_legal(board, i, j);
if (legal == 1)
{

//demining
int n = is_or_no(mine, i, j);
if (n == 1)
{
brush_mine(board, mine, i, j);
print_board(board, ROW, LIN);
win = win_mine(board, ROWS, LINS);
if (win == 1)
{
printf("successful demining\n");
break;
}
}
else
{
printf("You are killed, game over\n");
break;
}
}
else
{
printf("This coordinate has been checked or is beyond the scope of checking, please select again.\n");
}
}
else if (x == 2)
{
int win = 0;
int i = 0;
int j = 0;
scanf("%d%d", &i, &j);
int legal = brush_legal(board, i, j);
if (legal == 1)
{
int n = flag(board, mine, i, j);
if (n == 1)
{
win++;
}
if (win == 10)
{
printf("successful demining\n");
break;
}
}
else
{
printf("This coordinate has been checked or is beyond the scope of checking, please select again.\n");
}
}
else
{
printf("Wrong choice, choose again\n");
}
}
}```

# source code:

## game.h

```#pragma once

#include<stdio.h>
#include<time.h>
#include<stdlib.h>

//Macro variables defined by #define
#define ROWS 11
#define LINS 11
#define ROW 9
#define LIN 9
#define MINE 10

//Custom functions used to implement game functionality
void init_board(char mb[ROWS][LINS], int row, int lin, char str);//Initialize the board
void print_board(char mb[ROWS][LINS], int row, int lin);//print checkerboard
void bury_mine(char mine[ROWS][LINS], int row, int lin);//mine
int brush_legal(char board[ROWS][LINS], int row, int lin);//Judging whether the investigation coordinates are legal
int is_or_no(char mine[ROWS][LINS], int row, int lin);//Check if the coordinates are mine
int num_mine( char mine[ROWS][LINS], int row, int lin);//Get the number of mines around the coordinates
void brush_mine(char board[ROWS][LINS], char mine[ROWS][LINS], int row, int lin);//Recursively expand mine
int win_mine(char board[ROWS][LINS], int row, int lin);//Judging whether to win
int flag(char board[ROWS][LINS], char mine[ROWS][LINS], int row, int lin);//flag```

## game.c

```#include "game.h"

//Initialize the board
void init_board(char mb[ROWS][LINS], int row, int lin, char str)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < lin; j++)
{
mb[i][j] = str;
}
}
}
//print checkerboard
void print_board(char mb[ROWS][LINS], int row, int lin)
{
int j = 0;
for (j = 0; j <=lin; j++)
{
printf("%d ",j);
}
printf("\n");
int i = 0;
for (i = 1; i <= row; i++)
{
printf("%d ", i);
j = 0;
for (j = 1; j <= lin; j++)
{
printf("%c ", mb[i][j]);
}
printf("\n");
}
}
//mine
void bury_mine(char mine[ROWS][LINS], int row, int lin)
{
int count = 0;
while (1)
{
int i = rand() % row + 1;
int j = rand() % lin + 1;
if (mine[i][j] == '0')
{
mine[i][j] = '1';
count++;
}
if (count == MINE)
{
break;
}
}
}
//Judging whether the coordinates of the investigation are legal
int brush_legal(char board[ROWS][LINS], int row, int lin)
{
if (row < 10 && row>0&& lin < 10 && lin>0&& board[row][lin] == '*')
{
return 1;
}
else
{
return 0;
}
}
//Check if the selected coordinates are Lei
int is_or_no(char mine[ROWS][LINS], int row, int lin)
{
if (mine[row][lin] == '1')
{
return 0;
}
else
{
return 1;
}
}
//Get the number of mines around the coordinates
int num_mine(char mine[ROWS][LINS], int row, int lin)
{
int count = 0;
int i = 0;
for (i = row + 1; i > row - 2; i--)
{
int j = 0;
for (j = lin - 1; j < lin + 2; j++)
{
if (mine[i][j] == '1')
{
count++;
}
}
}
return count;
}
//Recursively expand mine
void brush_mine(char board[ROWS][LINS], char mine[ROWS][LINS], int row, int lin)
{
int count = num_mine(mine, row, lin);
if (row > 0 && row <= ROW && lin>0 && lin <= LIN)
{
if (count == 0)
{
board[row][lin] = ' ';
int i = 0;
for (i = row + 1; i > row - 2; i--)
{
int j = 0;
for (j = lin - 1; j < lin + 2; j++)
{
if (board[i][j] == '*')
{
brush_mine(board, mine, row, lin);
}
}

}
}
else
{
board[row][lin] = '0' + count;
}
}
}
//Judging whether to win
int win_mine(char board[ROWS][LINS], int row, int lin)
{
int count = 0;
int i = 0;
for (i = 1; i < row - 1; i++)
{
int j = 0;
for (j = 1; j < lin - 1; j++)
{
if (board[i][j] == '*')
{
count++;
}
}
}
if (count == 10)
{
return 1;
}
else
{
return 0;
}
}
//flag
int flag(char board[ROWS][LINS],char mine[ROWS][LINS], int row, int lin)
{
int count = 0;
board[row][lin] = "|>";
if (mine[row][lin] == '1')
{
return 1;
}
return 0;
}```

## test.h

```#include"game.h"

void is_start()
{
printf("**********************\n");
printf("*****   1: start  *****\n");
printf("*****   0: quit  *****\n");
printf("**********************\n");
}
//Game Implementation Module
void game()
{
//There are two arrays, one for the player to see, and one for laying mines
char mine[ROWS][LINS];//thunder
char board[ROWS][LINS];//player
//Initialize the board
init_board(mine, ROWS, LINS, '0');
init_board(board, ROWS, LINS, '*');
//print checkerboard
print_board(board, ROW, LIN);
//mine
bury_mine(mine, ROW, LIN);
//print_board(mine, ROWS, LINS);
//Check if the coordinates are legal
while (1)
{
int x = 0;
printf("Choose to check (1) or flag (2):>");
scanf("%d", &x);
if (x == 1)
{
int win = 0;
int i = 0;
int j = 0;
scanf("%d%d", &i, &j);
int legal = brush_legal(board, i, j);
if (legal == 1)
{

//demining
int n = is_or_no(mine, i, j);
if (n == 1)
{
brush_mine(board, mine, i, j);
print_board(board, ROW, LIN);
win = win_mine(board, ROWS, LINS);
if (win == 1)
{
printf("successful demining\n");
break;
}
}
else
{
printf("You are killed, game over\n");
break;
}
}
else
{
printf("This coordinate has been checked or is beyond the scope of checking, please select again.\n");
}
}
else if (x == 2)
{
int win = 0;
int i = 0;
int j = 0;
scanf("%d%d", &i, &j);
int legal = brush_legal(board, i, j);
if (legal == 1)
{
int n = flag(board, mine, i, j);
if (n == 1)
{
win++;
}
if (win == 10)
{
printf("successful demining\n");
break;
}
}
else
{
printf("This coordinate has been checked or is beyond the scope of checking, please select again.\n");
}
}
else
{
printf("Wrong choice, choose again\n");
}
}
}
void test()
{
int i = 0;
srand((unsigned int)time(NULL));
do
{
is_start();
scanf_s("%d", &i);
if (i == 1)
{
game();
printf("start the game\n");
}
else if (i == 0)
{
printf("exit the game\n");
}
else
{
printf("Wrong choice, choose again\n");
}
} while (i);
}
int main()
{
test();
return 0;
}```

Tags: C Game Development

Posted by djwinder on Sat, 31 Dec 2022 17:01:33 +0530