WEB视频自适应 Eclipse插件 树莓派USB datetime session web mongoose video razor orm rspec download Parsley 管理后台模板 android项目实战 网校直播系统 datetimepicker赋值 solr索引 oracle连接字符串 郑州普通话 python如何实现多线程 python环境配置 python教程 python中def的用法 python学习教程 python指令 java运算符 java基础数据类型 java集合转数组 java泛型的使用 linux系统安装 猫爪 蒙文字体 raid0教程 js刷新页面 js日期格式化 js关闭当前页面 ps制作表格 数组求和 国都证券官网下载
当前位置: 首页 > 学习教程  > 编程语言

C语言实现扫雷小游戏(上)

2021/2/13 18:31:15 文章标签: 测试文章如有侵权请发送至邮箱809451989@qq.com投诉后文章立即删除

业精于勤,荒于嬉;行成于思,毁于随。   2021农历辛丑牛年,祝所有人心想事成,万事胜意!   二维数组练习第二弹,实现扫雷小游戏。 文章目录一、扫雷游戏规则二、游戏流程三、扫雷游戏的双层数组…

  业精于勤,荒于嬉;行成于思,毁于随。
  2021农历辛丑牛年,祝所有人心想事成,万事胜意!
  二维数组练习第二弹,实现扫雷小游戏。


文章目录

  • 一、扫雷游戏规则
  • 二、游戏流程
  • 三、扫雷游戏的双层数组
    • 两个二维数组
    • 布雷数组巧妙的设计
  • 四、程序设计
    • 头文件
    • 游戏实现框架
    • 功能函数
      • InitBoard
      • DisplayBoard
      • SetMine
      • FindMine
  • 五、完整程序
  • 六、游戏测试
  • 七、写在后面


一、扫雷游戏规则

  把所有非地雷的格子揭开即胜利,踩到地雷格子即失败。


二、游戏流程

电脑打印游戏菜单(1.开始游戏 0.退出游戏)——>玩家选择(开始游戏——>进入游戏函数)——>电脑打印出雷盘——>玩家输入需要排雷的坐标——>可能性1:被炸死 可能性2:坐标安全,系统显示出周围八个格子内的地雷总数——>雷盘更新——>玩家输入需要排雷的坐标,继续排雷——>游戏胜利


三、扫雷游戏的双层数组

  前文有写到三(多)子棋小游戏,三子棋游戏只需要一个数组就够了,但是对于扫雷游戏的实现,一个数组是不够的,需要创建两个数组。


两个二维数组

  第一个数组,存放雷的分布信息,面向游戏设计者创建,暂且称之为雷盘布置数组,简称布雷数组,如下所示。

0 1 2 3 4 5 6 7 8 9
1 0 0 0 0 0 1 0 1 0
2 0 0 0 0 0 0 1 0 0
3 0 1 0 0 0 0 1 1 0
4 0 0 0 0 0 0 0 0 0
5 0 0 0 0 1 0 0 0 0
6 0 0 0 0 0 0 0 0 0
7 0 0 0 0 1 0 0 0 0
8 0 1 0 0 0 0 1 0 0
9 0 0 0 0 0 0 0 0 0

  第二个数组,存放排雷后的雷盘中雷的分布个数信息,面向玩家创建,暂且称之为玩家数组,如下所示。

0 1 2 3 4 5 6 7 8 9
1 * * * * * * * * *
2 * * * * * * * * *
3 * * 1 * * * * * *
4 * * * * * * * * *
5 * * * * * * * * *
6 * * * * * * * * *
7 * * * * * * * * *
8 * * * * * * * * *
9 * * * * * * * * *

布雷数组巧妙的设计

  程序设计的时候,需要判断玩家坐标周围八个格子中雷的总个数,那么这就带来一个问题:
  玩家选择边角最外环的一层坐标和玩家选择内环坐标判断方法不同。目测有两种解决方案。
  第一种:加if判断

