C语言:程序打包超详细教程和简单的游戏设计(猜数字和扫雷)

🚀write in front🚀
🔎大家好,我是翻斗花园牛爷爷★。希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎
🆔本文由 翻斗花园牛爷爷★ 原创 CSDN首发🐒 如需转载还请通知⚠
📝个人主页:翻斗花园牛爷爷★—CSDN博客
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​
📣系列专栏:翻斗花园牛爷爷★的系列专栏——CSDN博客
✉️我们并非登上我们所选择的舞台,演出并非我们所选择的剧本

目录

程序打包

第一个小游戏:猜数字

思路

实现

第二个小游戏:扫雷

实现流程

准备工作

具体步骤

1.打印主菜单

2.初始化棋盘

3.打印棋盘

4.布置雷

5.排雷

完整代码


程序打包

        很多小伙伴说了,游戏写好了,但是不知道怎么发给别人。因此在学习两个游戏前,先带大家了解一下如何将写好的程序打包成exe文件;

       工具:VS2022

1.首先打开VS2022,打开拓展

2.选择管理拓展,再搜索install;下载箭头所指的包。

 3.然后关闭VS所有的程序,包就会开始自动下载,下载完之后,重新进入VS;按照箭头指向进行。

 4.搜索Setup Project

 5.选择路径,这里我把它放到桌面上了

 6.出现类似这个界面,右键第一个,先添加想要打包的.c文件

 7.再选择项目输出,然后确定

8.回到解决方案资源管理器那里,右键setup,选择重新生成

9.此时回到桌面,打开setup1的文件夹,发现有两个,用Dubug进行调试的,就在Dubug里,反之就在Release里,我的在Release里

 10.发现生成了安装包,打开第一个,进行安装。路径选到了桌面

11.第一个就是你打包的文件了,之后你可以将这些再打包成压缩包发给朋友们



第一个小游戏:猜数字

思路

        1.首先我们可以根据游戏名字知道既然是猜数字,那麽一定是随机的数。因此可以得知用到rand函数,rand生成的是伪随机数,是根据srand设置的一个返回起点返回一个随机值,这个起点也叫随机数种子,rand就是根据随机数种子为基准来计算随机数的,且默认种子为1。srand是随机数发生器的初始化函数;

        2.还要了解一个知识,关于时间戳的认识:从计算机诞生到现在时间的秒数,持续变化,是个随机值。

        3.因为rand要返回一个随机数,而起点默认为srand设置,因为rand是根据随机数种子为基准来计算随机数的,所以为我们想让它生成不同的随机数,就是要让种子也随机。因此可以在srand函数中需要放一个随机数,所以通过时间戳来生成随机数放入srand函数中。这时利用了time函数

        4.当然漫无目的的猜数不是我们的目的,因此我们可以缩小猜数的范围rand()%100+1,把它的范围设立到1-100.如果想生成0-99间的话,就是rand()%100;如果想生成100-200间的话,就是rand()%100+(200-100+1);所以我们如果想要自定义随机数的范围,可以这样写rand()%100+(b-a+1),即为a-b的范围。

实现

1.先编写菜单页面

void menu() //函数调用
{
	printf("----------------------------------\n");
	printf("--------1.game------2.exit--------\n"); //表示两个选择
	printf("----------------------------------\n");
}

2.  编写游戏流程

void game() //函数调用
{
	int num, input;
	num = rand() % 100 + 1; //限定随机数范围
	while (1) //无限循环
	{
		printf("请输入数字\n");
		scanf_s("%d", &input); 
		if (num == input)
		{
			printf("恭喜,你猜对了\n");
			break;
		}
		else if (num < input)
		{
			printf("你猜大了");
		}
		else
		{
			printf("你猜小了");
		}
	}
}

3.编写主程序

