c语言实现功能最全的扫雷游戏

文章详细介绍了如何使用C语言实现扫雷游戏,包括初始化雷区、选择游戏模式、随机设置雷的位置、排查雷的逻辑、统计周围雷的个数以及点击空白格子时的自动展开功能。此外,游戏还包括计时功能,可以显示当前时间并计算完成游戏所用的时间。
摘要由CSDN通过智能技术生成

游戏介绍

该扫雷游戏具有以下功能:
计时,显示时间,难度模式选择,开雷和标记雷位置,动态显示雷个数等

代码讲解

初始化雷区

使用了两个二维数组,mine数组是用来存放布置好的雷的信息,show数组是用来存放排查出的雷的信息(显示在屏幕中)

void InitBoard(char board[][COLS], int rows, int cols, char ch)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = ch;
		}
	}
}
char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');

选择模式代码

游戏模式共分成三种模式:1、简单模式 2、中等模式 3、困难模式(在以后的函数中用digit接收此序号)。利用switch-case语句实现模式选择

printf("游戏模式共分成三种模式:1、简单模式  2、中等模式  3、困难模式\n");
			printf("请选择游戏模式:");
			scanf("%d", &choice);
			switch (choice)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

随机设置雷的位置代码

利用rand()和srand()函数生成的随机数作为雷的位置,期间进行位置重复的判断

//布置NUMBEROFMINE个雷
void SetMine(char board[][COLS], int row, int col, int digit)
{
	srand((unsigned)time(NULL));
	int count = 0;
	if (digit == 1)
		count = EASY_NUMBEROFMINE;
	else if (digit == 2)
		count = MEDIUM_NUMBEROFMINE;
	else
		count = EXPERT_NUMBEROFMINE;

	while (count > 0)
	{
		int r = rand() % row + 1;
		int c = rand() % col + 1;
		if (board[r][c] == '0')
		{
			board[r][c] = '1';
			count--;
		}
	}
}

排查雷代码

跟据前期选择的模式,使用if-else语句找到对应的代码位置。每一种模式均拥有1、打开位置和0、标记位置两个功能,当玩家选择0时,屏幕上边会显示雷的数量,当标记位置是雷的位置时,显示的数量会减1,当减为0时玩家胜利游戏结束;当玩家选择1时,如果该位置是雷,则游戏结束玩家失败;否则会统计该位置周围雷的个数,如果个数为0,则会以该位置为中心向外自动展开格子,直至遇到非零格子。
以简单模式为例:

