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语言>)

目录

一、扫雷简介

二、游戏目标

三、代码逻辑(附流程图)

?四、代码实现

0.创建项目

?1.创建菜单

2.创建数组

3.初始化数组

4.设置雷区

5.打印界面?

6.扫查雷区

7.尾声


一、扫雷简介

? ? ? ?扫雷可谓是一款非常大众的休闲益智游戏,当弟弟妹妹缠着你外出买玩具的时候,何不快来写一个扫雷程序,既能让他们体验扫雷的刺激与快感,又可以让自己抽出身来做自己想做的事情呢?想必此刻你已经被弟弟妹妹折腾得十分焦灼了,那赶紧在键盘上敲起来吧~

二、游戏目标

把系统设置好的雷完全扫除。

附雷诀八条:

第一条:基本定式不要忘,现场推理真够呛。

第二条:鼠标点击不要快,稳定节奏把空开。

第三条:顺手标雷不要惯,积累下来记录悬。

第四条:无从下手不要愣,就近猜雷把心横。

第五条:遇到猜雷不要怕,爆了脸上不留疤。

第六条:猜雷猜错不要悔,哭天抢地也白费。

第七条:碰上好局不要慌,紧盯局部慢扩张。

第八条:痛失好局不要恨,既然有缘定有份。

三、代码逻辑(附流程图)

咱再来简单梳理一下流程:

1.创建菜单(毕竟要让弟弟妹妹玩也要询问人家是否同意嘛QwQ)

2.创建数组(找好场地)

3.初始化数组(整理场地)

4.设置雷区(埋雷呗~)

5.打印界面(盖上草皮/沙土/苞米杆子?)

6.扫查雷区

?四、代码实现

0.创建项目

? ? ? ?在扫雷这项工程里我们同样需要创建三个项目:源文件扫雷.c、game.c和头文件game.h。其中源文件扫雷.c用于实现整个游戏的逻辑,源文件game.c用于函数定义,头文件game.h用于宏定义、函数声明等,创建如下图。

?1.创建菜单

? ? ? ?进入游戏后当然要有一个选择菜单啦。我们直接在源文件扫雷.c创建一个菜单函数即可,你可以根据自己的喜好敲出有特色的菜单,这里制作的菜单就先简朴一些啦~废话不多说,上代码:

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

至于各种头文件的声明我们一并放在头文件game.h中,只需在各个源文件声明一下#include "game.h"即可。想了解声明的具体使用可以去康康我之前在三子棋程序制作中的讲解:

https://blog.csdn.net/MISTER_a/article/details/119558952?spm=1001.2014.3001.5501

2.创建数组

在创建数组之前呢,我们先来架构一下main函数的逻辑。

2.1

? ? ? ?说来其实也简单,main函数的逻辑不过是进入菜单后进行选择,因此我们要创建一个变量input用来接受玩家的选择,这里要用到库函数scanf,由于scanf并不安全,我在之前的博客已经讲过修复的方法,不了解的小伙伴还请移步:https://blog.csdn.net/MISTER_a/article/details/119558952?spm=1001.2014.3001.5501,这里就不赘叙啦。输入的情况也无非三种:输入1、输入0或者输入其它数字。输入1则直接进入游戏函数Game,在玩完游戏时还能进入菜单,觉得不过瘾再来几把,不想玩了就可以选择退出游戏;输入0则直接退出游戏;输入其它数字则提示玩家输入错误,需让其重新返回菜单输入。

? ? ? ?因此对于进入菜单进行选择后的进程,我们用分支语句switch处理;由于某些情况还要返回菜单再次选择,我们用循环语句do...while处理;而输入0直接退出游戏,这里我们直接用while(input)进行判断即可,由于0为假,非0为真,input为0则直接跳出循环,非0则进入循环。代码如下:

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

2.2

? ? ? ?完成了main函数的架构,我们开始编写负责游戏主要功能的Game函数。同样Game函数我们放在源文件扫雷.c即可。

? ? ? ?在Game函数中,我们首先要创建两个二维数组mine(地雷)和show(展示)。其中mine数组用于玩家在扫雷前进行埋雷,而show数组就相当于地雷之上的地皮,在玩家未踩雷时标明周围有几个雷。我们扫雷的区域是9*9的方格,由于边沿的格子在检索自己周围八个小方格的时候会越界,所以我们索性创建11*11的方格,但是只用中间9*9的部分即可。

