C Language Learning - Array Application - Minesweeper (4.2)

Table of contents

Minesweeper design ideas:

1. Realization of game menu functions

 2. Realization of game functions

2.1 Initialize the storage and mine-checking information

2.2 Initialization and printing of the minesweeping map

2.2.1 Initialize the implementation of mine-laying and mine-clearing maps:

2.2.2 Realization of printing minesweeping map:

2.3 Information about laying mines

 2.3.1 The specific realization of mine information:

2.4 Information about player mine clearance

2.4.1 The specific implementation of player mine clearance

2.4.2 The specific implementation of recursive emptying

2.4.3 The specific implementation of calculating how many mines are around the grid

2.4.4 The specific realization of the function of judging winning or losing

2.4.5 The specific implementation of punishment after being killed by mine

3. Game testing:

4. Minesweeper source code

Write at the end:


Minesweeper design ideas:

We create three files to split minesweeper's implementation process:

A test file (test.c) a game implementation file (game.c) a header file (game.h)

Let's edit the test file first.

In fact, the design idea of ​​minesweeper is similar to that of Sanziqi.

1. Realization of game menu functions

Write a main function in test.c:

int main()//主函数中的代码量较少
{
	test();//我们通过分装一个函数实现全过程
	return 0;
}

We implement some functions through the test function we just created:

1. Playing once is not enough, you can play again

2. Create the game menu

3. Create a minesweeper game implementation function

void test()
{
	int choice = 0;
	do //我们使用一个do while循环,如果玩一把扫雷不过瘾,可以再玩一把
	{
		menu();//创建游戏菜单
		printf("请输入:>");
		scanf("%d", &choice);//接收玩家输入的值
		switch (choice)
		{
		case 1:
			printf("扫雷惊魂游戏开始\n");
			game();//我们将游戏的实现分装成一个函数
			break;
		case 0:
			printf("游戏已退出\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (choice);
}

Here is our game menu:

void menu()
{
	printf("*****************************************\n");
	printf("************** 扫 雷 惊 魂 **************\n");
	printf("*****************************************\n");
	printf("******* 开始游戏:1  退出游戏:0 ********\n");
	printf("*****************************************\n");
}

After writing this, we can first test the result of the code running:

(Note: If there is an error, it can be corrected in time, in case it is difficult to find the error at the end of writing)

In this way, we have completed the creation of the menu logic. 

 2. Realization of game functions

Next we have to concretely implement the function game.

Implementation ideas:

2.1 Initialize the storage and mine-checking information

Through thinking, I plan to create a standard 9*9 minesweeper map

Need to create two arrays to operate:

1. A store mine information, is hidden

2. Another information that stores the player's investigation is to remind the player

We use #define to define constants in the header file, which is convenient for future observation or modification,

Then quote it in the test file:

#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"//引用自己的头文件

void game()  //排查坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
{            //扫雷地图的大小从 9*9 -> 11*11
	char mine[ROWS][COLS] = { 0 }; //初始化布置雷的信息
	char show[ROWS][COLS] = { 0 }; //初始化排查雷的信息
}

2.2 Initialization and printing of the minesweeping map

Next we need to initialize and print the minesweeper map:

We can split it into two functions for implementation:

void game()  //排查坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
{            //扫雷地图的大小从 9*9 -> 11*11
	char mine[ROWS][COLS] = { 0 }; //初始化布置雷的信息
	char show[ROWS][COLS] = { 0 }; //初始化排查雷的信息

	//初始化扫雷地图
	InitBoard(mine, ROWS, COLS, '0');//初始化布雷的地图
	InitBoard(show, ROWS, COLS, '*');//初始化排雷的地图

	//打印扫雷地图
	PrintBoard(show, ROW, COL);//打印的式给玩家看的,用于排雷的地图
}

2.2.1 Initialize the implementation of mine-laying and mine-clearing maps:

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;//将布置雷的数组初始化成‘0’
		}                     //将排雷的数组(玩家看到的)布置成‘*’
	}
}

2.2.2 Realization of printing minesweeping map:

void PrintBoard(char board[ROWS][COLS], int row, int col)
{
	printf(" ------扫雷惊魂------\n");//添加头尾(美观)
	printf(" --------------------\n|");
	int i = 0;
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);//打印横坐标
	}
	printf("|\n");
	for (i = 1; i <= row; i++)
	{
		int j = 1;
		printf("|%d ", i);//打印纵坐标
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);//打印扫雷地图
		}
		printf("|");//添加边框(美观)
		printf("\n");
	}
	printf(" --------------------\n");
	printf(" -地图 碎片大厦的回忆-\n");
}

