C语言:扫雷小游戏(第一次不炸死,周围没有雷时可展开)

扫雷的实现思路

首先我们需要两个棋盘,设计者棋盘和玩家棋盘。打印棋盘后要在棋盘上布雷,这里采用的是九乘九的棋盘放置十个雷。棋盘存储信息用由二维数组来完成,让这个二维数组开始先全部存储0,然后把要布置雷的地方改为1,用来区分雷和非雷。布完雷后开始扫雷,如果第一次输入的坐标处是雷,为了实现第一次不炸死,把这个位置的1改为0,但此时雷的总数就减少一个,需要寻找一个字符为0的坐标将其改成1以维持雷的总数不变;如果第一次输入的坐标不是雷,程序需要实现两个功能,在玩家输入一个周围都没有雷的坐标时用递归展开为空格,在玩家输入一个周围有雷的坐标时显示周围雷的个数。扫完雷后我们需要判断输赢,切忌不要用空格数来判断,因为不是所有没有雷的的地方都显示为空格,有一部分无雷的坐标会显示周围的雷数,空格的个数无法确定,所以要用雷的个数来判断,因为雷的个数是永远不变的。有雷的地方永远显示为’*’,所以玩家扫完所有雷的时只要判断雷的个数是否为10,个数为10时玩家扫雷成功,游戏结束。


需要哪些功能的函数

1.初始化棋盘
这里的扫雷规模为九成九的棋盘布置十个雷,但是为了使玩家能清晰明了的输入坐标,需要给棋盘的行列标上数字,所以实际上我们需要的是一个十一乘十一的棋盘。
这里写图片描述
2.打印棋盘
3.布置所有的雷
4.获取这个坐标周围的雷数
5.展开一个周围没有雷的坐标
6.第一次不会炸死
7.判断输赢
8.排雷


在写程序之前先创建两个源文件game.c,test.c和一个头文件game.h。
这里写图片描述


一、test.c
1.主函数

int main()
{
	test();
	return 0;
}

2.test函数

void test()
{
	int input = 0;
	srand((unsigned int)time(NULL));//调用随机数
	do//游戏开始,重复玩
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);
}

3.game函数
row,col分别表示行和列,rows,cols分别表示行和列加2。

void game()
{
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	InitBoard(mine, ROWS, COLS,'0');//初始化设计者棋盘
	InitBoard(show, ROWS, COLS, '*');//初始化玩家棋盘
	SetMine(mine, ROW, COL);//布雷
	DisplayBoard(mine, ROW, COL);//打印设计者棋盘
	DisplayBoard(show, ROW, COL);//打印玩家棋盘
	SafeMine(mine,show,ROW,COL);//第一次不炸死
	FindMine(mine, show, ROW, COL);//排雷
}

4.菜单

void menu()
{
	printf("**************************\n");
	printf("********^扫雷小游戏^******\n");
	printf("******    1.play    ******\n");
	printf("******    0.exit    ******\n");
	printf("**************************\n");
}

二、game.c
1.初始化棋盘
由于玩家棋盘和设计者棋盘需要的参数不一样,所以不能全部初始化为全0或全‘*’,需要定义一个set用来传参。

void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)//设置一个字符set
{
	memset(board, set, rows*cols*sizeof(board[0][0]));
}

2.打印棋盘

void DisplayBoard(char board[ROWS][COLS], int row, int col)//只需要打印九乘九的棋盘
{
	int i = 0;
	int j = 0;
	for (i = 0; i <= row; i++)//打印行号和列号
	{
		printf("%d ", i);
	}
	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");
}

3.布雷

void SetMine(char board[ROWS][COLS], int row, int col)//雷只需要传到九乘九的格子里
{
	int x = 0;
	int y = 0;
	int count = EASY_COUNT;//定义count来数雷,总共要布置十个雷
	while (count)
	{
		x = rand() % 9 + 1;//生成随机下标1-9
		y = rand() % 9 + 1;
		if (board[x][y] == '0')//判断这个位置有没有雷,没有雷的话将非雷的坐标由0改为1,每布置好一个雷,count--(这里不用判断坐标是否合法)
		{
			board[x][y] = '1';
			count--;
		}
	}
}

4.计算一个坐标周围雷的个数

