如何利用模块化方法制作一个简单的扫雷小项目并且做好代码(隐藏)售出准备(小游戏第三辑)

5a82b3613ec24c23ac25f5132d36f8fd.jpeg

目录

一.引言

二.简介

2.1感想(如果只是想看代码可以移步2.2或者三)

2.2一些单词

三.代码实现

3.1 text.c

3.2 game.h

3.3 game.c

3.3.1 数组初始化

3.3.2 棋盘展示

3.3.3 布置雷

3.3.4 关键函数寻找雷

四.代码隐藏便于售出


一.引言

        不知之前的猜数字小游戏有没有让你汗流浃背呢?还是说你轻松应对了呢!!

        第一辑:猜数字

        第二辑:抽号器

        如果是后者,那不妨挑战一下这个第三辑的难度!!!

        在学完函数章节后,有必要做个完整版的总结归纳了,那么各位同志们,不妨挑战一下做个知识点饱满丰富的扫雷小项目,不仅能加固自标识符到函数的有关知识点,而且还能体会模块化方法的精髓!!!

二.简介

2.1感想(如果只是想看代码可以移步2.2或者三)

        原谅我一个小项目还得搞个简介,主要是想先跟大家分享一下学完这个知识后的感想,这个代码写完后我的最深想法是模块化方法的优秀,层层嵌套,首先我在写最底层的主函数时我会很轻松的写,因为只要写1进入游戏,2退出游戏两个部分,接着在1进入游戏这里去优化game()函数,在这里我明白了学习英语的重要性,所有先给大家普及一下需要知道的英文吧(不要问为什么,问就是查过他们的英文(详见2.2)),ok,在日志我写到game.c包含初始化数组rearray,数组的打印displaybroad,布置雷setmine,以及模拟寻找雷finemine,而在写game()函数的时候,我也是秉承这个想法的一部分一部分写,在这里我只需要想需要几个参数,大概知道各个函数长什么样子,然后去.h中声明即可,这样子不仅加深了我对项目的整体思路,也另我对模块化的部分有了一定的印象,然后我就可以带着自信与方向去敲代码了,敲代码最重要的就是自信与方向,自信是有底气,方向也得对且清晰,所以我想我确实体会到了模块化方法对个人的便利,由于还没与他人共同使用过模块化方法,这里对团队模块化方法先不提。

2.2一些单词

我应该是少数会在文章中写英语单词意思的作者了吧

mine雷 arrary数组 row 行 column列(可简写成col)

本文自创自己看得懂的英文

rearray数组初始化  displaybroad展示棋盘

...(评论区补充吧,打累了)

三.代码实现

3.1 text.c

首先是我们的总测试函数text.c

text.c

#include"game.h"

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

void game()
{
	//创建两个字符数组
	char mine[ROWS][COLS];
	char show[ROWS][COLS];
	//初始化数组
	rearray(mine,ROWS,COLS,'0');
	rearray(show, ROWS, COLS,'*');
	//打印棋盘
	displaybroad(show, ROW, COL);
	//布置雷
	setmine(mine,ROW,COL);
	//displaybroad(mine, ROW, COL);测试用
	//排查雷
	findmine(mine, show, ROW, COL);
}


int main()
{
	int a=0;
	srand((unsigned int)time(NULL));//以时间为种子的随机函数,强制类型转换为unsigned int;
	do {
		menu();
		printf("欢迎安装游戏,请输出数字代表操作:\n");
		scanf("%d", &a);
		switch (a)
		{
		case 1:
			printf("欢迎来到扫雷游戏\n");
			game();
			break;
		case 2:
			printf("按任意键退出游戏!!!\n");
			a = 0;
			break;
		default:
			printf("键入错误,请重新选择!!!\n");
			break;
		}
	} while (a);
	return 0;
}

小小扫雷嘛,测试文件小正常,功能也差不多是这样子,首先是 菜单的打印,int a是为了接住1和2,进行游戏还是退出游戏,然后先设一个srand函数,实现生成随机数,在以时间为种子,是每次生成的随机数都不一样,因为在一些编译程序中rand函数生成的随机数是固定的数,所以导致随机函数不随机,而以时间为种子,可以是随机函数随机,接着正常打出输入流,然后switch解决1,2的选择,这里建议使用0和1做区分来更好的实现while函数,不赘述,用do while结构,先打菜单然后选择,然后判断即可完成

然后如果选择进入游戏,void game()在正式的游戏中我们需要创建两个字符数组来分别表示mine雷的个数数组,show数组是给玩家看的数组,全数组以*填充,这里我们考虑到,以1表示雷,以0表示非雷,我们发现如果雷的个数为1易与雷的表示混淆,所以我们使用两个数组,至于为什么用两个字符数组,相信读者在看完完整代码的时候能有一定的体会,这里卖个关子!

