C language game - simple minesweeper

foreword

This article mainly introduces a comprehensive small game in the primary stage of C language learning - a simple version of minesweeper.
The author feels that learning this game can have a relatively solid consolidation and review of the knowledge of C language in the primary stage! You can refer to it.
The author encapsulates the game into three files: game.h, game.c, and test.c for implementation.
game.h contains the required header files, macros for the defined array length, and function declarations for implementing game process functions!

1. Game Composition

We can use several functions to realize the realization of each game function step.
I divide it like this:
1. Game menu
2. Game test
3. Arrange the board and initialize the board
4. Initialize the number of mines according to our needs
5. Print the board
6. Players start mine clearance
7. Play the game according to each function The game function
8, the header file display of game.h
9, the finished game display


Second, the specific implementation of each function

1. Menu function

code show as below:

`void menu()
{
    
    
	printf("*****************************************\n");
	printf("**************   1、play!   *************\n");
	printf("**************   0、exit!   *************\n");
	printf("*****************************************\n");
}`
菜单就用printf函数打印出对应选项就可以实现

2. Game testing

The code is as follows (example):

int main()
{
    
    

	srand((unsigned int)time(NULL));//调用生成随机数

	int input = 0;

	do
	{
    
    
		menu();
		printf("请输入你的选择>\n");
		scanf("%d",&input);
		switch (input)
		{
    
    
		case 1:
			game();
			break;
		case 0:
			printf("结束游戏!\n");
			break;
		default :
			printf("输入有误,重新输入!\n");

		}
	} while (input);
	return 0;
}

According to our menu bar, there are several options. Use the switch statement to select and implement. Putting it in the loop can ensure that we can continue to choose after each game.
srand((unsigned int)time(NULL)); call this function It can be guaranteed that when we generate random numbers, they will be different each time!


3. Arrange the chessboard and initialize the chessboard

We can choose a variety of chessboards when arranging the chessboard. The author chooses a 9 +9 chessboard here.
We want to initialize the checkerboard to whatever character we want to pass in.
Since the author is showing that the checkerboard is initialized with '
', the two-dimensional array of the checkerboard is defined as a character type.
The code is as follows:

void InitBoard(char Mine[Rows][Cols], int rows, int cols,char ch)
{
    
    //字符ch是我们想要将棋盘格初始化为什么样子,就传入什么字符
	int i = 0, j = 0;
	for (i = 0; i < rows; i++)
	{
    
    
		for (j = 0; j < cols; j++)
		{
    
    
			Mine[i][j] = ch;
		}
	}
}

The length of the array is represented by the constant macro defined in the game.h header file, which is very convenient for maintaining and updating the game in the future, and only needs to modify the place where the macro is defined, reducing the workload.


4. Initialize the number of mines according to our needs

Because the minesweeper game displays the sum of the number of mines in the eight positions around it after each row of mines, so we should define two when defining the board, one is used to arrange mines, and the other is used to display the situation of the board after each mine is cleared. , and because it is necessary to visit the eight elements around the current position when judging the number of mines in the eight positions around the current position, since the position of the border of the chessboard will appear out of bounds when the array subscript is accessed, so we need to define the chessboard of 9 9 as 11 11, there is an extra row of grids on the top and bottom, and an extra column of grids on the left and right. We only initialize it to prevent mines from being placed in these positions, so that we visit each position of each 9*9 chessboard. When there are eight positions around a position, the array subscript will not appear out of bounds, and it will not affect our judgment on the number of mines around.
Code display:

void ArrBoard(char Mine[Rows][Cols], int rows, int cols)
{
    
    
	int count = Easy_Count;
	while (count)
	{
    
    
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (Mine[x][y] != '1')
		{
    
    
			Mine[x][y] = '1';
			count--;
		}
	}
}

Call the rand function with srand((unsigned int)time(NULL)); the function call generates a random number from 1 to 9, we use '1' to represent thunder


5. Print the chessboard

When printing the chessboard, we only need to print the 9*9 rows and columns we need, so we only need to pass in the macro that we print as 9. The
code shows:

void DisBoard(char Mine[Rows][Cols], int rows, int cols)
{
    
    
	printf("---------扫雷---------\n");
	int i = 0, j = 0;
	for (i = 0; i <= rows; i++)
	{
    
    
		printf("%d ", i);//把列的序号也打印出来
	}
	printf("\n");
	for (i = 1; i <=rows; i++)
	{
    
    
		printf("%d ", i);//每行打印前先把行号打印了
		for (j = 1; j <=cols; j++)
		{
    
    
			printf("%c ", Mine[i][j]);
		}
		printf("\n");
	}
	printf("---------扫雷---------\n");
}