Remember to quote in the header file game.h:

//初始化地图
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//打印地图
void PrintBoard(char board[ROWS][COLS], int row, int col);

The final result is:

Next we are going to set up mine:

2.3 Information about laying mines

We need to package a function for implementation:

void game()  //排查坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
{            //扫雷地图的大小从 9*9 -> 11*11
	char mine[ROWS][COLS] = { 0 }; //初始化布置雷的信息
	char show[ROWS][COLS] = { 0 }; //初始化排查雷的信息

	//初始化扫雷地图
	InitBoard(mine, ROWS, COLS, '0');//初始化布雷的地图
	InitBoard(show, ROWS, COLS, '*');//初始化排雷的地图

	//打印扫雷地图
	PrintBoard(show, ROW, COL);//打印的式给玩家看的,用于排雷的地图
	
	//布置雷的信息
	SetMine(mine, ROW, COL);//悄悄地布置

}

 2.3.1 The specific realization of mine information:

void SetMine(char mine[ROWS][COLS], int row, int col)
{
	int count = MINE_NUMBER;
	while (count)
	{
		//生成随机下标
		int x = rand() % row + 1;//生成1~9之间的数
		int y = rand() % col + 1;
		//布置雷
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

Referenced in the header file:

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

#define MINE_NUMBER 10 //定义雷的数量

//布置雷的信息
void SetMine(char mine[ROWS][COLS], int row, int col);

We can print out the mine information to see if there is any error:

After counting carefully, 10 mines were indeed buried.

Next, it’s time for players to clear mines

2.4 Information about player mine clearance

We need to package a function for implementation:

void game()  //排查坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
{            //扫雷地图的大小从 9*9 -> 11*11
	char mine[ROWS][COLS] = { 0 }; //初始化布置雷的信息
	char show[ROWS][COLS] = { 0 }; //初始化排查雷的信息

	//初始化扫雷地图
	InitBoard(mine, ROWS, COLS, '0');//初始化布雷的地图
	InitBoard(show, ROWS, COLS, '*');//初始化排雷的地图

	//打印扫雷地图
	PrintBoard(show, ROW, COL);//打印的式给玩家看的,用于排雷的地图

	//布置雷的信息
	SetMine(mine, ROW, COL);//悄悄地布置
	//PrintBoard(mine, ROW, COL);//打印埋雷信息出来,观察一下

	//排查雷
	FindMine(mine, show, ROW, COL);//目标是实现排雷时,能自动排空,并能判断输赢
}

2.4.1 The specific implementation of player mine clearance

Functions are linked together:

We improve the function step by step through the nesting of functions,

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int n = row * col;//n用来判断是否胜利
	while (n > 10)
	{
		printf("请输入要排雷的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)//限定在9*9的格子中
		{
			if (show[x][y] != '*')
			{
				printf("你已经排查过这里啦,去找其他地方吧\n");
				continue;//重新判断
			}
			if (mine[x][y] == '1')//碰到雷了
			{
				printf("\a呜呜...地雷把你炸懵了,电脑崩溃了......\n");//\a报警
					PrintBoard(mine, ROW, COL);//把雷的位置放出来给玩家看
					Shutdown();//游戏失败的小惩罚,嘻嘻
					break;
			}
			else
			{   //位置安全的情况
				find_safe_place(mine, show, x, y, row, col);//函数递归实现排空
				PrintBoard(show, ROW, COL);//打印排空后的情况
				n = win(show, row, col);//函数实现判断输赢
			}
		}
		else
		{
			printf("地图上没有这个坐标,请重新输入\n");//坐标非法的情况
		}
	}
	if (n == 10)
	{
		printf("恭喜你扫雷成功!!!\n");
		printf("这么好玩不再来一把吗?\n\n\n");
	}
}

Referenced in the header file:

//玩家排雷的信息
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

Next is the implementation of the packing function:

2.4.2 The specific implementation of recursive emptying

void find_safe_place(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int row, int col)
{
	if (x >= 1 && x <= row && y >= 1 && y <= col && mine[x][y] == '0' && show[x][y] == '*')
	{   //确保坐标在地图内,且未被排查过
		mine[x][y] = '@';//排查后的标记
		if (get_mine_count(mine, x, y))//函数实现该格子周围有多少颗地雷
		{	//如果有,则进入下一条语句计算
			show[x][y] = get_mine_count(mine, x, y) + '0';
		}
		else//周围没有地雷
		{
			show[x][y] = '0';//显示0
			int i = 0;
			for (i = -1; i <= 1; i++)//将该坐标的周围八个坐标都排查一遍
			{
				int j = 0;
				for (j = -1; j <= 1; j++)
				{
					find_safe_place(mine, show, x + i, y + j, row, col);//通过递归排空
				}
			}
		}
	}
}

2.4.3 The specific implementation of calculating how many mines are around the grid

int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
	int i = 0;
	int count = 0;//计数
	for (i = -1; i <= 1; i++)
	{
		int j = 0;
		for (j = -1; j <= 1; j++)//排查格子周围的八个格子
		{
			if (mine[x + i][y + j] == '1')//碰到地雷
			{
				count++;
			}
		}	
	}
	return count;//将计算后的值返回
}

2.4.4 The specific realization of the function of judging winning or losing

int win(char show[ROWS][COLS], int row, int col)
{
	int count = 0;
	int i = 0;
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		for (j = 1; j <= col; j++)//排查地图上所有的坐标
		{
			if (show[i][j] == '*')//当地图上只剩下十个未知的坐标
			{                     //而玩家没有被炸死,证明扫雷成功了
				count++;
			}
		}
	}
	return count;
}

