使用C语言实现控制台操作的扫雷游戏

一.扫雷游戏分析和设计

设计一个9*9的格子,在其中实现随机埋雷。

用户通过控制台选择要排查的位置,如果是雷,被炸死,游戏结束。如果不是雷,则显示周围有几个雷,直到所有非雷位置被排完,排雷成功游戏结束。

可以通过菜单选择是否继续玩或者退出游戏。

1.菜单设计

通过输入数字实现对菜单的选择,然后封装到函数中

void menu()//不需要返回值,void
{
	printf("\n***********************\n");
	printf("***********************\n");
	printf("******  1.play  *******\n");
	printf("******  0.exit  *******\n");
	printf("***********************\n");
	printf("***********************\n");
}
int main()
{
	int put = 0;
	
	do {
		menu();
		printf("请输入你的选择:");
		scanf(" %d", &put);
		switch (put)
		{
		case 1:
			printf("\n请开始扫雷\n");
			game();
			break;
		case 0:
			printf("\n已退出游戏!\n");
			break;
		default:
			printf("\n选择错误,请重新输入!\n");
			break;
		}
	} while (put);

	return 0;
}

2.游戏内容的实现

初始化棋盘

当玩家进入游戏后,首先会看到一个9*9的棋盘,但是我们在初始化棋盘的时候要创建一个(9+2)*(9+2)的棋盘,这是因为如果玩家没有踩到雷就要显示周围雷的个数,在判断周围雷的个数时在边缘的位置和中心的计算方法不同,为了计算方便我们在棋盘多加了两行两列。

#define ROWS ROW+2//设置的存储的棋盘的长宽
#define COLS COL+2

在初始化棋盘时,一个位置要存放是不是雷,和周围有几个雷的数据在一个数组中不易实现因此设计两个数组 ,一个是布置雷,一个是给玩家展示 。

//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');//用于存放雷的棋盘,初始化为0
InitBoard(show, ROWS, COLS, '*');//用于显示给用户看的,初始化为*

void InitBoard(char arr[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++)//控制列
		{
			arr[i][j] = set;//初始化数组
		}
	}
}

随机布雷

 rand()%row+1是为了生成小于等于行数的随机数 

//在棋盘中布置雷
srand((unsigned int)time(NULL));//生成一个随机数,time函数无参返回,返回类型强制转换为unsigned
void SetMine(char arr[ROWS][COLS], int row, int col)
{
	int count = number;//设置雷的数量为10
	while (count)
	{   //使用rand函数需要调用srand函数,设置在主函数里面
		int x = rand() % row + 1;//棋盘x的坐标,%row值为0-8,+1值变成0-9
		int y = rand() % col + 1;//棋盘y的坐标,同上0-9

		if (arr[x][y] == '0')//首先判断当前的随机位置是否有雷,无雷进入
		{
			arr[x][y] = '1';//没有雷就在当前位置下放一个‘1’表示雷
			count--;//放置成功后,雷的数量减一
		}

	}
}

打印棋盘

/打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col)//打印显示的棋盘
{
	int i = 0; //控制行
	for (i = 0; i <= col; i++)//打印列号
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%d ", i);//打印行号
		for (j = 1; j <= col; j++)//控制列
		{
			printf("%c ", arr[i][j]);//循环打印数组里的所有内容
		}printf("\n");//每一行打印完之后换行
	}
	printf("\n");
}

开始游戏