void FindMine(char mine[][COLS], char show[][COLS], int row, int col, int digit)
{
	int count = 0;
	if (digit == 1)
	{
		count = EASY_NUMBEROFMINE;
		while (cnt1 > 0) {
			int x = 0, y = 0, choice = 0;
			printf("\t输入1表示打开'*',输入0表示标记雷位置\n");
			printf("请选择:");
			scanf("%d", &choice);
			if (choice == 0)
			{
				printf("请输入标记雷的坐标:");
				scanf("%d%d", &x, &y);
				show[x][y] = '#';
				PrintBoard(show, row, col);
				if (mine[x][y] == '1')
				{
					count--;
				}
				printf("还剩%d个雷\n", count);
				if (count == 0)
				{
					break;
				}
			}
			else if (choice == 1)
			{
				printf("请输入要打开'*'的坐标:");
				scanf("%d%d", &x, &y);
				if (x >= 1 && x <= row && y >= 1 && y <= col)
				{
					if (mine[x][y] == '1')
					{
						printf("很遗憾,您被炸了!!!\n");
						printf("Game Over\n");
						PrintBoard(mine, ROW, COL);
						printf("以上是雷的分布\n");
						break;
					}
					else
					{
						OutwardRadiation(mine, show, x, y, digit);
						PrintBoard(show, row, col);
					}
				}
				else
				{
					printf("输入非法,请重新输入!\n");
				}
			}
			else
			{
				printf("输入错误,请重新输入\n");
			}

		}
		if (cnt1 == 0 || count == 0)
		{
			printf("恭喜你,排雷成功!!!\n");
		}
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

统计周围雷的个数代码

show数组在初始化和添加雷的时候,我们以’1’作为雷,以’0’作为非雷,此时让该位置四周的八个位置处字符相加再减去8*0(原理:1+‘0’=‘1’),即可得到该位置周围雷的数量。

//统计周围雷的个数
int GetMinNumber(char mine[][COLS], int x, int y)
{
	return mine[x - 1][y - 1]
		+ mine[x][y - 1]
		+ mine[x + 1][y - 1]
		+ mine[x - 1][y]
		+ mine[x + 1][y]
		+ mine[x - 1][y + 1]
		+ mine[x][y + 1]
		+ mine[x + 1][y + 1] - 8 * '0';
}

点击到空白格子时自动展开代码(递归)

此代码用递归实现。

//实现辐射式显示雷个数
void OutwardRadiation(char mine[][COLS], char show[][COLS], int x, int y, int digit)
{
	if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1)//位置是否越界
	{
		return;
	}
	if (show[x][y] != '*')//遍历过的位置不再遍历,防止出现死递归
	{
		return;
	}
	//不同模式
	if (digit == 1)
	{
		cnt1--;
	}
	else if (digit == 2)
	{
		cnt2--;
	}
	else
	{
		cnt3--;
	}

	int count = GetMinNumber(mine, x, y, digit) + '0';
	//该位置不为0时递归停止
	if (count != '0')
	{
		show[x][y] = count;
		return;
	}
	else
	{
		show[x][y] = '0';
		OutwardRadiation(mine, show, x - 1, y - 1, digit);
		OutwardRadiation(mine, show, x, y - 1, digit);
		OutwardRadiation(mine, show, x + 1, y - 1, digit);
		OutwardRadiation(mine, show, x - 1, y, digit);
		OutwardRadiation(mine, show, x + 1, y, digit);
		OutwardRadiation(mine, show, x - 1, y + 1, digit);
		OutwardRadiation(mine, show, x, y + 1, digit);
		OutwardRadiation(mine, show, x + 1, y + 1, digit);
	}
}

显示时间代码

在开始游戏时利用系统时间库函数显示当前时间–“xx年xx月xx日 xx时xx分xx秒 星期x”

//显示时间
void ShowTime()
{
	SYSTEMTIME sys;
	printf("");
	GetLocalTime(&sys);//获取系统时间
	printf("\t当前时间为:%4d/%02d/%02d %02d:%02d:%02d ",
		sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute, sys.wSecond);
	switch (sys.wDayOfWeek)
	{
	case 1:
	{
		printf("星期一\n");
		break;
	}
	case 2:
	{
		printf("星期二\n");
		break;
	}
	case 3:
	{
		printf("星期三\n");
		break;
	}
	case 4:
	{
		printf("星期四\n");
		break;
	}
	case 5:
	{
		printf("星期五\n");
		break;
	}
	case 6:
	{
		printf("星期六\n");
		break;
	}
	case 7:
	{
		printf("星期日\n");
		break;
	}
	default:
	{
		break;
	}
	}
}

计算玩游戏用时代码

利用clock_t实现

clock_t start, end;
start = clock();
Game(1);
end = clock();
printf("完成游戏用时%f分钟", (double)(end - start) / (CLOCKS_PER_SEC * 60));

整体代码展示

扫雷游戏的实现共使用了3个文件,一个头文件和两个源文件,分别是test.c,game.h,game.c。

test.c

#define  _CRT_SECURE_NO_WARNINGS 1
#include"game.h"

int main()
{
	int input = 0, choice = 0;
	do {
		menu();
		printf("请输入您的选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		{
			printf("\t\t     游戏开始\n");
			printf("游戏模式共分成三种模式:1、简单模式  2、中等模式  3、困难模式\n");
			printf("请选择游戏模式:");
			scanf("%d", &choice);
			switch (choice)
			{
			case 1:
			{
				printf("\t总共有%d个雷,Have a good time!\n", EASY_NUMBEROFMINE);
				clock_t start, end;
				start = clock();
				Game(1);
				end = clock();
				printf("完成游戏用时%f分钟", (double)(end - start) / (CLOCKS_PER_SEC * 60));
				break;
			}
			case 2:
			{
				printf("\t总共有%d个雷,Have a good time!\n", MEDIUM_NUMBEROFMINE);
				clock_t start, end;
				start = clock();
				Game(2);
				end = clock();
				printf("完成游戏用时%f分钟", (double)(end - start) / (CLOCKS_PER_SEC * 60));
				break;
			}
			case 3:
			{
				printf("\t总共有%d个雷,Have a good time!\n", EXPERT_NUMBEROFMINE);
				clock_t start, end;
				start = clock();
				Game(3);
				end = clock();
				printf("完成游戏用时%f分钟", (double)(end - start) / (CLOCKS_PER_SEC * 60));
				break;
			}

			default:
			{
				printf("输入错误,请重新输入!\n");
				break;
			}
			}
			break;
		}
		case 0:
		{
			printf("感谢您的参与,再见\n");
			break;
		}
		default:
		{
			printf("选择错误,请重新输入\n");
			break;
		}
		}
		Sleep(8888);
		system("cls");
	} while (input != 0);
	return 0;
}