为了方便日后修改,我们在头文件game.h中用define定义四个常量,如图所示

?我们在Game函数中创建的两个字符类型的数组如图所示

?创建完数组,我们就有可以扫雷的地盘啦。

3.初始化数组

? ? ? ?对两个数组分别进行初始化对应两个不同的目的。对mine数组初始化可以理解为埋雷,而对show数组初始化可以理解为蒙上地皮,并且在扫雷时用于标注周围雷的个数。

? ? ? ?对数组进行初始化也很简单,我们把mine数组中每个元素都初始化为字符'0',show数组中每个元素都初始化为字符'*'。因此我们要写一个函数Initboard,该函数的定义放在源文件game.c中,在头文件game.h中声明。

? ? ? ?由于数组的每个元素都要初始化,我们用for循环嵌套进行处理,因此我们要把数组行和列的参数都传过去。此外由于不同的数组初始化的字符不同,我们把每个数组要初始化的字符一并传过去。代码如下:

void Initboard(char board[ROWS][COLS], int row, int col,char character)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			board[i][j] = character;
		}
	}
}

4.设置雷区

? ? ? ?在游戏我们先计划布置10个雷,同样用define在头文件game.h中定义MINE为常量10,这样以后想要更改雷的个数也十分方便。我们写一个函数Setboard用于布置雷区,也是在源文件game.c中定义,在头文件game.h中声明。

? ? ? ?我们来思考一下函数Setboard该如何实现。首先得有雷,数量是10个,那雷该怎么表示呢?嘿嘿,这里的雷先用字符‘1’表示吧,之后会有大用,这里先卖个关子。然后十个雷是随机布置在场地中的,我们需要生成不同的随机数确定10个雷的坐标。对于随机生成的数字,我们当然要用时间戳啦~

? ? ? ?好了,这样就非常清晰明了了。我们先在main函数里贴个时间戳srand((unsigned int)time(NULL));并在头文件game.h中声明调用库函数,贴上#include <stdlib.h>和#include <time.h>。我们创建两个变量x、y分别对应横纵坐标。由于我们要生成的横纵坐标的范围都在1~9闭区间里,因此我们只要让生成的随机数模上9取余数再加1即可,即int x = rand() % 9 + 1; int y = rand() % 9 + 1;为了保证生成的坐标不会重合,我们需要用if语句进行判断,并且在每成功设置一个雷后,接下来要设置的雷的个数都会减1。代码如下:

void Setboard(char board[ROWS][COLS])
{	
	int count = MINE;
	while (count)
	{
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (board[x][y] != '1')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

然后各文件对应的改变分别如下:

game.h

game.c

扫雷.c

5.打印界面?

? ? ? ? ?布置完雷区后,我们就要打印出界面,让玩家感受紧张刺激的扫雷啦。

? ? ? ? ?我们要打印的是数组show,打印函数我们就称为Display吧,在源文件game.c中定义,头文件game.h中声明。同样是显示数组中的每个元素,因此使用for循环嵌套即可,代码如下:

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);
		for (j = 1; j <= COL; j++)
		{
			if (i == 0)
			{
				printf(" %d ", j);
			}
			else
			{
				printf(" %c ", board[i][j]);
			}
		}
		printf("\n");
	}
}

打印完每一行后别忘记换行哦!

6.扫查雷区

? ? ? ?想要扫查雷区,我们需要输入坐标来扫查对应的位置。我们创建两个变量x、y来对应接收输入的横纵坐标,而对于接收的坐标也是给出三种反应:

a.若该位置埋雷,则直接被炸没惹,并显示出埋雷情况,让玩家没的明白,然后返回开始菜单。

b.若该位置无雷,则应显示周围八个位置的埋雷情况,并在该位置标注个数,让玩家能更谨慎地进行扫雷活动,进而开始下一步行动。

c.若输入的坐标不在指定范围内,则应提醒玩家并让其重新输入坐标。

? ? ? ?为了实现以上逻辑,显然需要分支语句if,而整体的架构又需要放在一个循环中,这里我们用while循环即可。