如果是最外面的一圈的就单独拉出来判断其周围的雷的总数,但是这又导致了一个问题,四个角和每条棱的判断方法各不相同,所以这个解决方案很繁琐。

  第二种:巧妙地让布雷数组膨胀一圈

假设让布置雷的雷盘是11X11规格的,但是只在9X9的格子里布雷,那么对于每个9X9格子里的坐标,判断周围格子里雷的总数的算法都是一样的。(把巧妙打在公屏上!!!)


四、程序设计

  创建三个文件,game.h 游戏的头文件functions.c游戏所用到功能函数 game.c 游戏框架 三个文件。


头文件

  头文件的书写是一步一步需要什么写什么建立而来的,这里先把所有的宏定义、库函数引用、函数声明放这里,后面用到会有解释。

#define _CRT_SECURE_NO_WARNINGS 1

#define ROW 9
#define COL 9

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

#define EASY_COUNT 10

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

void test(void);
void menu(void);
void game(void);

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

游戏实现框架

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "game.h"

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

//游戏执行测试框架
void test(void)
{
	int input = 0;

	do {
		menu();//系统打印游戏菜单,调用menu函数

		printf("请选择:>>>");
		scanf("%d", &input);

		switch (input)//switch开关语句,作用显而易见
		{
		case 1:
			game();//调用game函数
			break;
		case 2:
			printf("退出游戏\n");
			input = 0;
			break;
		default:
			printf("输入值无效\n");
			break;
		}

	} while (input);
}

//菜单打印函数
void menu(void)
{
	printf("************************************\n");
	printf("*****1.开始游戏     0.退出游戏******\n");
	printf("************************************\n");
}

//游戏主函数
void game(void)
{
	//第一步,创建两个数组,一个是布盘数组,一个是用户数组
	//两个数组大小相同,属于叠加的双层结构。
	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);//更新打印好后的雷盘
	//第四步,扫雷
	FindMine(mine, show, ROW, COL);
}

功能函数

  游戏主函数中除游戏框架外的所有函数,习惯单独写在一个文件里。


InitBoard

  数组创建好,需要对两个数组进行初始化,但是因为两个数组初始化的分辨元素不一样,所以这里加入一个调用参数set。

//初始化函数
void InitBoard(char board[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++)
		{
			board[i][j] = set;//让布雷数组全部元素为字符'0',玩家数组全部为字符'*'
		}
	}
}

DisplayBoard

  初始化函数写好之后可以先写雷盘打印函数进行核验,所以先介绍DisplayBoard函数。

//雷盘打印
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;

	printf("\n");//打印个换行符分割下,不是必要

	//打印列号
	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");//打印个换行符分割下,不是必要
}

SetMine

  数组初始化好就要布置雷了,采用随机值的方法进行布雷,传递整个数组,但需要控制雷的分布只出现在内环9*9的网格里。

//布置雷盘
void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	srand((unsigned int)time(NULL));//使用系统时间作为随机值的种子

	while (count)//控制雷的个数
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;

		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

FindMine


  进行扫雷,如果玩家踩雷就被炸死,未踩雷,系统报告周围雷的个数。

//扫雷
void FindMine(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啊哦,你被炸死了!!!\n");
				DisplayBoard(mine, row, col);
				break;
			}
			else
			{//计算周围8个方块中雷的总数
				int count = (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';
				show[x][y] = count + '0';
				DisplayBoard(show, row, col);
				win++;//玩家输入一次win加一次,等到棋盘上只有雷就胜利了
			}
		}
		else
		{
			printf("非法输入!!!\n");
		}
	}
}

五、完整程序

#define _CRT_SECURE_NO_WARNINGS 1

#define ROW 9
#define COL 9

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

#define EASY_COUNT 10

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

void test(void);
void menu(void);
void game(void);

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);
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "game.h"

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