game.h

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

#define ROW 9//格子行有效长度
#define ROWS ROW+2//格子行总长度
#define COL 9//格子列有效长度
#define COLS COL+2//格子列总长度
#define EASY_NUMBEROFMINE 10//简单模式雷的个数
#define MEDIUM_NUMBEROFMINE 15//中等模式雷的个数
#define EXPERT_NUMBEROFMINE 25//困难模式雷的个数

extern int cnt1;//简单模式'*'个数
extern int cnt2;//中等模式'*'个数
extern int cnt3;//困难模式'*'个数

void Game(int digit);//进行游戏
void InitBoard(char board[][COLS], int rows, int cols, char ch);//初始化棋盘
void PrintBoard(char board[][COLS], int row, int col);//打印棋盘
void SetMine(char board[][COLS], int row, int col, int digit);//布置NUMBEROFMINE个雷
void FindMine(char mine[][COLS], char show[][COLS], int row, int col, int digit);//排查雷
int GetMinNumber(char mine[][COLS], int x, int y);//统计周围雷的个数
void OutwardRadiation(char mine[][COLS], char show[][COLS], int x, int y, int digit);//实现辐射式显示雷个数
void ShowTime();//显示时间
void menu();//菜单

game.c

#define  _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
int cnt1 = ROW * COL - EASY_NUMBEROFMINE;
int cnt2 = ROW * COL - MEDIUM_NUMBEROFMINE;
int cnt3 = ROW * COL - EXPERT_NUMBEROFMINE;

//菜单
void menu()
{
	printf("****************************************************\n");
	printf("\t\t欢迎来到扫雷游戏\n");
	printf("\t   输入1开始游戏  输入0结束游戏\n");
	ShowTime();
	printf("****************************************************\n");
}

//初始化棋盘
void InitBoard(char board[][COLS], int rows, int cols, char ch)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = ch;
		}
	}
}

//打印棋盘
void PrintBoard(char board[][COLS], int row, int col)
{
	printf("***********************扫雷************************\n");
	for (int i = 0; i <= row; i++)
	{
		printf("%d ", i);
		for (int j = 1; j <= col; j++)
		{
			if (i == 0)
			{
				printf("%d ", j);
			}
			else
			{
				printf("%c ", board[i][j]);
			}
		}
		printf("\n");
	}
}

