基于C语言实现扫雷小游戏详解

目录

一、扫雷游戏规则介绍

二、扫雷游戏实现思路分析

三、分文件实现扫雷游戏

四、分模块实现扫雷游戏

     测试逻辑的基本架构

菜单menu函数的实现

test函数基本架构

开始实现游戏前对部分变量重命名(方便修改数据)

创建数组并将其初始化

初始化棋盘函数InitBoard函数的实现

打印棋盘函数DisplayBoard函数的实现

布置雷的函数SetMine函数的实现

统计坐标周围雷的数量的函数GetMineCount函数的实现

排查雷的函数FindMine函数的实现

五、代码总览

test.c

game.c

六、关于随机数的产生(即rand函数)

七、总结


该文章中部分知识会在文章末尾进行提及,希望您能耐心看完!

一、扫雷游戏规则介绍

     由玩家选择一个位置进行查看,如果是雷,则游戏结束;如果不是雷,则显示该位置周围相邻的八个位置一共有多少雷,然后玩家继续选择位置,直到玩家找出所有的非雷位置,则扫雷成功,游戏结束。

二、扫雷游戏实现思路分析

     一个基础的扫雷游戏是由一个9*9的棋盘组成的,而雷在棋盘之下,我们由此联想到通过二维数组来实现该棋盘。

     假设我们用1来代表雷,0代表非雷,假如我们点击一个位置后,该位置显示1,我们无法区分该位置代表雷还是该位置代表周围八个位置中有一个雷。

     为了防止这种歧义的产生,我们可以创建两个大小一样的二维数组,一个用来布置雷(mine数组),另一个用来存储返回周围雷的个数这一信息(show数组)。

     那么我们真的是创建两个9*9的二维数组吗?

     答案显然是否定的,如果我们创建一个9*9的数组,当我们查看边界上的位置时,会发现周围部分位置在我们定义的数组之外,这样会造成越界访问,我们还得去判断数组是否越界,这样会大大增加我们代码的繁琐性。

     那么我们如何解决数组越界的问题呢?

     我们如果在原有的基础上左右各加一列,上下各加一行,创建一个11*11的二维数组,这样就可以解决数组越界的问题了。

三、分文件实现扫雷游戏

     将扫雷游戏分为test.c,game.c及game.h进行实现,使得该过程更具体有条理性。test.c文件为扫雷游戏的测试逻辑,game.c和game.h文件为扫雷游戏逻辑的实现。

四、分模块实现扫雷游戏

     测试逻辑的基本架构

void menu()
{

}

void test()
{
	do
	{
		menu();
	} while ();
}

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

该游戏测试逻辑在test函数中实现,test函数中首先通过do while语句实现菜单menu函数的打印

菜单menu函数的实现

void menu()
{
	printf("**************\n");
	printf("*** 1.paly ***\n");
	printf("*** 0.exit ***\n");
	printf("**************\n");
}

test函数基本架构

void test()
{
	int input;
	do
	{
		menu();
		printf("请进行选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
//在game函数中实现扫雷游戏
			break;
		case 0:
			printf("退出游戏成功\n");
			break;
		default:
//default表示的是输入0和1以外的数字时执行该代码
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
//while中通过input进行判断,input为0时条件为假,循环结束;input为其他值时条件为真,循环继续进行
}

开始实现游戏前对部分变量重命名(方便修改数据)

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

创建数组并将其初始化

char mine[ROWS][COLS] = { 0 };//数组全部初始化为'0'
char show[ROWS][COLS] = { 0 };//数组全部初始化为'*'
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');

初始化棋盘函数InitBoard函数的实现

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;
		}
	}
}

打印棋盘函数DisplayBoard函数的实现

void DisplayBoard(char arr[ROW][COL], int row, int col)
{
	int i = 0;
	printf("------扫雷游戏------\n");
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);//打印列号
	}
	printf("\n");
	for (int i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%d ", i);//打印行号
		for (j = 1; j <= col; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}

布置雷的函数SetMine函数的实现

假设在9*9的棋盘上随机布置10个雷

void SetMine(char arr[ROWS][COLS], int row, int col)
{
	int count = easycount;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (arr[x][y] == '0')
		{
			arr[x][y] = '1';
			count--;
		}
	}
}