game()函数先初始化两个数组,然后对其中的show数组进行展示,然后开始埋雷,用户开始找雷,然后game()结束

3.2 game.h

game.h

对game函数中的函数进行声明,然后包含主要的库函数,这里为什么主要的库函数都要写在这里呢,主要是text.c和game.c中都有include"game.h"(引用自创的库函数(详细见b站讲解)),所以方便起见就全部都放在这里了,不过在这个头文件中还有对一些常数的定义,emm,这里建议读者在阅读后亲自打完代码然后体会一下,其实这样子设计是有便于优化及后期测试的,不用对一个数字一改再改,只需要对其define也就是定义改一下就行,这就是全局观啊!

代码奉上

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<windows.h>
#define EASY 10
#define ROW 9
#define COL 9

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

void rearray(char a[ROWS][COLS], int rows, int cols, char set);
void displaybroad(char a[ROWS][COLS], int row, int col);
void setmine(char a[ROWS][COLS], int row, int col);
void findmine(char a[ROWS][COLS], char b[ROWS][COLS] ,int row, int col);

这里浅浅解释一下,#pragma once VS自己加的,不解释

第二句防止报错(本文使用了scanf函数)

必要头文件

对常数的定义

函数的声明

ok,对常数你可以先试着不定义#define EASY 10,然后对比前后测试的困难度

3.3 game.c

主角登场!!!game.c

知道你要,所以先上代码!!!!


#include"game.h"

void rearray(char a[ROWS][COLS],int rows,int cols,char set)
{

	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols;j++)
		{
			a[i][j] = set;
		}
	}
}

void displaybroad(char a[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 ", a[i][j]);
		}
		printf("\n");
	}
	printf("************扫雷*************\n");


}


void setmine(char a[ROWS][COLS], int row, int col)
{
	//布置10个雷
	int count = EASY;
	while (count)
	{
		int x = rand() % row + 1;//1-9(原本0-8)
		int y = rand() % col + 1;
		if (a[x][y] == '0')//判定是否已经是雷,防止重复set mine
		{
			a[x][y] = '1';
			count--;//满足设雷条件则雷减1
		}
	}
}

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 + 1]
		+ mine[x][y + 1] + mine[x + 1][y] + mine[x - 1][y + 1] - 8 * '0');


}

void findmine(char a[ROWS][COLS], char b[ROWS][COLS], int row, int col)
{

	int win = 0;
	while (win < row * col - EASY)
	{
			int x = 0;
			int y = 0;
			printf("请输入您要排查的坐标:>\n");
			scanf("%d %d", &x, &y);
			if (b[x][y] != '*')
			{
				printf("键入重复,请重新键入!!!\n");
				continue;
			}
			else if (x >= 1 && x <= row && y >= 1 && y <= col)
			{
		

				if (a[x][y] == '1')
				{
					printf("很遗憾,你被炸死了!!!\n");
					displaybroad(a, ROW, COL);
					break;
				}
				else
				{
					int count= getminecount(a, x, y);//获取雷的个数
					b[x][y] = count + '0';//导入雷的个数
					displaybroad(b, ROW, COL);//打印
					win++;
				}
			}
			else
			{
				printf("键入错误,坐标非法,请重新输入坐标:>\n");
			}
		
	}
	if (win == row * col - EASY)
	{
		printf("恭喜你,排雷成功!!!\n");
		displaybroad(b, ROW, COL);//打印
		printf("下面为您重新返回菜单\n");
	}
}

很好,上了你也得看得懂啊!其实吧,在之前较为复杂的程序中我会每一步进行详细的注释,但是读者可以看到,在game.c中我的注释基本没有,第一就是我的思路清晰,声明就已经等于每个注释了,第二就是这个项目还是在1.0版本,实现逻辑较为简单,代码并非大家看不懂,而且使用的还是较为能理解的一代扫雷代码,没有用循环表示其周围八圈,可谓十分简单!!!

所以为了节省篇幅,现在我们一步一步来讲解

3.3.1 数组初始化

void rearray(char a[ROWS][COLS],int rows,int cols,char set)//这个是我们的数组初始化函数
{

	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols;j++)
		{
			a[i][j] = set;
		}
	}
}

这个是我们的数组初始化函数,比较简单,读者可以想一下为什么要用到三个参数,没错,就是为了少一串代码,一个是数值数组,一个是字符数组,怎么样才能把他们联系在一起,然后一起初始化呢?这时候就直接把数值数组变成字符数组,然后减个0不就行了,然后对所有数组普遍初始化那不就是直接再加一个参数嘛,ok,过