2.4.5 The specific implementation of punishment after being killed by mine

void Shutdown()
{
	char input[20] = { 0 };
	system("shutdown -s -t 60");//关机指令
again:
	printf("你的电脑被地雷炸坏啦,如果输入:我是猪  就能修好电脑\n请输入:");
	scanf("%s", input, 20);
	if (strcmp(input, "我是猪") == 0)//引了头文件:#include<string.h>
	{
		system("shutdown -a");//停止关机指令
		printf("这就屈服了?再玩一把报仇吧!\n\n\n");
	}
	else
	{
		printf("不输入就等死吧,哼\n");
		goto again;
	}
}

The minesweeper game is finished, I hope you like it

Next is the testing session.

3. Game testing:

Let's win a test together!

 4. Minesweeper source code

test.c file:

#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"//引用自己的头文件

void menu()
{
	printf("*****************************************\n");
	printf("************** 扫 雷 惊 魂 **************\n");
	printf("*****************************************\n");
	printf("******* 开始游戏:1  退出游戏:0 ********\n");
	printf("*****************************************\n");
}

void game()  //排查坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
{            //扫雷地图的大小从 9*9 -> 11*11
	char mine[ROWS][COLS] = { 0 }; //初始化布置雷的信息
	char show[ROWS][COLS] = { 0 }; //初始化排查雷的信息

	//初始化扫雷地图
	InitBoard(mine, ROWS, COLS, '0');//初始化布雷的地图
	InitBoard(show, ROWS, COLS, '*');//初始化排雷的地图

	//打印扫雷地图
	PrintBoard(show, ROW, COL);//打印的式给玩家看的,用于排雷的地图

	//布置雷的信息
	SetMine(mine, ROW, COL);//悄悄地布置
	//PrintBoard(mine, ROW, COL);//打印埋雷信息出来,观察一下

	//排查雷
	FindMine(mine, show, ROW, COL);//目标是实现排雷时,能自动排空,并能判断输赢
}

	void test()
	{
		srand((unsigned int)time(NULL));//生成随机数
		int choice = 0;
		do //我们使用一个do while循环,如果玩一把扫雷不过瘾,可以再玩一把
		{
			menu();//创建游戏菜单
			printf("请输入:>");
			scanf("%d", &choice);//接收玩家输入的值
			switch (choice)
			{
			case 1:
				printf("扫雷惊魂游戏开始,祝你好运\n");
				game();//我们将游戏的实现分装成一个函数
				break;
			case 0:
				printf("游戏已退出\n");
				break;
			default:
				printf("输入错误,请重新输入\n");
				break;
			}
		} while (choice);
	}

int main()//主函数中的代码量较少
{
	test();//我们通过分装一个函数实现全过程
	return 0;
}

game.h file:

#pragma once

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

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

#define MINE_NUMBER 10 //定义雷的数量

//初始化地图
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);

//打印地图
void PrintBoard(char board[ROWS][COLS], int row, int col);

//布置雷的信息
void SetMine(char mine[ROWS][COLS], int row, int col);

//玩家排雷的信息
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

game.c file:

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;//将布置雷的数组初始化成‘0’
		}                     //将排雷的数组(玩家看到的)布置成‘*’
	}
}