//游戏执行测试框架
void test(void)
{
	int input = 0;

	do {
		menu();//系统打印游戏菜单,调用menu函数

		printf("请选择:>>>");
		scanf("%d", &input);

		switch (input)//switch开关语句,作用显而易见
		{
		case 1:
			game();//调用game函数
			break;
		case 2:
			printf("退出游戏\n");
			input = 0;
			break;
		default:
			printf("输入值无效\n");
			break;
		}

	} while (input);
}

//菜单打印函数
void menu(void)
{
	printf("************************************\n");
	printf("*****1.开始游戏     0.退出游戏******\n");
	printf("************************************\n");
}

//游戏主函数
void game(void)
{
	//第一步,创建两个数组,一个是布盘数组,一个是用户数组,两个数组大小相同,属于叠加的双层结构。
	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);//更新打印好后的雷盘
	//第四步,扫雷
	FindMine(mine, show, ROW, COL);
}
#include "game.h"

//初始化函数
void InitBoard(char board[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++)
		{
			board[i][j] = set;//让布雷数组全部元素为字符'0',玩家数组全部为字符'*'
		}
	}
}

//打印雷盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;

	printf("\n");//打印个换行符分割下,不是必要

	//打印列号
	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");//打印个换行符分割下,不是必要
}

//布置雷盘
void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	srand((unsigned int)time(NULL));//使用系统时间作为随机值的种子

	while (count)//控制雷的个数
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;

		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

//扫雷
void FindMine(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啊哦,你被炸死了!!!\n");
				DisplayBoard(mine, row, col);
				break;
			}
			else
			{//计算周围8个方块中雷的总数
				int count = (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';
				show[x][y] = count + '0';
				DisplayBoard(show, row, col);
				win++;//玩家输入一次win加一次,等到棋盘上只有雷就胜利了
			}
		}
		else
		{
			printf("非法输入!!!\n");
		}
	}
}

六、游戏测试

  这里将ROWCOL更改成3EASY_COUNT改成了5进行测试。

************************************
*****1.开始游戏       0.退出游戏******
************************************
请选择:>>>1

0 1 2 3
1 1 1 0
2 1 0 1
3 0 0 1


0 1 2 3
1 * * *
2 * * *
3 * * *

请输入排查雷的坐标:>>>1 1

啊哦,你被炸死了!!!

0 1 2 3
1 1 1 0
2 1 0 1
3 0 0 1

************************************
*****1.开始游戏       0.退出游戏******
************************************
请选择:>>>1

0 1 2 3
1 0 1 1
2 1 0 1
3 0 1 0


0 1 2 3
1 * * *
2 * * *
3 * * *

请输入排查雷的坐标:>>>2 2

0 1 2 3
1 * * *
2 * 5 *
3 * * *

请输入排查雷的坐标:>>>1 1

0 1 2 3
1 2 * *
2 * 5 *
3 * * *

请输入排查雷的坐标:>>>3 1

0 1 2 3
1 2 * *
2 * 5 *
3 2 * *

请输入排查雷的坐标:>>>3 3

0 1 2 3
1 2 * *
2 * 5 *
3 2 * 2


恭喜你,历经千辛万苦排雷成功!
    
************************************
*****1.开始游戏     0.退出游戏******
************************************
请选择:>>>

七、写在后面

  总的来说,这个程序只用了四个功能函数(处游戏框架外)实现了基本的扫雷程序,但是游戏还是非常鸡肋的,在真正的扫雷游戏中,当玩家选择的坐标周围八个坐标均没有雷时雷盘会之间展开,这还是很必要的,因为当扫雷的棋盘很大时,一个一个的选择坐标实属太没有游戏体验了,这个需要加入一个递归展开函数。
  加入递归展开后,游戏胜利判断条件也需要改变,相对复杂,所以写在了下一篇博客,欢迎各位大佬进行检阅、批评和指正,非常感谢!!!非常感谢!!!


本文链接: http://www.dtmao.cc/news_show_700257.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?