3.3.2 棋盘展示

void displaybroad(char a[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 ", a[i][j]);
		}
		printf("\n");
	}
	printf("************扫雷*************\n");


}

这个是我们的棋盘展示数组,就是几个循环,参数也是来个数组,我只要知道行和列就可以打出来的,较为简单,所以过

3.3.3 布置雷

void setmine(char a[ROWS][COLS], int row, int col)
{
	//布置10个雷
	int count = EASY;
	while (count)
	{
		int x = rand() % row + 1;//1-9(原本0-8)
		int y = rand() % col + 1;
		if (a[x][y] == '0')//判定是否已经是雷,防止重复set mine
		{
			a[x][y] = '1';
			count--;//满足设雷条件则雷减1
		}
	}
}

这个是布置雷函数,先定义要布置几个雷,然后值得注意的是while中的count你也可以写成1,没什么区别,随机生成x,y坐标(表示雷的坐标),这里注意的是rand()%9+1是什么呢,这里的%9结果是0-8,加1就是 1-9,而%10结果是0-9,注意这里的区别,我们的坐标不需要0,然后后面的判断是为了防止重复布置雷,所以使用了一个标志!

3.3.4 关键函数寻找雷

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 + 1]
		+ mine[x][y + 1] + mine[x + 1][y] + mine[x - 1][y + 1] - 8 * '0');


}

void findmine(char a[ROWS][COLS], char b[ROWS][COLS], int row, int col)
{

	int win = 0;
	while (win < row * col - EASY)
	{
			int x = 0;
			int y = 0;
			printf("请输入您要排查的坐标:>\n");
			scanf("%d %d", &x, &y);
			if (b[x][y] != '*')
			{
				printf("键入重复,请重新键入!!!\n");
				continue;
			}
			else if (x >= 1 && x <= row && y >= 1 && y <= col)
			{
		

				if (a[x][y] == '1')
				{
					printf("很遗憾,你被炸死了!!!\n");
					displaybroad(a, ROW, COL);
					break;
				}
				else
				{
					int count= getminecount(a, x, y);//获取雷的个数
					b[x][y] = count + '0';//导入雷的个数
					displaybroad(b, ROW, COL);//打印
					win++;
				}
			}
			else
			{
				printf("键入错误,坐标非法,请重新输入坐标:>\n");
			}
		
	}
	if (win == row * col - EASY)
	{
		printf("恭喜你,排雷成功!!!\n");
		displaybroad(b, ROW, COL);//打印
		printf("下面为您重新返回菜单\n");
	}
}

先讲下面的寻找雷函数,第一个函数是寻找雷的指定函数,所以我用了static去定义,主要是我懒的去声明这个函数,寻找雷故名思意就是输入想找的坐标,反馈是否被炸死,炸死就死的界面,没炸死就显示周围雷的个数,这里还需要考虑用户非法输入,用户输入重复等情况,相信这点小事情就是洒洒水啦,这里重点讲解一下扫雷计数getminecount函数的基本原理

071ab967501f4a83a0cd9ad71f8f5436.png

如果(2,2)是个雷,周围就是以他坐标为中心,8个坐标的总和

32cd4b950925446b98eed742dcc01974.png

是不是这个图有点晕,中间是表示1个雷,左下角是雷,所以我们使用双视角去看这个问题!!!

fc1140f1e9a1408794cca681ea7da681.png

随便画了个草图,差不多吧,第一个图是雷图(数组mine),右图是show数组(用户看到的数组)

所以我们差不多就知道1是周围8个空的和!

计算完后展示,然后设置一个成功标志,但用户把所有的雷找出来后,也就是把所有的非雷布部分都访问了一遍之后,我们就可以停止访问 ,宣布游戏胜利!!!

这就是模块化方法制作出来的扫雷程序,至于我们要如何隐藏我们的代码便于售出

四.代码隐藏便于售出

这里的代码隐藏我们简单讲一下吧,后续会专门出一个专辑,思路就是

读者可以注意到

game.c

game.h

是两个独立的文件,那么只要我们将game.c变成一个静态库.lib,那么向购买方我们只需提供一个.lib和一个函数声明的头文件即可!!

emm一个简单的隐藏,这主要是得益于我们将所有的关键代码都写在了game.c中,ok,我们代码隐藏就在这里讲个大概,更加深奥,有效的隐藏往往更加高明,下次再讲,see you next essay!

本资源提供免费下载:

源码

  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值