void PrintBoard(char board[ROWS][COLS], int row, int col)
{
	printf(" ------扫雷惊魂------\n");//添加头尾(美观)
	printf(" --------------------\n|");
	int i = 0;
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);//打印横坐标
	}
	printf("|\n");
	for (i = 1; i <= row; i++)
	{
		int j = 1;
		printf("|%d ", i);//打印纵坐标
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);//打印扫雷地图
		}
		printf("|");//添加边框(美观)
		printf("\n");
	}
	printf(" --------------------\n");
	printf(" -地图 碎片大厦的回忆-\n");
}

void SetMine(char mine[ROWS][COLS], int row, int col)
{
	int count = MINE_NUMBER;
	while (count)
	{
		//生成随机下标
		int x = rand() % row + 1;//生成1~9之间的数
		int y = rand() % col + 1;
		//布置雷
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

void Shutdown()
{
	char input[20] = { 0 };
	system("shutdown -s -t 60");//关机指令
again:
	printf("你的电脑被地雷炸坏啦,如果输入:我是猪  就能修好电脑\n请输入:");
	scanf("%s", input, 20);
	if (strcmp(input, "我是猪") == 0)//引了头文件:#include<string.h>
	{
		system("shutdown -a");//停止关机指令
		printf("这就屈服了?再玩一把报仇吧!\n\n\n");
	}
	else
	{
		printf("不输入就等死吧,哼\n");
		goto again;
	}
}

int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
	int i = 0;
	int count = 0;//计数
	for (i = -1; i <= 1; i++)
	{
		int j = 0;
		for (j = -1; j <= 1; j++)//排查格子周围的八个格子
		{
			if (mine[x + i][y + j] == '1')//碰到地雷
			{
				count++;
			}
		}	
	}
	return count;//将计算后的值返回
}

void find_safe_place(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int row, int col)
{
	if (x >= 1 && x <= row && y >= 1 && y <= col && mine[x][y] == '0' && show[x][y] == '*')
	{   //确保坐标在地图内,且未被排查过
		mine[x][y] = '@';//排查后的标记
		if (get_mine_count(mine, x, y))//函数实现该格子周围有多少颗地雷
		{	//如果有,则进入下一条语句计算
			show[x][y] = get_mine_count(mine, x, y) + '0';
		}
		else//周围没有地雷
		{
			show[x][y] = ' ';//显示0
			int i = 0;
			for (i = -1; i <= 1; i++)//将该坐标的周围八个坐标都排查一遍
			{
				int j = 0;
				for (j = -1; j <= 1; j++)
				{
					find_safe_place(mine, show, x + i, y + j, row, col);//通过递归排空
				}
			}
		}
	}
}

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int n = row * col;//n用来判断是否胜利
	while (n > 10)
	{
		printf("请输入要排雷的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)//限定在9*9的格子中
		{
			if (show[x][y] != '*')
			{
				printf("你已经排查过这里啦,去找其他地方吧\n");
				continue;//重新判断
			}
			if (mine[x][y] == '1')//碰到雷了
			{
				printf("\a呜呜...地雷把你炸懵了,电脑崩溃了......\n");//\a报警
					PrintBoard(mine, ROW, COL);//把雷的位置放出来给玩家看
					Shutdown();//游戏失败的小惩罚,嘻嘻
					break;
			}
			else
			{   //位置安全的情况
				find_safe_place(mine, show, x, y, row, col);//函数递归实现排空
				PrintBoard(show, ROW, COL);//打印排空后的情况
				n = win(show, row, col);//函数实现判断输赢
			}
		}
		else
		{
			printf("地图上没有这个坐标,请重新输入\n");//坐标非法的情况
		}
	}
	if (n == 10)
	{
		printf("恭喜你扫雷成功!!!\n");
		printf("这么好玩不再来一把吗?\n\n\n");
	}
}

int win(char show[ROWS][COLS], int row, int col)
{
	int count = 0;
	int i = 0;
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		for (j = 1; j <= col; j++)//排查地图上所有的坐标
		{
			if (show[i][j] == '*')//当地图上只剩下十个未知的坐标
			{                     //而玩家没有被炸死,证明扫雷成功了
				count++;
			}
		}
	}
	return count;
}

Write at the end:

The above is the content of this article, thank you for reading.

If you like this article, please like and comment, and write down your opinions.

If you want to learn programming with me, you might as well follow me, we will learn and grow together.

I will output more high-quality content in the future, welcome to watch.

おすすめ

転載: blog.csdn.net/Locky136/article/details/127696209