int main()
{
	int choice;
	srand((unsigned int)time(NULL));
	do        //do...while在这里可以让游戏多次玩
	{
		menu();
		printf("请输入正确的选项:\n"); scanf_s("%d", &choice);
		switch (choice)  //选择1,进入游戏,0则退出程序,其他数字则显示错误,并重新输入。
		{
		case 1:game();
			break;
		case 0:
			break;
		default:
			printf("错误,请输入正确的数字");
			break;
		}
	} while (choice);
	return 0;
}

4.完整代码

#include <stdio.h>
#include <windows.h>
#include <time.h>
void game()
{
	int num, input;
	num = rand() % 100 + 1;
	while (1)
	{
		printf("请输入数字\n");
		scanf_s("%d", &input);
		if (num == input)
		{
			printf("恭喜,你猜对了\n");
			break;
		}
		else if (num < input)
		{
			printf("你猜大了");
		}
		else
		{
			printf("你猜小了");
		}
	}
}
void menu()
{
	printf("----------------------------------\n");
	printf("--------1.game------2.exit--------\n");
	printf("----------------------------------\n");
}
int main()
{
	int choice;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请输入正确的选项:\n"); scanf_s("%d", &choice);
		switch (choice)
		{
		case 1:game();
			break;
		case 0:
			break;
		default:
			printf("错误,请输入正确的数字");
			break;
		}
	} while (choice);
	return 0;
}


第二个小游戏:扫雷

        扫雷这个游戏大家可谓是耳熟能详,当年可是风靡全网;很多小伙伴都好奇它是怎末实现的,今天我就为大家带来初级版的扫雷游戏;

游戏规则

              

          输入一个坐标,如果有雷,那么就会被炸死,游戏失败,重新开始。如果没有雷,则继续,并会在坐标处显示出周围八个格子的雷的数量。根据这个不断排雷,直到所有雷排除,游戏胜利。

 

实现流程


准备工作

        首先,要先创建两个.c文件:game.c和test.c;分别存储游戏实现部分和主函数部分的代码;再创建头文件game.h,用于存放函数声明;


具体步骤

        我们已经知道了扫雷的流程,但是我们应该如何实现它呢???

不要着急,慢慢来;首先我们进入游戏应该有一个主菜单吧;而主菜单如何打印呢,我们在上面猜数字的游戏里其实已经学习过了,它们的框架其实都差不多。


1.打印主菜单

       首先,我们要有进入和退出游戏两个选项吧,我们设立1为进入游戏;0为退出游戏;

void menu()
{
	printf("----------------------------\n");
	printf("-----------1.game-----------\n");
	printf("-----------2.exit-----------\n");
	printf("----------------------------\n");
}

再写出主函数,来进行调用

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));//先不要管,后面会讲到,为什莫用它
	do
	{
		menu();
		printf("请选择:");
		scanf_s("%d", &input);
		switch (input)
		{
		case 1:game();
			break;
		case 2:
			printf("退出游戏");
			break;
		default:
			printf("选择错误,重新选择");
			break;

		}
	} while (input);

	return 0;
}

这里的do...while可以让我们多次运行游戏;

此时的效果图就是如下

2.初始化棋盘

        对于棋盘的初始化,小伙伴们都很疑惑,该如何创建呢???既然是棋盘,那肯定是方方正正的啊,那么我们首先利用#define设立一下棋盘的行和列,这里我把行称为row,列称为col.

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

        大家一定很好奇后面两行是什么意思,我举个例子,如果坐标在最右上角,那麽现在想要知道它周围八个格子类的数量,是不是不可取,这时就发生了数组越界问题;因此我们要为棋盘四周加上一层;左右各一个即列,上下各一个即行是不是行列各加2啊;

        OK,定义完行列后就要开始进行棋盘的初始化了;

char mine[ROWS][COLS];
char show[ROWS][COLS];//定义数组,防止越界
Initboard(mine, ROWS, COLS, '0');//0代表没有雷
Initboard(show, ROWS, COLS, '*');//*代表隐藏排雷区