统计坐标周围雷的数量的函数GetMineCount函数的实现

static 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';
}

排查雷的函数FindMine函数的实现

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0, y = 0, win = 0;
	while (win<row*col-easycount)
	{
		printf("请输入要排查的坐标");
		scanf("%d %d", &x, &y);
		//判断坐标的有效性
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("猜到雷了,游戏结束\n");
					DisplayBoard(mine, ROW, COL);
					break;
				}
				else
				{
					//该坐标不是雷,就得统计坐标周围有几个雷
					int count = GetMineCount(mine, x, y);
					show[x][y] = count + '0';
					DisplayBoard(show, ROW, COL);
					win++;
				}
			}
			else
			{
				printf("该位置已经被排查,请重新输入位置\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
	if (win == row * col - easycount)
	{
		printf("排雷成功\n");
		DisplayBoard(mine, ROW, COL);
	}
}

五、代码总览

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"
void menu()
{
	printf("**************\n");
	printf("*** 1.paly ***\n");
	printf("*** 0.exit ***\n");
	printf("**************\n");
}

void game()
{
	//完成扫雷游戏
	//mine数组中存放布置好的雷的信息
	char mine[ROWS][COLS] = { 0 };//数组全部初始化为'0'
	
	//show数组中存放排查出的雷的信息
	char show[ROWS][COLS] = { 0 };//数组全部初始化为'*'
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	//布置雷
	//在9*9的棋盘上随机布置10个雷
	SetMine(mine,ROW,COL);
	//打印棋盘
	DispalyBoard(show, ROW, COL);
	//排查雷
	FindMine(mine, show, ROW, COL);
}

void test()
{
	int input;
	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);
}

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

game.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"
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[ROW][COL], int row, int col)
{
	int i = 0;
	printf("------扫雷游戏------\n");
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);//打印列号
	}
	printf("\n");
	for (int i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%d ", i);//打印行号
		for (j = 1; j <= col; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}

void SetMine(char arr[ROWS][COLS], int row, int col)
{
	int count = easycount;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (arr[x][y] == '0')
		{
			arr[x][y] = '1';
			count--;
		}
	}
}

static 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';
}

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0, y = 0, win = 0;
	while (win<row*col-easycount)
	{
		printf("请输入要排查的坐标");
		scanf("%d %d", &x, &y);
		//判断坐标的有效性
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("猜到雷了,游戏结束\n");
					DisplayBoard(mine, ROW, COL);
					break;
				}
				else
				{
					//该坐标不是雷,就得统计坐标周围有几个雷
					int count = GetMineCount(mine, x, y);
					show[x][y] = count + '0';
					DisplayBoard(show, ROW, COL);
					win++;
				}
			}
			else
			{
				printf("该位置已经被排查,请重新输入位置\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
	if (win == row * col - easycount)
	{
		printf("排雷成功\n");
		DisplayBoard(mine, ROW, COL);
	}
}
#define _CRT_SECURE_NO_WARNINGS 1

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

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define easycount 10
//声明函数

//棋盘初始化的函数
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);

//打印棋盘
void DisplayBoard(char arr[ROW][COL], int row, int col);

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

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

六、关于随机数的产生(即rand函数)

rand函数返回一个0-32767之间的数字,头文件为#include<stldib.h>

srand(xx);//xx为一个随机变化的值,xx为定值时a也为定值,xx为一个unsigned int类型,即正整数

int a=rand();

调用rand之前通过srand设置一个随机的起点,srand的头文件为#include<stdlib.h>

//时间一直在发生变化,将时间戳传入xx

时间戳设置:

头文件为#include<time.h>

time(NULL)//time为一个整型类型

即为srand((unsigned int)time(NULL));//NULL为空指针

放在主函数中,只需要设置一次

例:如何将随机数控制在1-100之间:

int ret=rand()%100+1;//%100的余数是0-99,再+1达到目标

七、总结

也是写完了关于小游戏的一篇博客,非常感谢您能看完这篇博客,以上内容中如果出现问题,欢迎在评论区提出并指正。

  • 30
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值