【C语言】扫雷小游戏

本文详细介绍了使用C++编写的扫雷游戏程序,包括预处理模块(文件引用、宏定义),主函数设计(主功能选择与game()函数调用),以及关键函数如初始化数组、打印地图、布置雷和排查雷的实现。
摘要由CSDN通过智能技术生成


一、预览

  • 主页面
    主页面
  • 游戏页面
    在这里插入图片描述

二、预处理模块

  • 文件引用
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
  • 宏定义
#define ROW 9
#define COL 9

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

#define EASY_COUNT 10 //简单版本
  • 函数声明
    在本程序中使用了几个自定义的函数,这些函数的功能及声明形式代码如下:
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//初始化数组的内容

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

void SetMine(char board[ROWS][COLS], int row, int col);//布置雷

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//排查雷

int get_mine_count(char board[ROWS][COLS], int x, int y);

三、主函数设计

  • 功能概述
    在扫雷游戏的main()函数中主要实现了调用menu()函数显示主功能选择菜单,并且在switch分支选择结构中调用game()函数实现游戏的进行。

1.主函数的实现

编号功能
0退出游戏
1进入游戏

主函数main()的实现代码如下:

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));//设置随机数的生成起点

	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		system("cls");
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("下次再玩吧!\n");
			break;
		default:
			printf("ERROR!\n");
			break;
		}
	} while (input);

	return 0;
}

2.主页面的显示

在主函数中,通过调用menu()函数来显示主页面。
它的实现代码如下:

void menu()
{
	printf(":------------  扫 雷  ------------:\n");
	printf(":                                 :\n");
	printf(":                                 :\n");
	printf(":             1  play             :\n");
	printf(":                                 :\n");
	printf(":             0  exit             :\n");
	printf(":                                 :\n");
	printf(":                                 :\n");
	printf(":---------------------------------:\n");
}

四、game()函数的说明

1.game()函数

代码如下:

void game()
{
	char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
	char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
	
	//初始化数组的内容
	InitBoard(mine, ROWS, COLS, '0');//mine 数组在没有布置雷的时候,都是'0'
	InitBoard(show, ROWS, COLS, '*');//show 数组在没有排查雷的时候,都是'*'

	SetMine(mine, ROW, COL);//布置雷

	DisplayBoard(show, ROW, COL);

	FindMine(mine, show, ROW, COL);//排查雷  现在mine数组里看用户输入的坐标是否是雷
			   //是雷 游戏结束
			   //不是雷 统计他周围有几个雷 同时把数值显示到show数组里去
}

2.其余函数的说明

① 数组的初始化

将一个11×11的二维数组初始化为0,原因在思路中有讲到

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}

② 打印数组

这里通过for循环打印扫雷小游戏所需的页面,使其合理与美观

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("-----  扫 雷  -----\n");
	printf("  ");
	for (j = 1; j <= col; j++)
	{
		printf("%d ", j);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("-----  扫 雷  -----\n");
}

③ 布置雷的信息

这边定义EASY_COUNT是为了方便以后的更改,可以更改更高难度的版本

void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	  
	
	while (count)
	{	//x,y必须要在while循环里面定义,如果第一次判断不成功,便再次赋值一个随机值
		int x = rand() % row + 1; // 1~9
		int y = rand() % col + 1; // 1~9
		if (board[x][y] == '0')//如果等于0就说明不是雷,就给这个变量赋值为1,使得它变为雷
		{
			board[x][y] = '1';
			count--;
		}
	}
}

④ 统计周围的雷

这里的get_mine_count()函数是为了得到这个坐标周围的雷数然后返回,这个函数将用于FindMine()函数

int get_mine_count(char board[ROWS][COLS], int x, int y)
{
	int i = 0;
	int j = 0;

	return (board[x + 1][y + 1] +
		board[x + 1][y] +
		board[x + 1][y - 1] +
		board[x][y + 1] +
		board[x][y - 1] +
		board[x - 1][y + 1] +
		board[x - 1][y] +
		board[x - 1][y - 1] - 8 * '0');
}

⑤ 排查雷

  • 排查雷 现在mine数组里看用户输入的坐标是否是雷
  • 是雷 - 游戏结束
    不是雷 - 统计他周围有几个雷 同时把数值显示到show数组里去
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;//排查的个数 如果排查的次数等于81-10=71次,说明成功了

	while (win < row * col - EASY_COUNT )
	{
		printf("请输入要排查的坐标:>");
		scanf("%d %d", &x, &y);
		system("cls");
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标的合法性 
		{
			if (show[x][y] != '*')
			{
				printf("该坐标被排查过了,不能重复排查\n");
			}
			if (mine[x][y] == '1')//1表示有雷 0表示没有
			{
				system("cls");
				printf("很遗憾,你被炸死了\n");
				DisplayBoard(show, ROW, COL);//让用户知道自己死在哪儿
				Sleep(3000);
				system("cls");
				break;
			}
			else//不是雷,统计周围有多少个雷 由于1的ASCII值为49 字符0的ASCII值为48
				//这里可以使用'1'-'0'= 1,即字符1减去字符0等于数字0
				//同理 可以将这个坐标周围的八个字符相加后减去8×'0',这样就能够统计周围的雷
			{
				win++;
				int count = get_mine_count(mine, x, y);
				//统计mine数组中的(x, y)坐标周围有几颗雷
				show[x][y] = count + '0';//转换成数字字符
				DisplayBoard(show, ROW, COL);
			}
		}
		else
		{
			printf("ERROR!\n");
		}
	}

	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功!\n");
		DisplayBoard(show, ROW, COL);
	}
}