//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x, y;//排查的坐标
	int count = 0;//可排查的次数
	while (count < row * col - number)
	{
		printf("请输入要排查的坐标(中间用空格隔开):");
		scanf("%d %d", &x, &y);//输入排查坐标

		if (x >= 1 && x <= row && y >= 1 && y <= col)//排查坐标需要在1-9之间
		{
			if (mine[x][y] == '1')//如果输入的坐标位置是‘1’,则被炸死
			{
				printf("很遗憾,你被炸死啦!!!!\n");
				printf("\n");
				DisplayBoard(mine, ROW, COL);//被炸死了,将布置雷的棋盘打印出来
				break;//跳出
			}

			else//输入位置不是雷,则显示当前位置的周围有几个雷
			{
				ExpandBlank(mine, show, x, y);
				DisplayBoard(show, ROW, COL);//显示排查过后的用户棋盘
				if (EndMine(show, ROW, COL))//返回为真
				{
					printf("恭喜你排雷成功!!!\n");//排雷成功
					DisplayBoard(mine, ROW, COL);//打印布置的棋盘
					break;
				}
			}
		}
		else
		{
			printf("输入坐标错误,请重新输入\n");
		}
	}
}
显示输入坐标周围有几个雷
//排查输入坐标周围的雷
int GetMine(char mine[ROWS][COLS], int x, int y)
{
	//每个坐标相加并减去字符0的大小(字符0的ASII码值为48),转换成数字
	return mine[x - 1][y] + mine[x + 1][y] + mine[x - 1][y - 1] +
		mine[x][y - 1] + mine[x + 1][y - 1] +
		mine[x - 1][y + 1] + mine[x][y + 1] +
		mine[x + 1][y + 1] - 8 * '0';
}
无雷区域的扩展

//无雷区域的扩展,使用递归实现
void ExpandBlank(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	int num = GetMine(mine, x, y);//九宫格雷的数量函数
	if (num)
	{
		// 将雷的数量放入show数组中, + ‘0’是将num由int类型转换为字符char类型
		show[x][y] = num + '0';
	}
	else if (show[x][y] == '*')
	{
		show[x][y] = ' ';//将没有雷的地方赋值为空格
		int i = 0, j = 0;//使用循环作为递归的条件,找出无雷区域
		for (i = x - 1; i <= x + 1; i++)
		{
			for (j = y - 1; j <= y + 1; j++)
			{
				ExpandBlank(mine, show, i, j);
			}
		}
	}
}
  开始排雷

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x, y;//排查的坐标
	while (count < row * col - number)
	{
		printf("请输入要排查的坐标(中间用空格隔开):");
		scanf("%d %d", &x, &y);//输入排查坐标

		if (x >= 1 && x <= row && y >= 1 && y <= col)//排查坐标需要在1-9之间
		{
			if (mine[x][y] == '1')//如果输入的坐标位置是‘1’也就是雷,则被炸死
			{
				printf("很遗憾,你被炸死啦!!!!\n");
				printf("\n");
				DisplayBoard(mine, ROW, COL);//被炸死了,将布置雷的棋盘打印出来
				break;//跳出
			}

			else//输入位置不是雷,则显示当前位置的周围有几个雷
			{
				ExpandBlank(mine, show, x, y);
				DisplayBoard(show, ROW, COL);//显示排查过后的用户棋盘
				if (EndMine(show, ROW, COL))//返回为真
				{
					printf("恭喜你排雷成功!!!\n");//排雷成功
					DisplayBoard(mine, ROW, COL);//打印布置的棋盘
					break;
				}
			}
		}
		else
		{
			printf("输入坐标错误,请重新输入\n");
		}
	}
}

二.代码整合

#pragma once

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


#define number 10//雷的个数
#define ROW 9//棋盘显示的长宽
#define COL 9

#define ROWS ROW+2//设置的存储的棋盘的长宽
#define COLS COL+2

void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);//接收数组,行,列,所要初始的内容

void DisplayBoard(char arr[ROWS][COLS], int row, int col);//数组大小不变,但是传过来显示的棋盘变成9×9

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

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

//初始化棋盘
void InitBoard(char arr[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++)//控制列
		{
			arr[i][j] = set;//初始化数组
		}
	}
}
//打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col)//打印显示的棋盘
{
	int i = 0; //控制行
	for (i = 0; i <= col; i++)//打印列号
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%d ", i);//打印行号
		for (j = 1; j <= col; j++)//控制列
		{
			printf("%c ", arr[i][j]);//循环打印数组里的所有内容
		}printf("\n");//每一行打印完之后换行
	}
	printf("\n");
}

//在棋盘中布置雷
void SetMine(char arr[ROWS][COLS], int row, int col)
{
	int count = number;//设置雷的数量为10
	while (count)
	{   //使用rand函数需要调用srand函数,设置在主函数里面
		int x = rand() % row + 1;//棋盘x的坐标,%row值为0-8,+1值变成0-9
		int y = rand() % col + 1;//棋盘y的坐标,同上0-9

		if (arr[x][y] == '0')//首先判断当前的随机位置是否有雷,无雷进入
		{
			arr[x][y] = '1';//没有雷就在当前位置下放一个‘1’表示雷
			count--;//放置成功后,雷的数量减一
		}

	}
}

