引言:
本篇文章来介绍学习C语言中的一个小项目“扫雷游戏”,该项目代码量在200行左右,同时该篇文章也是专题<C语言小游戏>中的一篇,接下来就请跟着笔者的思路来一步一步完成这个项目。
正文:
项目躯干:
首先,一个程序的诞生一定有main函数,所以我们要先写出一个main函数
int main()
{
return 0;
}
而其他代码一定是在main函数中被调用或运行的。
有了main函数,我们就要思考这个项目分为哪几部分?可以想到它需要一个菜单,我们接着向下写
void Menu()//打印菜单
{
printf("* * * * * * * * * * * * *\n");
printf("* * * 1 开 始 游 戏 * * *\n");
printf("* * * 0 结 束 游 戏 * * *\n");
printf("* * * * * * * * * * * * *\n");
}
这时我们给出了菜单,就要用户进行选择了,同时对用户做出的选择作出相应反应
void Test()
{
int choose = 0;
do
{
Menu();
printf("请输入你的选择==>");
scanf("%d", &choose);
system("cls");
switch (choose)
{
case 1:
Game();
break;
case 0:
printf("正在退出游戏\n");
break;
default:
printf("识别错误,请重新输入\n");
}
} while (choose);
}
为了使用户玩的更加方便,这里笔者加上了一个do-while循环,同时还有一个清屏指令(system("cls");),该指令存在于<Windows.h>中,可以使页面使用时更加人性化。这是可以看到笔者还卖了一个坑:Game();这就是项目的核心,也可以说是灵魂。
项目灵魂:
接下来就是重磅的Game();函数,首先就要创建一个Game();函数
void Game()//游戏主体
{
}
当然有了它我们还要往里面填充东西,这时就要想到,扫雷一定要有棋盘吧,这是我们就要创建两个棋盘,一个给用户展示,另一个存放雷,用来判断用户排查的是不是雷
char Mine[ROW][COL] = { 0 };//放雷数组
char Show[ROW][COL] = { 0 };//展示数组
这里用到了ROW,COL两个常量,这两个常量是笔者事先定义好的不止这两个如下
#define row 9//行
#define col 9//列
#define ROW row+2
#define COL col+2
#define Easy 10//雷数
这些常量在下文都会用到,继续上文问题,有了棋盘还要做相应的初始化,通常我们会进行一个数组一个数组的进行初始化,可这样在无形中就增大了项目的代码量,所以这里笔者将其单独写成一个函数进行调用
void Init(char arr[ROW][COL], int Row, int Col, char c)//初始化数组
{
for (int i = 0; i < Row; i++)
{
for (int j = 0; j < Col; j++)
{
arr[i][j] = c;
}
}
}
这时调用语句就应写成这样
Init(Mine, ROW, COL, '0');//数组初始化
Init(Show, ROW, COL, '*');
虽然棋盘被初始化了但是我们还是没有将雷布置进去,所以接下来就是布置雷
void MineDep(char arr[ROW][COL], int Row, int Col)//布置雷
{
srand((unsigned int)time(NULL));
int count = Easy;
while (count)
{
int x = rand() % Row + 1;
int y = rand() % Row + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
这里就是用了srand对rand进行了处理保证了数字的随机性,而count作为while函数的条件也保证了雷的个数,同时if函数使雷的位置不会重复。
我们布置好了雷,下一步就是让用户开始扫雷,而扫雷就要给用户提供一个棋盘供其参考,因为雷要一点点扫,所以棋盘也不止一次被打印,所以这里还是将其写成一个函数
void Print(char arr[ROW][COL], int Row, int Col)//打印棋盘
{
printf("- - - 扫 雷 游 戏 - - -\n");
for (int i = 0; i <= Col; i++)
{
printf("%2d", i);
}
printf("\n");
for (int i = 1; i <= Row; i++)
{
printf("%2d", i);
for (int j = 1; j <= Col; j++)
{
printf("%2c", arr[i][j]);
}
printf("\n");
}
printf("- - - - - - - - - - - -\n");
}
当然该函数中笔者对棋盘做了一点美化,有了这个函数之后就是让用户一次又一次的去排查雷,直到棋盘上只剩下雷,或踩到雷时结束游戏
void Find(char arr1[ROW][COL], char arr2[ROW][COL], int Row, int Col)//寻找雷
{
int x = 0, y = 0;
int temp = 0;
while (1) {
Print(arr2, row, col);
printf("输入要排查的坐标==>");
scanf("%d %d", &x, &y);
system("cls");
if ((x > 0 && x < 10) && (y > 0 && y < 10))
{
if (arr1[x][y] == '1')
{
printf("你踩到地雷了!!!\n地雷排布图\n");
Print(arr1, row, col);
break;
}
else
{
int sum = 0;
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
sum += arr1[i][j] - '0';
}
}
arr2[x][y] = '0' + sum;
temp++;
}
}
else
{
printf("坐标不存在,请重新输入\n");
}
if (temp == row * col - Easy)
{
printf("扫雷成功!!!\n");
break;
}
}
}
这里还有一个小块就是对于排查后的坐标显示其周围雷的个数
int sum = 0;
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
sum += arr1[i][j] - '0';
}
}
arr2[x][y] = '0' + sum;
这时整个项目能用到的代码大多都在这了,可是可以发现这些代码都是一块一块的,并不连贯,就像一块块灵魂碎片,接下来还有一份工作就是将这些碎片拼接起来
整理拼接:
<Game.h>
首先可以看我们定义了多个常量、函数、同时也要调用多个头文件,所以这里笔者就自己定义了一个头文件来存放这些东西命名为Game.h
#define row 9
#define col 9
#define ROW row+2
#define COL col+2
#define Easy 10
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void Menu();//菜单
void Test();
void Game();
void Init(char arr[ROW][COL], int Row, int Col, char c);//棋盘初始化
void MineDep(char arr[ROW][COL], int Row, int Col);//布置雷
void Print(char arr[ROW][COL], int Row, int Col);//打印棋盘
void Find(char arr1[ROW][COL], char arr2[ROW][COL], int Row, int Col);//寻找雷
<main.c>
这个函数就没存放多少东西
#include"Game.h"
int main()
{
Test();
return 0;
}
void Test()
{
int choose = 0;
do
{
Menu();
printf("请输入你的选择==>");
scanf("%d", &choose);
system("cls");
switch (choose)
{
case 1:
Game();
break;
case 0:
printf("正在退出游戏\n");
break;
default:
printf("识别错误,请重新输入\n");
}
} while (choose);
}
<game.c>
这个文件是重量级的包含大量函数
#include"Game.h"
void Menu()//打印菜单
{
printf("* * * * * * * * * * * * *\n");
printf("* * * 1 开 始 游 戏 * * *\n");
printf("* * * 0 结 束 游 戏 * * *\n");
printf("* * * * * * * * * * * * *\n");
}
void Game()//游戏主体
{
char Mine[ROW][COL] = { 0 };//创建数组
char Show[ROW][COL] = { 0 };
Init(Mine, ROW, COL, '0');//数组初始化
Init(Show, ROW, COL, '*');
MineDep(Mine, row, col);//布置雷
Find(Mine, Show, ROW, COL);//寻找雷
}
void Init(char arr[ROW][COL], int Row, int Col, char c)//初始化数组
{
for (int i = 0; i < Row; i++)
{
for (int j = 0; j < Col; j++)
{
arr[i][j] = c;
}
}
}
void MineDep(char arr[ROW][COL], int Row, int Col)//布置雷
{
srand((unsigned int)time(NULL));
int count = Easy;
while (count)
{
int x = rand() % Row + 1;
int y = rand() % Row + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
void Print(char arr[ROW][COL], int Row, int Col)//打印棋盘
{
printf("- - - 扫 雷 游 戏 - - -\n");
for (int i = 0; i <= Col; i++)
{
printf("%2d", i);
}
printf("\n");
for (int i = 1; i <= Row; i++)
{
printf("%2d", i);
for (int j = 1; j <= Col; j++)
{
printf("%2c", arr[i][j]);
}
printf("\n");
}
printf("- - - - - - - - - - - -\n");
}
void Find(char arr1[ROW][COL], char arr2[ROW][COL], int Row, int Col)//寻找雷
{
int x = 0, y = 0;
int temp = 0;
while (1) {
Print(arr2, row, col);
printf("输入要排查的坐标==>");
scanf("%d %d", &x, &y);
system("cls");
if ((x > 0 && x < 10) && (y > 0 && y < 10))
{
if (arr1[x][y] == '1')
{
printf("你踩到地雷了!!!\n地雷排布图\n");
Print(arr1, row, col);
break;
}
else
{
int sum = 0;
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
sum += arr1[i][j] - '0';
}
}
arr2[x][y] = '0' + sum;
temp++;
}
}
else
{
printf("坐标不存在,请重新输入\n");
}
if (temp == row * col - Easy)
{
printf("扫雷成功!!!\n");
break;
}
}
}
至此代码的整合拼接就结束了,同时正文也告一段落
演示:
扫雷演示
总结:
为什么要写那么多的函数呢?因为代码要讲求高内聚,底耦合;同时减少代码量,减轻自己负担,提高代码质量,同时也提高代码的可读性。
最后,该项目就到此告一段落,如果各位读者对文章有什么看法,或问题欢迎留言。