五、思路

  • 每个格子可以使用9x9的数组进行存放,可以用两个9x9的数组分别存放 布置好雷的信息mine[9][9]1和 排查出的雷的信息show[9][9]2
  • 当我们的雷布置到边界时,为了避免坐标越界和判断坐标的有效性以提高效率,我们可以将其视为将这个边界扩大一圈,但是这个扩大的范围里不存放雷,即mine[11][11]和show[11][11]

整体代码

\\#define _CRT_SECURE_NO_WARNINGS

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

#define ROW 9
#define COL 9

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

#define EASY_COUNT 10 //简单版本

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);

void DisplayBoard(char board[ROWS][COLS], int row, int col);

void SetMine(char board[ROWS][COLS], int row, int col);

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

int get_mine_count(char board[ROWS][COLS], int x, int y);

void menu()
{
	printf(":------------  扫 雷  ------------:\n");
	printf(":                                 :\n");
	printf(":                                 :\n");
	printf(":             1  play             :\n");
	printf(":                                 :\n");
	printf(":             0  exit             :\n");
	printf(":                                 :\n");
	printf(":                                 :\n");
	printf(":---------------------------------:\n");
}

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("-----  扫 雷  -----\n");
	printf("  ");
	for (j = 1; j <= col; j++)
	{
		printf("%d ", j);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("-----  扫 雷  -----\n");
}

void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	  
	
	while (count)
	{	//x,y必须要在while循环里面定义,如果第一次判断不成功,便再次赋值一个随机值
		int x = rand() % row + 1; // 1~9
		int y = rand() % col + 1; // 1~9
		if (board[x][y] == '0')//如果等于0就说明不是雷,就给这个变量赋值为1,使得它变为雷
		{
			board[x][y] = '1';
			count--;
		}
	}
}

int get_mine_count(char board[ROWS][COLS], int x, int y)
{
	int i = 0;
	int j = 0;

	return (board[x + 1][y + 1] +
		board[x + 1][y] +
		board[x + 1][y - 1] +
		board[x][y + 1] +
		board[x][y - 1] +
		board[x - 1][y + 1] +
		board[x - 1][y] +
		board[x - 1][y - 1] - 8 * '0');
}


void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;//排查的个数 如果排查的次数等于81-10=71次,说明成功了

	while (win < row * col - EASY_COUNT )
	{
		printf("请输入要排查的坐标:>");
		scanf("%d %d", &x, &y);
		system("cls");
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标的合法性 
		{
			if (show[x][y] != '*')
			{
				printf("该坐标被排查过了,不能重复排查\n");
			}
			if (mine[x][y] == '1')//1表示有雷 0表示没有
			{
				system("cls");
				printf("很遗憾,你被炸死了\n");
				DisplayBoard(show, ROW, COL);//让用户知道自己死在哪儿
				Sleep(3000);
				system("cls");
				break;
			}
			else//不是雷,统计周围有多少个雷 由于1的ASCII值为49 字符0的ASCII值为48
				//这里可以使用'1'-'0'= 1,即字符1减去字符0等于数字0
				//同理 可以将这个坐标周围的八个字符相加后减去8×'0',这样就能够统计周围的雷
			{
				win++;
				int count = get_mine_count(mine, x, y);
				//统计mine数组中的(x, y)坐标周围有几颗雷
				show[x][y] = count + '0';//转换成数字字符
				DisplayBoard(show, ROW, COL);
			}
		}
		else
		{
			printf("ERROR!\n");
		}
	}

	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功!\n");
		DisplayBoard(show, ROW, COL);
	}
}

void game()
{
	char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
	char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
	
	//初始化数组的内容
	InitBoard(mine, ROWS, COLS, '0');//mine 数组在没有布置雷的时候,都是'0'
	InitBoard(show, ROWS, COLS, '*');//show 数组在没有排查雷的时候,都是'*'

	SetMine(mine, ROW, COL);//布置雷

	DisplayBoard(show, ROW, COL);

	FindMine(mine, show, ROW, COL);//排查雷  现在mine数组里看用户输入的坐标是否是雷
			   //是雷 游戏结束
			   //不是雷 统计他周围有几个雷 同时把数值显示到show数组里去
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));//设置随机数的生成起点

	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		system("cls");
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("下次再玩吧!\n");
			break;
		default:
			printf("ERROR!\n");
			break;
		}
	} while (input);

	return 0;
}

  1. 初始化为’0’ ↩︎

  2. 初始化为’*’ ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值