这里要说一下,0代表没有雷。1则代表所处位置有雷;mine你可以理解为管理者看到的即可以看到地雷的位置,show则是游戏者看到的;不懂不要紧,慢慢往下看,你一定能懂的;

再进行初始化棋盘的函数

void Initboard(char board[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++)
		{
			board[i][j] = set;//set表示接收定义的符号,好处是方便改变符号;
		}
	}
}

然后要在game.h中进行声明,就是把上面那句话给复制过去;

大家一定也疑惑一个地方,为什么有的大写,有的小写呢;那是因为大写的是宏,而小写则是传参;小伙伴们,你们理解了吗!!!

//初始化棋盘
void Initboard(char board[ROWS][COLS], int rows, int cols, char set);//记得加上分号哦

好的,现在棋盘已经初始化完了,我们可以开始打印棋盘了;


3.打印棋盘

        这时我们就要在主函数的game()模块创建一个新函数了;我把它叫做Displayboard。接受三个参数show、ROW和COL;用于展示布局;

Displayboard(show, ROW, COL);

        那么,开始正式的编写打印棋盘的代码,回到game.c中,因为这里是对棋盘的打印,所以行和列为row和col。

void Displayboard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	for (i = 0; i <= col; i++)//将i初始化为0,目的是让最外面那层防止越界的从0-9刚好包住棋盘的从1-9
	{
		printf("%d ", i);//打印列号
	}
	puts(" ");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印行号


		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}

		printf("\n");
	}

}

如果第一个for循环将i初始化为1的话,就会出现下图的情况。

好的,我们看一下效果图;下面的0和1暂时不用管,后面会说。主要看一下效果图。

这样是不是感觉有点不太清爽的样子;没有一点边界感🤙🤙🤙,这可不行,我们再稍微改一下。

 

void Displayboard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("------------扫雷游戏------------\n");
	for (i = 0; i <= col; i++)//打印列号
	{
		printf("%d ", i);
	}
	puts(" ");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印行号


		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}

		printf("\n");
	}
	printf("------------扫雷游戏------------\n");

}

 效果如下:

嘿嘿,是不是好多了;但是又有小伙伴说了,人家的棋盘两符号之间都有框在隔着。不多说,安排;😈😈😈

void Displayboard(char board[ROWS][COLS], int row, int col)
{
	
	int i = 0;
	printf("------------扫雷游戏------------\n");
	for (i = 0; i <= col; i++)//打印列号
	{
		if (i == 0)
		{
			printf("%d  ", i);//空格要注意,自己调整。
		}
		else
		{
			printf("%d  ", i);
		}
	}
	printf("\n");
	for (i = 0; i <= col; i++)//打印每一列的框架
	{
		if (i == 0)
		{
			printf(" |");
		}
		else
		{
			printf("--|");
		}
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d|", i);//打印行号


		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c |", board[i][j]);
		}

		printf("\n");

		for (int k = 1; k <= row; k++)//打印每一行的框架
		{
			if (k == 1)
			{
				printf(" ");
			}
			if (k == 1)
				printf("|--|");
			else
			{
				printf("--|");
			}
		}
		printf("\n");
	}
	printf("------------扫雷游戏------------\n");

}

 哼哼,经过N长时间的修改,终于改好了😬😬😬;下面来看一下效果图吧。

是不是高端大气上档次😈😈😈

还有,不要忘记在game.h里面进行声明哦;

//打印棋盘
void Displayboard(char board[ROWS][COLS], int row, int col);

那么,棋盘已经布置好了,就要开始布置雷了;

4.布置雷

        首先我们可以想到,雷的位置一定是随机的,那我们就要用到随机数的知识了,上面的猜数字游戏主要是利用它来解决的。不懂的小伙伴可以看看上面的。♥️♥️♥️

        而对于布置雷我又创建了一个新的函数

Setmine(mine, ROW, COL);

        然而,我要先设置一下雷的数量,在哪里设置呢???当然是在game.h中利用#define设置了;