//布置NUMBEROFMINE个雷
void SetMine(char board[][COLS], int row, int col, int digit)
{
	srand((unsigned)time(NULL));
	int count = 0;
	if (digit == 1)
		count = EASY_NUMBEROFMINE;
	else if (digit == 2)
		count = MEDIUM_NUMBEROFMINE;
	else
		count = EXPERT_NUMBEROFMINE;

	while (count > 0)
	{
		int r = rand() % row + 1;
		int c = rand() % col + 1;
		if (board[r][c] == '0')
		{
			board[r][c] = '1';
			count--;
		}
	}
}

//排查雷
void FindMine(char mine[][COLS], char show[][COLS], int row, int col, int digit)
{
	int count = 0;
	if (digit == 1)
	{
		count = EASY_NUMBEROFMINE;
		while (cnt1 > 0) {
			int x = 0, y = 0, choice = 0;
			printf("\t输入1表示打开'*',输入0表示标记雷位置\n");
			printf("请选择:");
			scanf("%d", &choice);
			if (choice == 0)
			{
				printf("请输入标记雷的坐标:");
				scanf("%d%d", &x, &y);
				show[x][y] = '#';
				PrintBoard(show, row, col);
				if (mine[x][y] == '1')
				{
					count--;
				}
				printf("还剩%d个雷\n", count);
				if (count == 0)
				{
					break;
				}
			}
			else if (choice == 1)
			{
				printf("请输入要打开'*'的坐标:");
				scanf("%d%d", &x, &y);
				if (x >= 1 && x <= row && y >= 1 && y <= col)
				{
					if (mine[x][y] == '1')
					{
						printf("很遗憾,您被炸了!!!\n");
						printf("Game Over\n");
						PrintBoard(mine, ROW, COL);
						printf("以上是雷的分布\n");
						break;
					}
					else
					{
						OutwardRadiation(mine, show, x, y, digit);
						PrintBoard(show, row, col);
					}
				}
				else
				{
					printf("输入非法,请重新输入!\n");
				}
			}
			else
			{
				printf("输入错误,请重新输入\n");
			}

		}
		if (cnt1 == 0 || count == 0)
		{
			printf("恭喜你,排雷成功!!!\n");
		}
	}
	else if (digit == 2)
	{
		count = MEDIUM_NUMBEROFMINE;
		while (cnt2 > 0) {
			int x = 0, y = 0, choice = 0;
			printf("\t输入1表示打开'*',输入0表示标记雷位置\n");
			printf("请选择:");
			scanf("%d", &choice);
			if (choice == 0)
			{
				printf("请输入标记雷的坐标:");
				scanf("%d%d", &x, &y);
				show[x][y] = '#';
				PrintBoard(show, row, col);
				if (mine[x][y] == '1')
				{
					count--;
				}
				printf("还剩%d个雷\n", count);
				if (count == 0)
				{
					break;
				}
			}
			else if (choice == 1)
			{
				printf("请输入要打开'*'的坐标:");
				scanf("%d%d", &x, &y);
				if (x >= 1 && x <= row && y >= 1 && y <= col)
				{
					if (mine[x][y] == '1')
					{
						printf("很遗憾,您被炸了!!!\n");
						printf("Game Over\n");
						PrintBoard(mine, ROW, COL);
						printf("以上是雷的分布\n");
						break;
					}
					else
					{
						OutwardRadiation(mine, show, x, y, digit);
						PrintBoard(show, row, col);
					}
				}
				else
				{
					printf("输入非法,请重新输入!\n");
				}
			}
			else
			{
				printf("输入错误,请重新输入\n");
			}

		}
		if (cnt2 == 0 || count == 0)
		{
			printf("恭喜你,排雷成功!!!\n");
		}
	}
	else
	{
		count = EXPERT_NUMBEROFMINE;
		while (cnt3 > 0) {
			int x = 0, y = 0, choice = 0;
			printf("\t输入1表示打开'*',输入0表示标记雷位置\n");
			printf("请选择:");
			scanf("%d", &choice);
			if (choice == 0)
			{
				printf("请输入标记雷的坐标:");
				scanf("%d%d", &x, &y);
				show[x][y] = '#';
				PrintBoard(show, row, col);
				if (mine[x][y] == '1')
				{
					count--;
				}
				printf("还剩%d个雷\n", count);
				if (count == 0)
				{
					break;
				}
			}
			else if (choice == 1)
			{
				printf("请输入要打开'*'的坐标:");
				scanf("%d%d", &x, &y);
				if (x >= 1 && x <= row && y >= 1 && y <= col)
				{
					if (mine[x][y] == '1')
					{
						printf("很遗憾,您被炸了!!!\n");
						printf("Game Over\n");
						PrintBoard(mine, ROW, COL);
						printf("以上是雷的分布\n");
						break;
					}
					else
					{
						OutwardRadiation(mine, show, x, y, digit);
						PrintBoard(show, row, col);
					}
				}
				else
				{
					printf("输入非法,请重新输入!\n");
				}
			}
			else
			{
				printf("输入错误,请重新输入\n");
			}

		}
		if (cnt3 == 0 || count == 0)
		{
			printf("恭喜你,排雷成功!!!\n");
		}
	}
}