int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	return mine[x - 1][y] +
		mine[x - 1][y - 1] +
		mine[x][y - 1] +
		mine[x + 1][y - 1] +
		mine[x + 1][y] +
		mine[x + 1][y + 1] +
		mine[x][y + 1] +
		mine[x - 1][y + 1] - 8 * '0';
}

5.展开一个周围没有雷的坐标(递归)

void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
	int ret = 0;
	ret = GetMineCount(mine, x, y);
	if (ret == 0)
	{
		show[x][y] = ' ';
		if (x - 1>0 && y>0 && show[x - 1][y] == '*')
			OpenMine(mine, show, row, col, x - 1, y);

		if (x - 1>0 && y + 1 <= col && show[x - 1][y + 1] == '*')
			OpenMine(mine, show, row, col, x - 1, y + 1);

		if (x>0 && y + 1 <= col && show[x][y + 1] == '*')
			OpenMine(mine, show, row, col, x, y + 1);

		if (x + 1 <= row && y + 1 <= col && show[x + 1][y + 1] == '*')
			OpenMine(mine, show, row, col, x + 1, y + 1);

		if (x + 1 <= row && y>0 && show[x + 1][y] == '*')
			OpenMine(mine, show, row, col, x + 1, y);

		if (x + 1 <= row && y - 1>0 && show[x + 1][y - 1] == '*')
			OpenMine(mine, show, row, col, x + 1, y - 1);

		if (x>0 && y - 1>0 && show[x][y - 1] == '*')
			OpenMine(mine, show, row, col, x, y - 1);

		if (x - 1>0 && y - 1>0 && show[x - 1][y - 1] == '*')
			OpenMine(mine, show, row, col, x - 1, y - 1);

	}
	else
	{
		show[x][y] = GetMineCount(mine, x, y) + '0';
	}
}

6.第一次不炸死

void SafeMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int ret = 1;
	int ch = 0;
	printf("请输入要排查的坐标:>");
	scanf("%d%d", &x, &y);
	if (mine[x][y] == '1')//如果第一次输入坐标为雷将坐标改为0即非雷
	{
		mine[x][y] = '0';//获取周围雷的个数
		ch = GetMineCount(mine,x, y);
		show[x][y] = ch + '0';数字对应的ASCII值和数字字符对应的ASCII值相差48,即'0'的ASCII
		while (ret)//在其余有空的地方设置一个雷
       {
			 x = rand() % 9 + 1;//生成随机数1-9
			 y = rand() % 9 + 1;
			if (mine[x][y] == '0')
			{
				mine[x][y] = '1';
			}
			ret--;
		}
    }
	OpenMine(mine, show, row, col,x,y);
	DisplayBoard(show, row, col);
}

7.判断输赢
这里的判断方法是数雷的个数,如果玩家在没有被炸死的条件下棋盘只剩下十个雷即十个‘*’,说明玩家排雷成功。

int IsWin(char show[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	int count = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			if (show[i][j] == '*')
			{
				count++;
			}
		}
	}
	return count;
}

8.排雷

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请输入要排查的坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row &&y >= 1 && y <= col)//判断坐标的有效性
		{
			if (mine[x][y] == '1')//判断是否为雷,如果是雷提示被炸死并打印设计者棋盘
			{
				printf("很遗憾,你被炸死了\n");
				DisplayBoard(mine, row, col);
				break;
			}
			else//如果不是雷,获取周围雷的个数并展开
			{
				int c = GetMineCount(mine, x, y);
				show[x][y] = c + '0';
				OpenMine(mine, show, row, col, x, y);
				DisplayBoard(show, row, col);
				if (IsWin(show, row, col) == EASY_COUNT)
				{
					break;
				}
            }
       }
		else//如果坐标无意义,提示坐标非法
		{
			printf("坐标非法\n");
		}
	}
		if (IsWin(show, row, col) == EASY_COUNT)
		{
			printf("恭喜你,排雷成功\n");
			DisplayBoard(mine, ROW, COL);
		}
}

	

三、game.h
将所有用到的函数全部声明。

#ifndef __GAME_H_
#define __GAME_H_
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define EASY_COUNT 10

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

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);
void SafeMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

#endif //__GAME_H_

游戏运行界面如下:
这里写图片描述
这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值