#define EASY_COUNT 10//这里EASY_COUNT就是雷的数量

接着开始正题

void Setmine(char mine[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	while (count)
	{
		int x = rand() % row + 1; //随机一个数,使其在0-9的范围,作为行
		int y = rand() % col + 1; //随机一个数,使其在0-9的范围,作为列
		if (mine[x][y] == '0') //如果坐标处为0,说明无炸弹。
		{
			mine[x][y] = '1'; //既然没有炸弹,所以在这个坐标下安放炸弹。
			count--; //每安装一个,炸弹数量减一,直到全部安装完毕。
		}
	}
}

 根据前面学习,rand()函数生成的是伪随机数。因此我们要利用时间戳使随机数种子随机才行;就要利用time.h了;

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));//把它放在do...while循环前面
	do
	{
		menu();
		printf("请选择:");
		scanf_s("%d", &input);
		switch (input)
		{
		case 1:game();
			break;
		case 2:
			printf("退出游戏");
			break;
		default:
			printf("选择错误,重新选择");
			break;

		}
	} while (input);

	return 0;
}

好了,雷已经布置好了,这时候如果我们想看一下雷在哪个地方怎么办呢???可以在game()函数中布置雷的下面添加Displayboard

void game()
{
	char mine[ROWS][COLS];
	char show[ROWS][COLS];
    //初始化
	Initboard(mine, ROWS, COLS, '0');
	Initboard(show, ROWS, COLS, '*');
	//打印棋盘
	Displayboard(show, ROW, COL);
	//布置雷
	Setmine(mine, ROW, COL);
	Displayboard(mine, ROW, COL);//mine代表雷的布局,所以我们可以看到雷的布局
}

这也就是我上面的图中为什么会出现0和1的原因;1为雷,0为安全位置;小伙伴们,都懂了吗🤙🤙🤙

仍然要记得声明

//布置雷
void Setmine(char mine[ROWS][COLS], int row, int col);
5.排雷

        既然布置雷已经了解了,那我们就开始最后一个步骤吧。再创建一个函数Findmine

Findmine(mine, show, ROW, COL);

 接着我们捋一下思路;首先输入坐标后有三种可能:

1.坐标处有雷,游戏失败,重新开始

2.坐标处没有雷,已排除数量+1.

3.输入的坐标超出范围。

再者定义一个win,来表示已排除炸弹数量;它的范围是什么呢;大家不妨想一想,当时我们游戏设立的行和列是多少,再减去炸弹数量不就是已排除数量吗;当win==row*col-EASY_COUNT的时候,就说明炸弹已经排完,游戏胜利。

win<row*col-EASY_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("请输入坐标:\n");
		scanf_s("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了,游戏结束\n");
				Displayboard(mine, ROW, COL);
				break;
			}
			else
			{
				int count = GetMineCount(mine, x, y);//获取x,y坐标周围有几个雷
				show[x][y] = count + '0';//'0'的Ascii值为48,count假如为1,值为49,转换为数字为1;
				Displayboard(show, ROW, COL);//这句话就是把通过GetMineCount函数获取到的周围的类的数量显示出来。
				win++;
			}
		}
		else
		{
			printf("坐标非法,重新输入");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功");
		Displayboard(mine,ROW, COL);
	}
}

至于这里为什么要+‘0’呢,我放一张ASCII码让大家看看。

 我们可以看到'0'是48,如果我们所选坐标周围的雷的数量为1,48+1换为字符是不是1呢。说到这里

大家应该都懂了吧。🌝🌝🌝

然后我们发现这里调用了GetMineCount,因此我们需要写出函数主体。

static  int GetMineCount(char mine[ROWS][COLS], int x, int y) //static可以让我们不用再声明这个函数
		{
		return (mine[x][y - 1] +
			mine[x][y + 1] +
			mine[x - 1][y] +
			mine[x - 1][y - 1] +
			mine[x - 1][y + 1] +
			mine[x + 1][y] +
			mine[x + 1][y - 1] +
			mine[x + 1][y + 1] - 8 * '0'); //为啥这么做呢?字符数据相减,对应其ASCII相减,就是为了方便统计排雷处周围的雷数
	}

 

