【C语言】如何写一个扫雷游戏

1. 扫雷游戏分析和设计

1.1 扫雷游戏的功能说明

• 使⽤控制台实现经典的扫雷游戏

• 游戏可以通过菜单实现继续玩或者退出游戏

• 扫雷的棋盘是9*9的格⼦

• 默认随机布置10个雷

• 可以排查雷

①如果位置不是雷,就显⽰周围有⼏个雷

②如果位置是雷,就炸死游戏结束

③把除10个雷之外的所有⾮雷都找出来,排雷成功,游戏结束

2. 首先我们把游戏的框架搭建出来

我们首先设计一个游戏开始界面,“1”表示开始游戏,“0”表示退出游戏,然后我们开始玩游戏,一把不过瘾,我们可以再玩一把,一直就这么玩下去,那么整体游戏思路就是这么一个流程。

代码如下:

#include <stdio.h>

//游戏菜单
void menu()
{
	printf("*************************\n");
	printf("****** 1.play game ******\n");
	printf("****** 0.exit game ******\n");
	printf("*************************\n");
}

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("扫雷游戏\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}

	} while (input);

	return 0;
}

好,我们现在就可以测试一下,游戏整体框架是否正确。

调试运行结果:

从调试运行结果来看,整体游戏框架没问题,接下来我们就可以进行下一步。

3. 初始化棋盘

这时候,我们就可以考虑怎么设置一个初始棋盘,显示给玩家,意思就是,给游戏做一个游戏界面。为了方便,我们可以把字符 '1' 当作雷,字符 '0' 就不是雷,这种的做法,是为了后续统计雷的数量提供便利。

设计思想:

我们可以这样设计,游戏开始界面设计成全部都是 '*' ,用 '*' 来遮挡棋盘里面的雷 '1' ,然后让玩家输入坐标去排雷。这样想毫无疑问,肯定是可以的,但是一个棋盘是二维字符数组,单纯用一个数组去存放如此多的信息,显然不够简化,会使得这个游戏设计的过于复杂化。

这时我们可以考虑,用两个数组来存放这些信息,一个显示给玩家,供玩家观察,一个隐藏起来存放雷的信息,这样就避免程序的复杂化。

初始棋盘程序:

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

初始完棋盘,我们把它打印出来,打印棋盘程序:

//打印棋盘
void Print_hide(char hide[ROWS][COLS], int row, int col)
{
	printf("----- 扫雷游戏 -----\n");
	//打印列号
	for (int i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");

	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印行号
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", hide[i][j]);
		}
		printf("\n");
	}
}

void Print_show(char show[ROWS][COLS], int row, int col)
{
	printf("----- 扫雷游戏 -----\n");
	//打印列号
	for (int i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");

	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印行号
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", show[i][j]);
		}
		printf("\n");
	}
}

完成以上内容我们来测试一下,主程序:

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

//打印棋盘
void Print_hide(char hide[ROWS][COLS], int row, int col)
{
	printf("----- 扫雷游戏 -----\n");
	//打印列号
	for (int i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");

	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印行号
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", hide[i][j]);
		}
		printf("\n");
	}
}

void Print_show(char show[ROWS][COLS], int row, int col)
{
	printf("----- 扫雷游戏 -----\n");
	//打印列号
	for (int i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");

	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印行号
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", show[i][j]);
		}
		printf("\n");
	}
}

调试运行结果:

效果还不错,接下来我们就可以进行下一步。

4. 布置雷和查找雷

前面我们讲述了如何初始化棋盘,接下来我们就可以布置雷。但这里有一个问题是,我们布置9*9的棋盘里面随机10个格子的雷,这挺好操作的,但就是我们扫完一个格子不是雷时,我们得统计这个格子周围的8格子雷的数量,然后显示给玩家。

红色方格统计雷的数量是3,这没问题,问题就出在?统计雷的数量,这里到底是几个雷?前面我们说了,我们统计的是玩家所选的方格周围8个格子的坐标,但是右下角要统计周围的8格子的雷,是不是就越界了,这样统计的话程序就会出bug,那到底怎么办呢?

仔细考虑的话,我们应该能想到,既然统计到外面的格子会越界,那我们就给它范围放大一点,周围再加一圈格子,这样它就不会越界了。对,就是这样。

所以我们上面的棋盘初始化程序是按 11*11 来初始化的,但是哦,我们显示棋盘就只需要显示 9*9棋盘就行了。

4.1 布置雷

接下来我们就在hide棋盘的淡蓝色 9*9 位置随机10个格子布置雷 '1' ,我们可以利用时间戳随机产生10个坐标。

//布置雷 "1"
void hide_mine(char hide[ROWS][COLS], int row, int col)
{

	int count = MINE_NUM;//10个雷
	while (count)
	{
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (hide[x][y] == '0')
		{
			hide[x][y] = '1';
			count--;
		}
	}
}

主程序:

#include <stdio.h>
#include "game.h"

//游戏菜单
void menu()
{
	printf("*************************\n");
	printf("****** 1.play game ******\n");
	printf("****** 0.exit game ******\n");
	printf("*************************\n");
}

//游戏逻辑
void Mine_game()
{
	char show[ROWS][COLS] = { 0 };//展示棋盘,用来玩游戏界面,同时显示周围雷的个数
	char hide[ROWS][COLS] = { 0 };//隐藏棋盘,用来布置雷的

	//初始化棋盘
	Init_board(show, ROWS, COLS, '*');
	Init_board(hide, ROWS, COLS, '0');

	//布置雷 "1"
	hide_mine(hide, ROW, COL);

	//打印棋盘
	Print_hide(hide, ROW, COL);
	//Print_show(show, ROW, COL);
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			//printf("扫雷游戏\n");
			Mine_game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}

	} while (input);

	return 0;
}

