目录
1.制作一个简易的菜单
2.创建数组
3.对数组进行初始化
4.打印棋盘
5.布置雷
6.排查雷
在这个之前,要创建三个文件,test.c ,game.c , game.h
分开文件放可以更加整洁,更加利于理解,每个文件实现对应的功能
game.c 放游戏的逻辑实现, game.h 放函数声明和 头文件
2.第一行的#include "game.h" ,我把头文件放到game.h了
3.menu();不需要传参数也不要返回值,所以void menu()
#include <stdio.h>
#include "game.h"
void menu()
{
printf("****************\n");
printf("*** 1.play ***\n");
printf("*** 0.exit ***\n");
printf("****************\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择喵:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏喵...");
break;
default:
printf("输入错误,请重新输入:\n");
break;
}
} while (input);
return 0;
}
do—while循环,用input变量,来控制循环是否会继续,它可以在使用前就先运行代码一次,我们用这个特性就可以先打印一遍菜单。假如输入1就会进入循环,因为在循环中,不是0的数为真(非0为真),0则为假,为假就不会执行
switch判断语句,再让用户输入1或者0来判断,1开始游戏,0结束提出,假如输入了3, 8,9等等其他的数就会让用户再次输入(再次输入是因为input的值是1,会一直循环)
2.创建数组
这里的game();就有用了,void无返回值的类型,不需要return返回值
创建两个数组,注意观察创建的类型是char类型的,每个坐标只存放一个字符
mine,布置雷,雷是不可看见了。
show,用来排查的,用户可以看见的
ROWS和COLS,是我们定义的两个宏,叫做不带参数的宏,
#define 标识符 字符串,宏的基本格式
这个也是定义在game.h里面,我们要创建的是一个9*9的棋盘,要排查雷的数量是10个
在下面的数组创建中就可以直接用了,行和列都是11,初始化为全0
因为要做逻辑运算,假如要排查9行7列的数,就会发现溢出了,所以是要创建11*11
防止溢出。
game.h部分的
#include <stdio.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
test.c 部分的
void game()
{
//创建数组喵,mine布置雷,show可视化,初始化为0
char mine[ROWS][COLS] = {0};
char show[COLS][COLS] = {0};
}
3.对数组进行初始化
初始化函数,布置雷的棋盘一个需要初始化为全为字符‘0’,show,未排查的雷要初始化为全‘ * ’。
mine初始化为全0,是因为后面每次布置一个雷就要是字符‘ 1 ’,代表一个雷
3.1.这边传的参数是数组,棋盘行,列,需要初始化的实参
game.h ,这里就偷个懒啦,先把要声明的头文件都放这里,这里不用看很仔细,到后面就知道了
每个函数在用前都要声明这个。变量的类型和参数,告诉程序。
这里也就解释了最开头的 #include "game.h"。这样就可以找到定义了
#include <stdio.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#include <time.h>
#include <stdlib.h>
#define EASY_COUNT 10
//数组初始化
void InitBoard(char arr[ROWS][COLS],int rows,int cols, char set);
//打印数组
void DisplayBoard(char arr[ROWS][COLS], int row, int col);
//布置雷
void SetMine(char arr[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
test.c
void game()
{
//创建数组喵,mine布置雷,show可视化,初始化为0
char mine[ROWS][COLS] = {0};
char show[COLS][COLS] = {0};
//对数组进行初始化
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
}
game.h,部分的
3.2.形参,收到char数组,行和列,初始化的参数
初始化通过两个for循环遍历的每个地方。每遍历到一个位置就放入,set也就是传过来的字符
#include "game.h"
//初始化棋盘,函数的函数就是形参是变化的,但是实参不是变化的
void InitBoard(char arr[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++)
{
arr[i][j] = set;
}
}
}
4.打印棋盘
竟然初始化了数组中的数,接下来就要打印初始化好的数组,打印数组可以用同样的思路
有双层for循环遍历整个数组,来看看是否初始化成功
两个数组,mine和show,这里注释掉了,因为后面要布置雷的。如果要看有没有初始化成功也可以打印看看
test.c
void game()
{
//创建数组喵,mine布置雷,show可视化,初始化为0
char mine[ROWS][COLS] = {0};
char show[COLS][COLS] = {0};
//对数组进行初始化
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//打印棋盘
//DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
}
game.c
4.1.注意这里前面的第一个for循环,是为美化一下棋盘用数字来标记列号的,这个是在数组打印前就输出的,然后用\n换行。
4.2.排查雷的部分是9*9,做逻辑运算的是11*11,所以传过来的值是ROW和COL。
下面的双层是用来打印数组的,下面有一个printf(“%d ”,i);用来打印行号的,在每次数组的行开始打印前的。
数组的每个打印完要空格有间距视觉上会好一些printf(“%d ”,arr[ i ][ j ]);。每行打印完也要换行
这个arr[ i ][ j ]是当遍历到当前位置时。
//打印棋盘,做逻辑运算的是创建的数组,显示需要排查的雷的是9*9的部分
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
int i = 0;
for (i = 0; i <= col; 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 ", arr[i][j]);
}
printf("\n");
}
}
最后的调试结果就是这样的喵
5.布置雷
test.c
5.1布置雷,要布置完才知道,所以打印要放布置前才行。不然棋盘都打印完了,雷去哪里布置?
void game()
{
//创建数组喵,mine布置雷,show可视化,初始化为0
char mine[ROWS][COLS] = {0};
char show[COLS][COLS] = {0};
//对数组进行初始化
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//布置雷
SetMine(mine, ROW, COL);
//打印棋盘
//DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
}
game.c
5.2.布置雷是mine,9*9内
5.3.第一步首先,EASY-COUNT定义一个宏表示10个雷,放在3.2。
5.4.先用一个while循环,每成功布置一次雷就count--,知道为0,循环结束,rand一个生成随机数的函数,一般这个函数是需要srand函数,用这个来获取种子,一般是要搭配使用。
在程序的最开头设置,time是获取一个时间戳,1970—现在的总共的秒数,但是返回的类型是time_s,所有用unsigned,强制转换成无符号整型。rand需要的值是个无符号整型
int main()
{
//在程序的最开始位置设置种子
srand((unsigned)time(NULL));
int input = 0;
5.5.int x = rand() % row + 1,row是9,所以余数是0—8。+1,余数就会变为1—9,假设余数是8,它就要+1,变成9。通过rand产生的随机值就可以x 和 y的地址
5.6.然后if,判断这个地址里面是“0”,是就布置,并且count - -。
//布置雷,按照逻辑来讲,布置雷要在打印棋盘之前
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;//创建一个变量,来计数,EASY_COUNT,表示要布置10个雷
while (count)//不等于0,时会一直循环
{
int x = rand() % row + 1;//通过随机数,在棋盘上随机布置雷
int y = rand() % col + 1;//row和col控制范围
if (arr[x][y] == '0')//如果该坐标是'0',就布置雷
{
arr[x][y] = '1';
count--;//每布置成功一次就-1
}
}
}
最后的效果实现,查看一下雷布置的结果,但是只是测试看一下
6.排查雷
test.c
void game()
{
//创建数组喵,mine布置雷,show可视化,初始化为0
char mine[ROWS][COLS] = {0};
char show[COLS][COLS] = {0};
//对数组进行初始化
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//布置雷
SetMine(mine, ROW, COL);
//打印棋盘
DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//排查雷
FindMine(mine, show, ROW, COL);
}
game.c
首先要看排查雷的部分,
6.1.先定义两个变量,先判断坐标的有效性n m换成x和y的更好理解,假如不在9*9的棋盘内,输入错误
6.2.输入的坐标正确,但是被炸死了,就是mine[n][m] == '1',挑战失败,并且打印布置雷的棋盘,让你输的心服口服
6.3.没有被炸死,就要统计这个坐标的周围有几个雷,然后放到show这个棋盘中
GetMineCount(mine, n, m);通过这个函数来统计周围有几个雷
假设坐标是3 6
6.4,每次遍历到该位置,就—‘0’,因为字符'1'的ASCLL码值是60,字符‘0’的ASCLL是59
它两相减的差值是1,有几个雷就会返回几。放到count计数,这个函数是int类型的需要返回值
6.5然后再将返回值用ct装起来,ct+‘0’,转换成对应字符,然后放到show这个棋盘中。
6.6,win++,每排查完一个雷就+1,用while来,win < row * col - EASY_COUNT,9*9的棋盘-雷的数量81-10=71,小于71会一直执行直到雷排查完
6.7.最后一步就是雷都都排查完了,win == row * col - EASY_COUNT,正好是一个雷都不剩了
恭喜你!,挑战成功
int GetMineCount(char mine[ROWS][COLS], int n,int m)
{
int count = 0;
for (int i = n - 1; i <= n + 1; i++)
{
for (int j = m - 1; j <= m + 1; j++)
{
count = mine[i][j] - '0';
}
}
return count;
}
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int n = 0;
int m = 0;
int win = 0;
while (win < row * col - EASY_COUNT)
{
printf("请输入你要排查的坐标:");
scanf("%d %d", &n, &m);
if (n >= 1 && n <= 9 && m >= 1 && m <= 9)
{
//输入正确后
if (mine[n][m] == '1')
{
printf("挑战失败\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int ct = GetMineCount(mine, n, m);
show[n][m] = ct + '0';//转换成字符
DisplayBoard(show, ROW, COL);
win++;//每排查完一个就++
}
}
else
{
printf("输入错误,请重新输入:");
}
}
if (win == row * col - EASY_COUNT)
{
printf("挑战成功\n");
DisplayBoard(mine, ROW, COL);
}
最终效果,多多实操、頑張る
后续的扩展功能,等我学习一下再来吧,喵喵
有些地方不好,会慢慢改进的--_--