再把Findmine进行声明

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

写到这里,初级版的扫雷就已经结束了。各位看官是否学会了呢???😬😬😬

 还有一个知识点,我们可以把库函数都写在game.h中,game.c和test.c中只用写#include "game.h"就可以了。

完整代码

<game.h>
#pragma once
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
//初始化棋盘
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 mine[ROWS][COLS], int row, int col);
//排雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);


<game.c>
#include "game.h"

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


}
void Displayboard(char board[ROWS][COLS], int row, int col)
{
	
	int i = 0;
	printf("------------扫雷游戏------------\n");
	for (i = 0; i <= col; i++)//打印列号
	{
		if (i == 0)
		{
			printf("%d  ", i);
		}
		else
		{
			printf("%d  ", i);
		}
	}
	printf("\n");
	for (i = 0; i <= row; i++)
	{
		if (i == 0)
		{
			printf(" |");
		}
		else
		{
			printf("--|");
		}
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d|", i);//打印行号


		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c |", board[i][j]);
		}

		printf("\n");

		for (int k = 1; k <= row; k++)
		{
			if (k == 1)
			{
				printf(" ");
			}
			if (k == 1)
				printf("|--|");
			else
			{
				printf("--|");
			}
		}
		printf("\n");
	}
	printf("------------扫雷游戏------------\n");

}
void Setmine(char mine[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (mine[x][y] == '0')//如果坐标处为0,说明无炸弹。
		{
			mine[x][y] = '1';
			count--;
		}
	}
}
static  int GetMineCount(char mine[ROWS][COLS], int x, int y)
		{
		return (mine[x][y - 1] +
			mine[x][y + 1] +
			mine[x - 1][y] +
			mine[x - 1][y - 1] +
			mine[x - 1][y + 1] +
			mine[x + 1][y] +
			mine[x + 1][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;
	int y = 0;
	int win = 0;
	while (win<row*col-EASY_COUNT)//实现循环操作
	{
		printf("请输入坐标:\n");
		scanf_s("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了,游戏结束\n");
				Displayboard(mine, ROW, COL);
				break;
			}
			else
			{
				int count = GetMineCount(mine, x, y);//获取x,y坐标周围有几个雷
				show[x][y] = count + '0';//'0'的Ascii值为48,count假如为1,值为49,转换为数字为1;
				Displayboard(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,重新输入");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功");
		Displayboard(mine,ROW, COL);
	}
}

<test.c>
#include "game.h"
void menu()
{
	printf("----------------------------\n");
	printf("-----------1.game-----------\n");
	printf("-----------2.exit-----------\n");
	printf("----------------------------\n");
}
void game()
{
	char mine[ROWS][COLS];
	char show[ROWS][COLS];
	Initboard(mine, ROWS, COLS, '0');
	Initboard(show, ROWS, COLS, '*');
	//打印棋盘打印
	Displayboard(show, ROW, COL);
	//布置雷
	Setmine(mine, ROW, COL);
	Displayboard(mine, ROW, COL);	//布置雷后放,让你看到雷的位置
	//排雷
	Findmine(mine, show, ROW, COL);
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:");
		scanf_s("%d", &input);
		switch (input)
		{
		case 1:game();
			break;
		case 2:
			printf("退出游戏");
			break;
		default:
			printf("选择错误,重新选择");
			break;

		}
	} while (input);

	return 0;
}

最后,大家欣赏一下效果图

 创作不易,希望大佬们以及未来的大佬们给个三连再走吧

 创作不易,希望大佬们以及未来的大佬们给个三连再走吧

 创作不易,希望大佬们以及未来的大佬们给个三连再走吧

同时,也希望各位大佬能够指正文章的错误,(^_^)∠※

  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翻斗花园牛爷爷★

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值