在学习c语言一段时间后,在掌握分支语句以及循环语句,数组,函数这些基本知识后我们就可以来设计一些简单的游戏,下面就是利用这些基础知识完成扫雷游戏的过程,包含游戏功能的设计以及解释什么代码可以实现这些功能 希望能为读者带来一些收获,文章中若有何错误和不足各位可在评论区指出,感谢!!!
1.编写代前一些流程
1.扫雷游戏的功能说明
在所要编写的代码中 希望能实现的功能如下
1. 程序能直接自己在9*9的棋盘中布置雷
2.当用户输入坐标后,程序能排查雷(若这个位置是雷就炸死,游戏结束 这个位置不是雷就告诉这个位置周围由几个雷)
3.在把所有不是雷的位置都找到后,游戏也结束,游戏胜利
2.实现功能实现分析过程
在扫雷游戏中我们一开始希望能实现存放雷的功能,这时就可以想到可以用一个9*9的二维数组来存放雷
这时可以在想表示有雷的位置存放1,没有雷的位置就存放0
但如果这样设计我们需要考虑到还有排查出周围雷的个数信息要表示
这时如果把雷和排查出雷的个数放在同一个二维数组内时,就会出现无法判断数组内的1时表示什么信息 这时有一些读者就会想用比如用*表示雷,#表示非雷 这样排查出雷的个数就不会与雷的信息有重叠的部分
这样的想法是可行的,当当程序在遍历数组内的元素时 需要经过三层判断,判断是*还是#还是数字,这样会使得程序运行繁琐,所以不使用这种方法
这时就可以想到再创建一个同样大的二维数组来存放排查出雷个数
这排查过程中在如下这些边界位置时,这些位置周围8个就会有的是不在9*9的二维数组里,这样情况下如果是出现越界就要用另一种排查方法就会使得程序执行过程复杂
因此是否有更好的解决方法呢?
可以用扩大数组来避免出现越界的情况,比如棋盘大小是9*9,就可以创建一个11*11的二维数组
这样就可以让在边界的位置在排查过程中也是用与其他位置相同的方法
在没有被排查的位置显示* ,排查过的位置显示周围雷的个数
这时就会出现一个问题:在同一个数组内同时存放字符*和数字 会导致在初始化和打印等流程中一个函数无法实现所有功能
这时如果将数组里面的数字变成字符数字就可以解决这个问题
因此这两个二维数组都是字符数组
我们专门给⼀个棋盘(对应⼀个数组mine)存放布置好的雷的信息,再给另外⼀个棋盘(对应另外⼀个数组show)存放排查出的雷的信息这样就互不干扰了,把雷布置到mine数组,在mine数组中排查雷,排查出的数据存放在show数组,并且打印show数组的信息给后期排查参考。
同时为了保持神秘,show数组开始时初始化为字符 '*',为了保持两个数组的类型⼀致,可以使⽤同⼀套函数处理,mine数组最开始也初始化为字符'0',布置雷改成'1'。如下如:
3.游戏文件结构设置
test.c 文件中写游戏的测试逻辑
game.c 文件中写游戏中函数的实现等
game.h 文件中写游戏需要的数据类型和函数声明等
以上就是编写代码前对游戏的一些分析,接下来就是讲解代码应如何实现
2.扫雷游戏代码的实现
1.test.c内大体逻辑
首先在test.c内创建一个main函数 再在里封装一个test函数
在test函数里设计一个能让用户循环玩的功能 这时就可以在test函数里使用do...while循环
先打印出开始界面让用户选择 用户输入1就开始游戏 ,输入2就退出游戏 输入其他值就提示用户输入值错误,请重新输入,打印开始界面的功能放在menu函数里 扫雷游戏的实现放在game函数里
同时将test.c文件和game.c文件包含头文件#include"game.h" 这样只要在game.h中声明库函数的头文件,其他文件中无需再进行此操作
还需要在game.h内输入#pragma once,让.h代码在.c的文件中只展开一次
2.扫雷功能具体实现流程
1.初始化数组
在game函数中先创建两字符类型的二维数组 一个数组名为mine 另一个show,把雷布置到mine数组 ,排查出的数据存放在show数组
但这样初始化数组之后 不容易改变棋盘大小 所以我们可以把数组大小在game.h里定义
其中ROW表示实际棋盘行,COL表示实际棋盘列 ROWS表示实际数组行,COLS表示实际数组列
这时就可创建数组
接下来对数组初始化,这时就需要在game.c内创建一个InitBoard函数来实现数组初始化的功能,
在此之前要在game.h内对InitBoard函数进行声明
在这个函数中因为实参传的是实际数组大小 所以形参用小写的rows,cols来表示
在这种情况下如果要对mine和show初始化需要将函数InitBoard编写两次,这时我们只需要在实参上再传递一个想要初始化的内容的参数 用set表示
2.打印棋盘
在初始化数组后就将进入到棋盘的打印 这时在引用DisplayBoard函数来实现打印
由于棋盘实际大小为9*9所以实参部分传的是ROW,COL
形参则用row与col来接收 从而来避免与初始化棋盘InitBoard函数形参搞混
先在game.c内声明函数
DisplayBoard的代码如下:
3.在棋盘内布置雷
首先我们目标是要在9*9的棋盘内布置10个雷 先在game.h里定义雷个数为Counts
再创建函数Setmine 同时在game.h内声明
以下是布置雷函数的代码
在这当中用到了rand来生成随机数 但rand默认的基准值种子是1而且循环也不会改变,这时就需要再用到srand同时利用库函数time的返回标准时间差来生成随机的种子
同时srand是在test.c的test函数里使用
在使用srand与time库函数时要在game.h里引用头文件 #include<stdlib.h>和#include<time.h>
4.排查输入位置有无雷
最后一步就是当用户输入棋盘位置坐标时,如果输入位置有雷就游戏结束,没有就显示周围雷个数,直到所有不是雷位置被输入就游戏成功
这时需要创建一个Findmine函数用来实现以上功能
在game.h先进行声明
以下是该函数的内容
在以上函数 当输入位置不是雷时之后在计算这个位置周围8个位置雷的个数时,调用GetMineCount函数 以下是该函数的两种形式都可行
3.游戏代码
1.game.h
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define Counts 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);
2.game.c
#define _CRT_SECURE_NO_WARNINGS 1
#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)
{
printf("--------扫雷---------\n");
int i = 0;
for (i = 0; i <= 9; i++)
{
printf("%d ", i);
}
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");
}
printf("--------扫雷---------\n");
}
void Setmine(char mine[ROWS][COLS], int row, int col)
{
int count = Counts;
int x = 0;
int y = 0;
while (count)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (mine[x][y] != '1')//判断这个位置是不是雷
{
mine[x][y] = '1';
count--;
}
}
}
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
int i = 0;
int count = 0;
for (i = -1; i <= 1; i++)
{
int j = 0;
for (j = -1; j <= 1; j++)
{
count += (mine[x + i][y + j] - '0');
}
}
return count;
/*return (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');*/
}
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 - Counts)
{
printf("请输入要排查的坐标>:\n");
scanf("%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);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("输入值不在范围内x:1~9,y:1~9\n");
}
}
if (win == row * col - Counts)
{
printf("排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
3.test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
printf("*************************\n");
printf("********1.play***********\n");
printf("********2.quit***********\n");
printf("*************************\n");
}
void game()
{
char mine[ROWS][COLS] = { 0 };// 该数组用来存放雷的信息
char show[ROWS][COLS] = { 0 };//该数组用来存放排查出雷的信息
// 初始化棋盘
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//打印棋盘
DisplayBoard(show, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//布置雷
Setmine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//排查雷
Findmine(mine, show, ROW, COL);
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择>:\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 2:
break;
default:
printf("输入值错误,请重新输入\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
4.代码运行
以下是扫雷游戏代码的一次使用 读者也可自己运行试试
以上就是本篇文章所有内容希望能得到你的点赞与收藏!!!