//排查输入坐标周围的雷
int GetMine(char mine[ROWS][COLS], int x, int y)
{
	//每个坐标相加并减去字符0的大小(字符0的ASII码值为48),转换成数字
	return mine[x - 1][y] + mine[x + 1][y] + mine[x - 1][y - 1] +
		mine[x][y - 1] + mine[x + 1][y - 1] +
		mine[x - 1][y + 1] + mine[x][y + 1] +
		mine[x + 1][y + 1] - 8 * '0';
}

//获胜条件函数
int EndMine(char show[ROWS][COLS], int row, int col)
{
	int count = 0;
	for (int i = 1; i <= row; i++)
	{
		for (int j = 1; j <= col; j++)
		{
			if (show[i][j] == '*')//在棋盘上查找没有被排查的点
				count++;//统计没有被排查的点的数量
		}
	}
	if (count == number)//如果没有被排查的点的数量等于雷的数量
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

//无雷区域的扩展,使用递归实现
void ExpandBlank(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	int num = GetMine(mine, x, y);//九宫格雷的数量函数
	if (num)
	{
		// 将雷的数量放入show数组中, + ‘0’是将num由int类型转换为字符char类型
		show[x][y] = num + '0';
	}
	else if (show[x][y] == '*')
	{
		show[x][y] = ' ';//将没有雷的地方赋值为空格
		int i = 0, j = 0;//使用循环作为递归的条件,找出无雷区域
		for (i = x - 1; i <= x + 1; i++)
		{
			for (j = y - 1; j <= y + 1; j++)
			{
				ExpandBlank(mine, show, i, j);
			}
		}
	}
}


//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x, y;//排查的坐标
	int count = 0;//可排查的次数
	while (count < row * col - number)
	{
		printf("请输入要排查的坐标(中间用空格隔开):");
		scanf("%d %d", &x, &y);//输入排查坐标

		if (x >= 1 && x <= row && y >= 1 && y <= col)//排查坐标需要在1-9之间
		{
			if (mine[x][y] == '1')//如果输入的坐标位置是‘1’,则被炸死
			{
				printf("很遗憾,你被炸死啦!!!!\n");
				printf("\n");
				DisplayBoard(mine, ROW, COL);//被炸死了,将布置雷的棋盘打印出来
				break;//跳出
			}

			else//输入位置不是雷,则显示当前位置的周围有几个雷
			{
				ExpandBlank(mine, show, x, y);
				DisplayBoard(show, ROW, COL);//显示排查过后的用户棋盘
				if (EndMine(show, ROW, COL))//返回为真
				{
					printf("恭喜你排雷成功!!!\n");//排雷成功
					DisplayBoard(mine, ROW, COL);//打印布置的棋盘
					break;
				}
			}
		}
		else
		{
			printf("输入坐标错误,请重新输入\n");
		}
	}
}
void menu()//不需要返回值,void
{
	printf("\n***********************\n");
	printf("***********************\n");
	printf("******  1.play  *******\n");
	printf("******  0.exit  *******\n");
	printf("***********************\n");
	printf("***********************\n");
}
void game()//不需要返回值,void
{
	srand((unsigned int)time(NULL));//生成一个随机数,time函数无参返回,返回类型强制转换为unsigned
	char mine[ROWS][COLS];//设置成可变量方便于修改游戏难度
	char show[ROWS][COLS];

	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');//用于存放雷的棋盘,初始化为0
	InitBoard(show, ROWS, COLS, '*');//用于显示给用户看的,初始化为*

	//打印棋盘
	DisplayBoard(show, ROW, COL);//打印9×9显示给用户看的棋盘

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

	//开始排查雷
	FindMine(mine, show, ROW, COL);
}

int main()
{
	int put = 0;
	
	do {
		menu();
		printf("请输入你的选择:");
		scanf(" %d", &put);
		switch (put)
		{
		case 1:
			printf("\n请开始扫雷\n");
			game();
			break;
		case 0:
			printf("\n已退出游戏!\n");
			break;
		default:
			printf("\n选择错误,请重新输入!\n");
			break;
		}
	} while (put);

	return 0;
}

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值