//实现辐射式显示雷个数
void OutwardRadiation(char mine[][COLS], char show[][COLS], int x, int y, int digit)
{
	if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1)//位置是否越界
	{
		return;
	}
	if (show[x][y] != '*')//遍历过的位置不再遍历,防止出现死递归
	{
		return;
	}
	//不同模式
	if (digit == 1)
	{
		cnt1--;
	}
	else if (digit == 2)
	{
		cnt2--;
	}
	else
	{
		cnt3--;
	}

	int count = GetMinNumber(mine, x, y, digit) + '0';
	//该位置不为0时递归停止
	if (count != '0')
	{
		show[x][y] = count;
		return;
	}
	else
	{
		show[x][y] = '0';
		OutwardRadiation(mine, show, x - 1, y - 1, digit);
		OutwardRadiation(mine, show, x, y - 1, digit);
		OutwardRadiation(mine, show, x + 1, y - 1, digit);
		OutwardRadiation(mine, show, x - 1, y, digit);
		OutwardRadiation(mine, show, x + 1, y, digit);
		OutwardRadiation(mine, show, x - 1, y + 1, digit);
		OutwardRadiation(mine, show, x, y + 1, digit);
		OutwardRadiation(mine, show, x + 1, y + 1, digit);
	}
}


//统计周围雷的个数
int GetMinNumber(char mine[][COLS], int x, int y)
{
	return mine[x - 1][y - 1]
		+ mine[x][y - 1]
		+ mine[x + 1][y - 1]
		+ mine[x - 1][y]
		+ mine[x + 1][y]
		+ mine[x - 1][y + 1]
		+ mine[x][y + 1]
		+ mine[x + 1][y + 1] - 8 * '0';
}

//显示时间
void ShowTime()
{
	SYSTEMTIME sys;
	printf("");
	GetLocalTime(&sys);//获取系统时间
	printf("\t当前时间为:%4d/%02d/%02d %02d:%02d:%02d ",
		sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute, sys.wSecond);
	switch (sys.wDayOfWeek)
	{
	case 1:
	{
		printf("星期一\n");
		break;
	}
	case 2:
	{
		printf("星期二\n");
		break;
	}
	case 3:
	{
		printf("星期三\n");
		break;
	}
	case 4:
	{
		printf("星期四\n");
		break;
	}
	case 5:
	{
		printf("星期五\n");
		break;
	}
	case 6:
	{
		printf("星期六\n");
		break;
	}
	case 7:
	{
		printf("星期日\n");
		break;
	}
	default:
	{
		break;
	}
	}
}

//进行游戏
void Game(int digit)
{
	char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
	char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	//打印棋盘
	SetMine(mine, ROW, COL, digit);//布置10个雷
	PrintBoard(show, ROW, COL);
	FindMine(mine, show, ROW, COL, digit);
}

运行结果

程序刚开始运行
开始游戏
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值