? ? ? ?那么无雷时的情况标明该如何实现呢?这里我们创造一个函数Count,设置其返回类型为整型,同样在源文件game.c中定义,在头文件game.h中声明。

? ? ? ?至于如何统计周围八个位置的雷的个数,这里我们就用到了之前卖的关子。由于埋雷时使用的字符‘1',我们只需要把周围八个位置的1加起来就可以得到雷的个数,但是这里我们用的是符'1',那该如何转化为整型呢?

? ? ? ?其实也不难,根据ASCll表我们得知,字符‘1’对应的十进制数为49,而字符‘0’对应的十进制数为48,因此我们只要用字符‘1’减去字符‘0’就可以得到整型1啦。换言之,字符数字减去字符‘0’就可以得到它对应的整型。废话不多说,上图上代码:

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

这里直接暴力把周围八个位置加起来就可以啦,因为有八个字符'1'相加,所以我们要减去8*'0'。当然上述算法你也可以用for循环来实现。

Game函数的架构也基本完成啦,对于踩雷后如何跳出循环嵌套,笔者这里就直接用goto语句了,代码如下:

void Game()
{
	char mine[ROWS][COLS];
	char show[ROWS][COLS];
	Initboard(mine, ROWS, COLS,'0');
	Initboard(show, ROWS, COLS,'*');
	Setboard(mine);
	Displayboard(show, ROWS, COLS);
	while (1)
	{	
		int count = MINE;
		
			while (count > 0)
			{
				int x = 0;
				int y = 0;
			
				printf("请输入(row col):");
				scanf("%d%d", &x, &y);
				
				if (x > 0 && x <= ROW + 1 && y > 0 && y <= COL)
				{
					if (mine[x][y] == '1')
					{
						printf("踩雷了,游戏结束\n");
						Displayboard(mine, ROWS, COLS);
						goto again;
					}
					else
					{
						int ret = Count(mine, x, y);
						show[x][y] = ret + '0';
						Displayboard(show, ROWS, COLS);
						count--;
					}
				}
				else
				{
					printf("非法输入,请重新输入\n");
				}
			}		
	}
again:;
}

7.尾声

到这里我们整个工程就已经彻底完成啦。快来让你的弟弟妹妹试一试吧~说不定弟弟妹妹一上瘾,你都能抽出一整天的时间出去约会了呢~

这里我们让程序跑起来康康QwQ

好像也还阔以喔。至于函数递归和倒计时的设计,我们以后有时间再聊叭,要洗洗睡了呢= =估计目前这些应付弟弟妹妹也应该游刃有余叭。

最后贴上整个工程的代码:

game.h

#pragma once

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

#define ROWS 11
#define COLS 11
#define ROW ROWS-2
#define COL COLS-2
#define MINE 10

void Initboard(char board[ROWS][COLS], int row, int col, char character);
void Setboard(char board[ROWS][COLS]);
void Displayboard(char board[ROWS][COLS], int row, int col);
int Count(char board[ROWS][COLS], int x, int y);

?game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void Initboard(char board[ROWS][COLS], int row, int col,char character)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			board[i][j] = character;
		}
	}
}
void Setboard(char board[ROWS][COLS])
{

	int count = MINE;
	while (count)
	{
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (board[x][y] != '1')
		{
			board[x][y] = '1';
			count--;
		}
	}
}
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);
		for (j = 1; j <= COL; j++)
		{
			if (i == 0)
			{
				printf(" %d ", j);
			}
			else
			{
				printf(" %c ", board[i][j]);
			}
		}
		printf("\n");
	}
}
int Count(char board[ROWS][COLS], int x, int y)
{
	return (board[x - 1][y - 1] +
		board[x - 1][y] +
		board[x - 1][y + 1] +
		board[x][y - 1] +
		board[x][y + 1] +
		board[x + 1][y - 1] +
		board[x + 1][y] +
		board[x + 1][y + 1]-8*'0');
}

扫雷.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];
	char show[ROWS][COLS];
	Initboard(mine, ROWS, COLS, '0');
	Initboard(show, ROWS, COLS, '*');
	Setboard(mine);
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		Menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("扫雷\n");
			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语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-13 11:45:37  更:2021-08-13 11:48:01 
 
开发: 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年5日历 -2024/5/21 3:43:33-

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