IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 用C语言实现小游戏之——【扫雷】 -> 正文阅读

[C++知识库]用C语言实现小游戏之——【扫雷】

用C语言实现一个简易的扫雷小游戏!

【游戏要求】

【扫雷游戏】:

  1. 布置雷——10个
  2. 扫雷:输入坐标

? ? ? ? ? ? ? ? ? ? 是雷->炸死!游戏结束!

? ? ? ? ? ? ? ? ? ? 不是雷->告诉你这个坐标周围8个坐标上共有多少个雷。

? ? ? ? ? ? ? ? ? ? 直到把所有非雷的位置全部都找出来,则扫雷成功!游戏结束!


【代码实现】

※与上一篇博客中类似,这个游戏的代码也将分模块完成!即分成游戏的函数实现(game.c)、函数声明和符号定义(game.h)、测试(test.c)三个部分

首先是在test.c中编写一个简易的开始菜单。用do...while循环获取正确的输入,用switch...case判断开始游戏、退出游戏或者是重新选择。

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

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

接着我们要布置雷。我们如何存储数据呢?我们可以用数组(9*9 二维数组)来存储,将数组中雷的地方设置为1,非雷的地方设置为0即可,但这就会与点开之后表示周围有一个雷的1混淆,有歧义。我们可以更换雷和非雷的标记为*和#来解决这一问题,但这样打印的时候就需要经过筛选,雷的地方不能打印为雷,挺麻烦的。于是我们采用【两个数组】的方法来解决。我们再单独搞一个数组,两个数组一样大,坐标也相对应。一个是专门用来打印的(排查出的雷的信息,未排查出的用*表示)数组char show[][],另一个是专门用来存放雷(‘1’)或非雷(‘0’)的(布置好的雷的信息)数组char mine[][]。现在我们需要解决另外一个问题。因为要显示周围一圈的雷的个数,所以要遍历周围八个位置,但如果是边界上的格子的话就会有越界的问题,对于数组来说是越界访问。那么我们该如何解决这一问题呢?既然害怕边界的越界,那就不如【多开辟一圈】数组,即在原先的基础上多了两行两列。9*9->11*11,真正用的是中间9*9的,检测雷的数量的数量时就不会越界了。那么我们就可以在game.h中define ROW和COL为9,define ROWS和COLS为11。

然后就可以重点写game()函数了。首先要定义两个数组,然后将数组【初始化】。我们可以用编写一个函数来实现数组的初始化。因为show数组(初始化为‘0’)和mine数组(初始化为‘*’)的初始化内容不一样,所以我们在编写函数的时候可以把初始化内容作为函数的一个参数来使用,定义void init_board(char arr[ROWS][COLS], int rows, int cols, char set)。

void init_board(char arr[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++)
		{
			arr[i][j] = set;
		}
	}
}

然后我们需要【打印棋盘】,我们定义另外一个函数来打印棋盘(只打印9*9)。为了增强游戏的可玩性,我们将在打印部分的第一行和第一列加上行列的序号,这样可以更清楚。

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

可以实现这样的效果:

?


接下来我们就要【布置雷】了,我们将用一个set_mine函数来实现,只需要在中间9*9的区域布置雷即可。我们可以先在game.h中定义符号常量EASY_COUNT为10,表示这个扫雷游戏将设置十个雷。我们选择用随机数来生成电脑放置雷的位置。随机数使用了rand()和srand()和时间戳,具体原理可见我的上上篇博客中关于随机数的介绍哦~首先要在我们的test函数里的do...while的循环之前用srand((unsigned int)time(NULL)),并在game.h中添加相关头文件(stdlib.h 和 time.h)然后就可以在布置雷的函数中用rand()函数生成随机数来布置雷了~

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

可以将mine数组打印出来检查一下:

?


接下来我们就要开始【排查雷】了,可以写一个find_mine(mine, show, ROW, COL)函数来排查雷。首先是要获取要排查的雷的坐标,然后判断其是否合法,不合法的话要重新输入,所以这里需要一个循环,循环跳出的条件为将所有非雷的地方全部打开,因此我们用一个变量win来计数。输入正确坐标之后排查这个地方,若这个地方是雷,则被炸死游戏结束!如果不是雷,则遍历周围八个坐标统计雷的个数(我们可以另外定义一个函数来计算这个值),然后将数值放在show数组中,并打印目前的show数组,变量win+1,最后判断是否全部扫完继续或跳出循环。

代码实现如下:

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

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<row*col-EASY_COUNT)
	{
		printf("请输入要排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,被炸死了!\n");
				show_board(mine, ROW, COL);
				break;
			}
			else
			{
				int count = get_mine_count(mine, x, y);
				show[x][y] = count + '0';
				show_board(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,重新输入!\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
		show_board(mine, ROW, COL);
	}
}

【小结】

我们这个小游戏用到的符号常量、定义的函数和头文件大致有这些

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

#define ROW 9
#define COL 9
#define EASY_COUNT 10

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

//初始化
void init_board(char arr[ROWS][COLS], int rows, int cols, char set);

//打印
void show_board(char arr[ROWS][COLS], int row, int col);

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

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

test.c中则是游戏执行的框架

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

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

}

void game()
{
	//扫雷游戏的实现
	char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
	char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
	//初始化棋盘
	init_board(mine, ROWS, COLS, '0');
	init_board(show, ROWS, COLS, '*');
	//打印棋盘
	show_board(show, ROW, COL);
	//布置雷
	set_mine(mine, ROW, COL);
	//排查雷
	find_mine(mine, show, ROW, COL);
}

int main()
{
	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);
	return 0;
}

具体的函数的代码都在上文中啦~祝大家阅读愉快~

另:游戏有两个部分可以进行优化升级:第一是关于【展开一片】的问题,可用递归实现(只要满足该坐标不是雷且周围八个都不是雷则可展开,被展开的坐标又可作为新的起点继续展开。但被展开过的应该做个标记,下次递归到的时候不再递归。也就是满足不是雷且周围八个不是雷且没被排查过即可展开一片。)第二是关于【标记雷】的实现。这些都是该代码可进行的优化~

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-01-25 10:24:21  更:2022-01-25 10:25:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:28:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码