调试运行结果:

效果不错,符合我们预期,接下来我们就可以进行下一步。

4.2 查找雷

玩家可以输入自己想要查找坐标,遇到雷 '1' 就游戏结束,没有遇到雷 '1' 就继续查找,直到成功避开所有的雷 '1' ,游戏就成功通关。

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

//查找雷
void find_mine(char hide[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{
	int num = 0;
	while (num < row * col - MINE_NUM)
	{
		//输入坐标
		int x = 0;
		int y = 0;
		printf("请输入要排查的坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (hide[x][y] == '1')
			{
				printf("抱歉,你被炸死了,游戏结束!\n");
				Print_hide(hide, ROW, COL);
				break;
			}
			else
			{
				if (show[x][y] != '*')
				{
					printf("该坐标已经被排查过了,无需再排查!\n");
				}
				else
				{
					//统计hide[x][y]坐标周围8个格子有几个雷
					int count = mine_count(hide, x, y);
					show[x][y] = count + '0';
					Print_show(show, ROW, COL);
					num++;
				}
			}
		}
		else
		{
			printf("输入坐标有误,请重新输入!\n");
		}
	}
	if (num == row * col - MINE_NUM)
	{
		printf("恭喜你,排雷成功!\n");
		Print_hide(hide, ROW, COL);
	}
}

这一块的程序意思是,我们得统计坐标(x,y)周围8个坐标雷的数量。

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

5. 整体调试运行

所有程序:

main.c

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

/*
'1'表示雷,'0'不是雷,这是放在隐藏棋盘
'0' ASCLL码  48
'1' ASCLL码  49
*/

//游戏菜单
void menu()
{
	printf("*************************\n");
	printf("****** 1.play game ******\n");
	printf("****** 0.exit game ******\n");
	printf("*************************\n");
}

//游戏逻辑
void Mine_game()
{
	char show[ROWS][COLS] = { 0 };//展示棋盘,用来玩游戏界面,同时显示周围雷的个数
	char hide[ROWS][COLS] = { 0 };//隐藏棋盘,用来布置雷的
	
	//初始化棋盘
	Init_board(show, ROWS, COLS, '*');
	Init_board(hide, ROWS, COLS, '0');

	//布置雷 "1"
	hide_mine(hide, ROW, COL);

	//Print_hide(hide, ROW, COL);
	Print_show(show, ROW, COL);

	//查找雷
	find_mine(hide,show, ROW, COL);

	//打印棋盘
	//Print_hide(hide, ROW, COL);
	//Print_show(show, ROW, COL);
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			//printf("扫雷游戏\n");
			Mine_game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}

	} while (input);

	return 0;
}

game.c

#include <stdio.h>
#include "game.h"
#include <stdlib.h>

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

//打印棋盘
void Print_hide(char hide[ROWS][COLS], int row, int col)
{
	printf("----- 扫雷游戏 -----\n");
	//打印列号
	for (int i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");

	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印行号
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", hide[i][j]);
		}
		printf("\n");
	}
}

void Print_show(char show[ROWS][COLS], int row, int col)
{
	printf("----- 扫雷游戏 -----\n");
	//打印列号
	for (int i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");

	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印行号
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", show[i][j]);
		}
		printf("\n");
	}
}

//布置雷 "1"
void hide_mine(char hide[ROWS][COLS],int row, int col)
{

	int count = MINE_NUM;//10个雷
	while (count)
	{
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (hide[x][y] == '0')
		{
			hide[x][y] = '1';
			count--;
		}
	}
}

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

//查找雷
void find_mine(char hide[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{
	int num = 0;
	while (num < row * col - MINE_NUM)
	{
		//输入坐标
		int x = 0;
		int y = 0;
		printf("请输入要排查的坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (hide[x][y] == '1')
			{
				printf("抱歉,你被炸死了,游戏结束!\n");
				Print_hide(hide, ROW, COL);
				break;
			}
			else
			{
				if (show[x][y] != '*')
				{
					printf("该坐标已经被排查过了,无需再排查!\n");
				}
				else
				{
					//统计hide[x][y]坐标周围8个格子有几个雷
					int count = mine_count(hide, x, y);
					show[x][y] = count + '0';
					Print_show(show, ROW, COL);
					num++;
				}
			}
		}
		else
		{
			printf("输入坐标有误,请重新输入!\n");
		}
	}
	if (num == row * col - MINE_NUM)
	{
		printf("恭喜你,排雷成功!\n");
		Print_hide(hide, ROW, COL);
	}
}

game.h

#define MINE_NUM 10 //10个雷

#define ROW  9 //显示行
#define COL  9 //显示列

#define ROWS ROW+2 //棋盘行
#define COLS COL+2 //棋盘列

//初始化棋盘
void Init_board(char board[ROWS][COLS], int rows, int cols, char set);

//打印棋盘
void Print_hide(char hide[ROWS][COLS], int row, int col);
void Print_show(char show[ROWS][COLS], int row, int col);

//布置雷 "1"
void hide_mine(char hide[ROWS][COLS], int row, int col);

//查找雷
void find_mine(char hide[ROWS][COLS], char show[ROWS][COLS], int row, int col);

运行结果:

效果不错,恭喜您完成这个游戏的设计!

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值