文章目录
扫雷逻辑
创建一个项目test.c 储存游戏逻辑
基础架构
我们先说基础架构,明白扫雷的架构原理,明白原理后扫雷并不难;
打印菜单
打印菜单不需要返回值,创建void函数,
“printf”函数需要调用库函数 #include <stdio.h>
后面可以把这个库函数放入 game.h,这样调用game.h就可以了方便很多
打印菜单:
void menu()
{
printf("***************")
printf("*** 1. play ***")
printf("*** 0. exit ***")
printf("***************")
}
函数输入“1”开始游戏,输入“0”退出游戏;
初始化数组
设置两个数组 “mine”, “show”,一个用来随机输入雷,一个用来排雷,如果用一个数组雷用“1”表示非雷为“0”,排雷会显示周围雷的个数,这样显示雷的数会和雷1“”冲突,如果说给雷换成其他符号,那样数组太杂,还是不方便,所以用两个数组表示
,最开始“mine”数组没有雷所以要初始化成全是0,“show”数组最开始没有排查所以初始化成一种符号,这里用“*”演示,又因为当排雷时是要把所选位置一圈都检测一遍,如果所选位置是边上位置时会越界,所以把数组扩大一圈,防止出现越界。
创建数组:
char mine[ROWS][COLS];//'0'
char show[ROWS][COLS];//'*'
ROWS 是 ROW + 2 “ROW”(行)
COLS 是 COL + 2 “COL”(列)
如果写mine[11][11]这种后续想要改变行列比较麻烦,所以用’ROW’'COLS’表示;
初始化数组(int初始化):
InitBoard(mine,ROWS,COLS,'0');
InitBoard(show,ROWS,COLS,'*');
数组初始化之后就要打印棋盘;
打印棋盘
之前设置了行列位“ROW”“COL”,打印棋盘多出来的那一圈是为了防止越界不需要展示,所以不用“ROWS”“COLS”;
打印棋盘:
DisplavBoard(mine,ROWS,COLS):
DisplayBoard(show,ROWS,COLS);
打印mine是为了给我们自己看调试用的,代码完成时,要注释掉“DisplavBoard(mine,ROWS,COLS):”
布雷
布雷要知道在那个数组,多少行多少列的范围所以要有“mine”“ROW”“COL”
布雷:
SetMine(mine,ROW,COL);
排雷
排雷需要两个数组才能进行,多少行多少列的范围要有“show”“mine”“ROW”“COL”
排雷:
FindMine(mine,show,ROW,COL);
这些是扫雷的架构,看懂这些后面就很好理解;
函数入口(main函数)
随机数值
扫雷的雷肯定是要随机的,如果固定那几个地方是雷,那就太没意思了,想要随机就需要用到"srand()“,还得让随机,那么就需要一个能一直变化的变量"time” 给time一个空指针:“time(NULL)”;再把"time(NULL)“强制转换成int类型”(unsigned int) time(NULL));“最后加上"srand()”,一个设置随机数值的函数就创建好了:
srand((unsigned int)time(NULL));
然后就是进行菜单的选择:
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择\n")
break;
}
}while(input);
return 0;
}
输入“1”进入游戏;
输入“0”退出游戏;
输入其他的数字提示错误重新输入;
玩完之后进while循环,这样可以反复的玩,不用重新进入;
完整逻辑代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("***********************\n");
printf("****** 1. play *****\n");
printf("****** 0. exit *****\n");
printf("***********************\n");
}
void game()
{
//数组
char mine[ROWS][COLS];//'0'
char show[ROWS][COLS];//'*'
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//棋盘打印
//DisplayBoard(mine, ROW, COL);
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("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while (input);
return 0;
}
游戏的函数声明
创建game.h 储存游戏的函数声明
头文件
.h后缀也就是头文件,头文件有什么作用呢?
1.方便开发:包含一些文件需要的共同的常量,结构,类型定义,函数,变量申明;
2.使函数的作用域从函数声明的位置开始,而不是函数定义的位置(实践总结)
3 .提供接口:对一个软件包来说可以提供一个给外界的接口(例如: stdio.h)。
通过阅读上文游戏逻辑,可以知道有4个函数需要声明:
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘的
void DisplayBoard(char board[ROWS][COLS], int rows, int cols);
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
不仅如此还有一些库函数需要放在头文件里方便开发:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
调用了“ROW”“COL”但是它们的数值还没有设置,这篇博客做一个简易的扫雷就9*9吧:
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
布雷的函数咱们写了,但是并没有写数值:
#define EASY_COUNT 10
头文件完整代码:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.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 rows, int cols);
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
这样咱们头文件就写好了,声明完函数就要实现函数了;
扫雷的实现
初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
括号里大家会有问题的是“char set”,这是什么?
在游戏逻辑的时候两个数组要初始化两种字符:
char mine[ROWS][COLS];//'0'
char show[ROWS][COLS];//'*'
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
一个“0”,一个“*”;所以用set表示初始化该数组,初始化成该数组对应字符;
所以初始化数组:
#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 rows, int cols);
既然是棋盘就需要有行列的序号:
for (i = 0; i <= row; i++)
{
printf("%d ", i);
}
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");
}
棋盘打印完了,也可以加上扫雷游戏几个字:
int i = 0;
printf("--------扫雷游戏-------\n");
for (i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
棋盘打印完整代码:
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
printf("--------扫雷游戏-------\n");
for (i = 0; i <= row; 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 DisplayBoard(char board[ROWS][COLS], int rows, int cols);
在头文件里咱们设置过雷的数量了需要调用一下:
int count = EASY_COUNT;
然后做一个循环,每放一颗雷就“count–”,
坐标 x,y的范围由“ROW”“COL”决定:
int x = rand() % row + 1;
int y = rand() % col + 1;
因为是随机的x,y,有可能会出现重复,所以要确定mine[x][y]的位置是“0”,也就是没雷才能放:
if (mine[x][y] == '0')
这样就完成了布雷,布雷完整代码:
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')
{
mine[x][y] = '1';
count--;
}
}
}
排雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
首先排查坐标,坐标不合法重新输入:
while (1)
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
;
}
else
{
printf("坐标非法,重新输入\n");
}
坐标合法,排查这个位置是不是雷,是雷(“1”)扑街,然后显示mine棋盘别让玩家死不瞑目,如果不是雷,统计周围有几个雷:
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("坐标非法,重新输入\n");
}
数字字符和数字之间的转化规律,字符“0”的ASCII为48
字符1,2,3,4… ASCII依次累加1;
所以字符“1”-字符“0”= ASCII“49”- ASCII“48” = 数字“1”;
字符“2”-字符“0”= ASCII“50”- ASCII“48” = 数字“2”
知道了转化规律
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
统计周围的数值,count + ‘0’ 转化成字符放入show[x][y];
GetMineCount是统计mine数组周围有几个雷那怎么实现呢看下图:
[x][y]周围有8个格子,让8个格子加在一起减去 8*'0’就知道附近多少雷了:
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] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - 8 * '0');
}
完整排雷代码:
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] +
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-EASY_COUNT)
{
printf("请输入要排查的坐标:>");
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("坐标非法,重新输入\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
完整代码实现:
#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)
{
int i = 0;
printf("--------扫雷游戏-------\n");
for (i = 0; i <= row; 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 = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
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] +
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-EASY_COUNT)
{
printf("请输入要排查的坐标:>");
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("坐标非法,重新输入\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
至此一个扫雷程序就写完了,但是正常的扫雷每开一个格子都是会连带着一片空白格一起开;但是这个程序无法实现,我也在研究怎样才能做出正常的扫雷,
关注我,第一时间了解我的动态。
下期见,拜拜~
我的CSDN:Y.Ge_-CSDN博客
大家可以关注我CSDN账号,优先发布!
标签:ROWS,int,void,程序,mine,COLS,char,详解,扫雷 From: https://blog.51cto.com/u_16182079/6898637