In order to facilitate us to determine the coordinates of each position when printing, we can print out the labels of each row and column by the way, so that the array subscript of the first row of our chessboard in the array becomes: 1, and the first column becomes : 1, more convenient for players to locate


6. The player starts mine clearance

Code display:

int NumThunder(char Mine[Rows][Cols],int x,int y)
{
    
    //我们可以将判断一个位置周围八个位置的雷数总和的代码单独封装成一个函数
	return Mine[x - 1][y] + Mine[x][y - 1] + Mine[x][y + 1] + Mine[x - 1][y - 1] + Mine[x - 1][y + 1] + Mine[x + 1][y] + Mine[x + 1][y - 1] + Mine[x + 1][y + 1] - 8 * 48;
	//字符'0'的Acall值是48,所以这里-8*48是进行字符和整型的转化
}


void RemMine(char Mine[Rows][Cols], char Dis[Rows][Cols], int rows, int cols)
{
    
    
	int win = 0;
	while (win<rows*cols- Easy_Count)//循环确保排雷结束后游戏才结束
	{
    
    
		int x = 0, y = 0;
		printf("请输入你想要排雷的坐标>\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= rows && y >= 1 && y <= cols)
		{
    
    
			if (Mine[x][y] == '1')//踩到雷,游戏直接结束
			{
    
    
				printf("踩到地雷了,结束失败!\n");
				DisBoard(Mine, Row, Col);//失败后展示雷的分布
				break;
			}
			else 
			{
    
    
				//不是雷,则计算坐标x,y周围有几个雷
				int res = NumThunder(Mine, x, y) + 48;
				Dis[x][y] = res;
				DisBoard(Dis, Row, Col);//展示本次排雷后的棋盘以供继续排雷
				win++;//每排雷一次,排雷的次数加1
			}
		}
		else//输入坐标必须在1-9范围内,否则重新输入
		{
    
    
			printf("输入坐标有误,重新输入!\n");
		}
	}
	if (win == rows * cols - Easy_Count)//排雷次数与非雷数量相等且一直没有踩到雷时游戏胜利
	{
    
    
		printf("恭喜你,排雷成功!\n");
		DisBoard(Mine, Row, Col);//成功后展示雷的分布
	}
}


7. Game function for playing games according to each function

We use a game function to combine the functions of the game implementation process in a certain order, and complete the whole process of the game
Code display:

void game()
{
    
    
	char MineBoard[Rows][Cols] = {
    
     0 };//布置雷盘
	char ShowBoard[Rows][Cols] = {
    
     0 };//展示的棋盘
	InitBoard(MineBoard, Rows, Cols,'0');//初始化时将多的那两行两列也算上,因为后面统计周围雷数量时要用
	InitBoard(ShowBoard, Rows, Cols, '*');
	//DisBoard(MineBoard, Row, Col);//打印时就只穿想要打印的数量,顺便就从下标1开始打印了,因为0下标的元素刚好不用展示出来
    ArrBoard(MineBoard, Row, Col);//随机放置地雷
	//DisBoard(MineBoard, Row, Col);
	DisBoard(ShowBoard, Row, Col);
	//DisBoard(MineBoard, Row, Col);
	RemMine(MineBoard,ShowBoard, Row, Col);
}

8. The header file of game.h shows

The following shows the constant macros defined in the game.h header file and the header file
code display of the library functions used:

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

# define Row 9
# define Col 9
# define Rows Row+2
# define Cols Col+2
#define Easy_Count 10//设置的雷数


//初始化棋盘
void InitBoard(char Mine[Rows][Cols], int rows, int cols,char ch);

//打印棋盘
void DisBoard(char Mine[Rows][Cols], int rows, int cols);

//布雷
void ArrBoard(char Mine[Rows][Cols], int rows, int cols);

//排雷
void RemMine(char Mine[Rows][Cols], char Dis[Rows][Cols], int rows, int cols);

9. Display of finished game

choose
Choose 1 to start the game.
insert image description here
Choose the coordinates you want to mine and start mine clearance. After each mine clearance is successful, continue to display the latest board to continue mine clearance.
insert image description here
After stepping on a mine, the game fails and the distribution of mines is shown to the player.

Summarize

I hope that my understanding of this minesweeper game can help everyone, and please feel free to correct the areas that can be optimized. Thank you for watching, and I will continue to share my programming learning process in the future! ! !

Guess you like

Origin blog.csdn.net/m0_71214261/article/details/131959914