扫雷游戏由一个有X,Y轴的平面格子构成,所以需要用到二位数组.
1.利用两个二位数组分别来布置雷(玩家不可见)char mine[ROWS][COLS],展示扫雷的界面(玩家可见)char show[ROWS][COLS].
2.雷的布置:利用随机数生成布置雷,需要用到时间戳,rand()函数.
3.爆炸式边界展开:当扫雷点四周没有雷的时候,扫雷边界会向四周继续展开, 直到边界出现雷. 利用函数的递归实现该功能.
4.不同颜色显示:利用彩色打印实现不同雷数量的显示,以及疑似有雷位置的标记.
5.标记功能,创建一个一维数组存储标记点的坐标.
test.c(主程序,游戏的大体框架)
game.c(自定义函数,游戏的各个具体功能实现)
game.h(头文件,宏,函数声明)
定义的棋盘比展示的棋盘多了两行两列,用于解决查询棋盘边缘格子四周的地雷数量,这样边缘格子也存在上下左右的8个相邻格子.扩宽的格子不设置地雷.
这里可以修改棋盘大小,地雷数量,可以调整难度.
//宏定义
//棋盘数量
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//地雷数量
#define easy_count 10
主函数放在test,c
int main()
{
//输入值
int input = 0;
//雷布置
char mine[ROWS][COLS] = { 0 };
//扫雷展示界面
char show[ROWS][COLS] = { 0 };
//随机种子
srand((unsigned int) time(NULL));
do
{
//菜单
menu();
//选择
printf("请输入选择\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
start = time(NULL);
//游戏
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入.\n");
break;
}
} while (input);
return 0;
}
这里只是一个大体框架,其中的每一个功能函数后面在实现.就比如标记坐标的存储,一开始写的扫雷代码没有这个,后面有了思路在加上的.
//头文件
#include "game.h"
//游戏
void game()
{
//存储标记坐标
int mark[60][2] = { 0 };
int mark_ = 0;//序号
//棋盘初始化
InitBoard(mine, ROWS, COLS, '0');//数组名,数组首元素的地址
InitBoard(show, ROWS, COLS, '*');
//打印棋盘
DisplayBoard(show, ROW, COL,0,0,0);
//布置地雷
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL,0,0,0);//测试代码用,作弊
//扫雷
FindMine(mine, ROW, COL);
}
不用细说,只是普通的printf()函数.
//菜单
void menu()
{
printf("**************************\n");
printf("******** 扫雷 *******\n");
printf("******** 1.play *******\n");
printf("******** 0.exit *******\n");
printf("**************************\n");
}
因为上文说到,需要用到两个二维数组,其中一个用来存储地雷坐标,一个用来展示界面.
所以这里需要两种不同的初始化(0和’*'),用set参数区分.
//棋盘初始化
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
arr[i][j] = set;
}
}
}
打印棋盘,因为上文定义的棋盘arr[ROWS][COLS]比展示的棋盘多了两行两列,所以需要参数int row, int col来确定打印边界,不打印边缘多出来的两行.这里打印棋盘的函数看起来有点长,主要是因为需要打印标记点的坐标,还有不同地雷数目的格子用不同颜色打印,醒目.
函数中调用的彩色打印函数传递的参数是字符串首元素地址,void printf_green(char* s),
为了保证参数的传递和打印格式统一,这里用一个临时数组char tmp[4] = { arr[i][j],32,32,‘\0’ };32为空格的ASCII码值.
//打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("----------扫雷游戏------------\n");
for (j = 0; j <= col; j++)//打印列号
{
printf("%-2d ", j);//打印的棋盘,不改变原有棋盘,所以这里可以为 整形 ,不用 字符型
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%-2d ", i);//打印行号
for (j = 1; j <= col; j++)
{
int jump = 0;//用于跳出多重 for循环
//打印标记坐标
for (int k = 0; k < mark_; k++)
{
if ((i == mark[k][0]) && (j == mark[k][1]) && (arr[i][j] == '*'))
{
printf_red("* ");
jump = 1;
continue;
}
}
if (jump == 1)
{
jump = 0;//还原
continue;
}
//不同地雷数目的格子用不同颜色打印
if (arr[i][j] == '1')
{
char tmp[4] = { arr[i][j],32,32,'\0' };//用于与printf_green参数一致.32为空格的ASCII码值,其实也可以用' ',不过懒得换了
printf_green(tmp);
continue;
}
if (arr[i][j] == '2')
{
char tmp[4] = { arr[i][j],32,32,'\0' };
printf_blue(tmp);
continue;
}
if (arr[i][j] == '3')
{
char tmp[4] = { arr[i][j],32,32,'\0' };
printf_yellow(tmp);
continue;
}
if (arr[i][j] > '3')
{
char tmp[4] = { arr[i][j],32,32,'\0' };
printf_red(tmp);
continue;
}
//除了以上特殊打印,剩下的正常打印
printf("%c ", arr[i][j]);
}
printf("\n");
}
printf("----------扫雷游戏------------\n");
}
利用随机数生成布置雷,需要用到时间戳,rand()函数.随机种子的初始化在main()函数部分. srand((unsigned int) time(NULL));
//布置地雷
//debug: board[][COLS],这里不能是 COL ,否则不完整
void SetMine(char board[ROWS][COLS], int row, int col)
{
//雷坐标
int x = 0;
int y = 0;
//雷数量
int count = easy_count;
while (count)
{
//随机数范围, 1 ~ row
x = rand() % row + 1;
y = rand() % col + 1;
//判断坐标合法性
if (board[x][y] == '0')//随机数范围包含了 x >= 1 && x <= row && y >= 1 && y <= col &&
{
board[x][y] = '1';
count--;
}
}
}
该部分主要实现4个功能:
1.扫雷坐标 2.标记坐标 3.取消上次标记 4.取消某点标记
用switch函数分别对应这4个功能.
1.扫雷: 输入扫雷坐标,先检测坐标的合法性,合法时,将坐标与存储地雷的棋盘board[x][y]作比较,并用CountMine(board, x, y, ROW, COL)函数显示附近地雷的数量.
检查非雷格子数目
count = CheckMine(show, ROW, COL);
通关的标准就是把所有没有地雷的格子都找到.失败这是踩到了地雷.
这里偷懒了, 失败的时候直接用goto语句跳转到 lable处,没有换别的方法.
2.标记坐标: 将输入坐标存入数组,mark_表示序号
mark[mark_][0] = x;
mark[mark_][1] = y;
mark_++;
打印棋盘的函数会检测mark[ ][ ]数组中存储的坐标,如果匹配,就用printf_red("* ");来表示标记的位置.
3.取消上次标记 : 将坐标存入mark[ ][ ]数组表示标记,反之,清除mark[ ][ ]数组里的元素表示删除标记.
mark[mark_][0] = 0;
mark[mark_][1] = 0;
mark_–;
4.取消某点标记: 方法比较简单,就是将输入的坐标依次与mark[ ][ ]数组中存储的坐标相比较,如果有,则清除对应元素.
//扫雷
void FindMine(char board[ROWS][COLS], int row, int col)//board[ROWS][COLS] 应该相当于指针变量
{
//非雷格子数目
int all_count = ROW * COL - easy_count;
int count = 1;
while (count < all_count) //如果初始只有 1 个非雷格子,程序漏洞,通关
{
int x = 0;
int y = 0;
int z = 0;
//清空缓存区无用输入
clear();
printf("请选择输入:> 1.扫雷坐标 2.标记坐标 3.取消上次标记 4.取消某点标记\n");
scanf("%d", &z);
switch(z)
{
case 1:
//清空缓存区无用输入
clear();
printf("输入扫雷坐标:>\n");
scanf("%d %d", &x, &y);
//输入坐标合法性检测
if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '*')
{
//有雷,被炸死,游戏结束
if (board[x][y] == '1')
{
printf_red("很遗憾,你被炸死了,任务失败.\n");
goto lable;
break;
}
//无雷,显示附近的雷,游戏继续
if (board[x][y] == '0')
{
//显示附近的雷
CountMine(board, x, y, ROW, COL);//雷的数量
DisplayBoard(show, ROW, COL);//打印界面
//检查非雷格子数目
count = CheckMine(show, ROW, COL);
}
}
else
{
printf("坐标错误,请重新输入.\n");
}
break;
case 2:
printf("输入标记坐标:>\n");
scanf("%d %d", &x, &y);
//输入坐标合法性检测
if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '*')
{
//存入标记坐标
mark[mark_][0] = x;
mark[mark_][1] = y;
mark_++;
DisplayBoard(show, ROW, COL);//打印界面
}
else
{
printf("坐标错误,请重新输入.\n");
}
break;
case 3:
if (mark_ <= 0)
{
printf("已经没有标记\n");
break;
}
printf("取消上一次标记:>\n");
mark[mark_][0] = 0;
mark[mark_][1] = 0;
mark_--;
DisplayBoard(show, ROW, COL);//打印界面
break;
case 4:
//定点清除标记
printf("输入需清除的标记坐标:>\n");
int x0 = 0;
int y0 = 0;
scanf("%d %d", &x0, &y0);
//输入坐标合法性检测
if (x0 >= 1 && x0 <= row && y0 >= 1 && y0 <= col && show[x0][y0] == '*')
{
int i = 0;
for (i = 0; i < mark_; i++)
{
if ((mark[i][0] == x0) && (mark[i][1] == y0))
{
mark[i][0] = 0;
mark[i][1] = 0;
continue;
}
}
DisplayBoard(show, ROW, COL);//打印界面
}
else
{
printf("坐标错误,请重新输入.\n");
}
break;
default:
printf("坐标错误,请重新输入.\n");
}
}
if (count == all_count)
{
end = time(NULL);//结束时间
unsigned int time = (unsigned int)difftime(end,start);//计算耗时 /秒
printf_green("恭喜你,游戏通关!(~ ̄▽ ̄)~\n");
printf("\033[0m\033[1;32m你总共用时: %d 秒\033[0m\n",time);
//清除存储的标记坐标
while (mark_)
{
mark[mark_][0] = 0;
mark[mark_][1] = 0;
mark_--;
}
}
lable:
if (count < all_count)
{
end = time(NULL);//结束时间
unsigned int time = (unsigned int)difftime(end, start);//计算耗时 /秒
printf("\033[0m\033[1;31m你耗费了: %d 秒\033[0m\n", time);
//清除存储的标记坐标
while (mark_)
{
mark[mark_][0] = 0;
mark[mark_][1] = 0;
mark_--;
}
}
}
这里主要实现的功能有:
1.检测坐标点四周格子的地雷数量,并将地雷数量存入展示界面的数组show[x][y].
2.如果被检查格子四周地雷数目为0,则由该格子想四周展开,检测相邻格子地雷数量,直到遇到四周地雷数量不为0的格子停下.该功能在游戏中表现为检查一个格子展开一片的情景.
这里用函数的递归实现.
//显示附近的雷
void CountMine(char board[ROWS][COLS], int x, int y,int row,int col)
{
int i = 0;
int j = 0;
int count = 0;
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{ //&& (i !=0 || j !=0)可省略,因为中心坐标无雷才能进行这一步
if (board[x+i][y+j] == '1' && (i !=0 || j !=0) )//&& (i !=0 || j !=0)作用:i,j不同时为 0
{
count++;
}
}
}
//存入(x,y)坐标周围雷数量
show[x][y] = count + '0'; //原有值 '*' ,不是 '0'
//一个雷也没有,爆炸式展开
if (count == 0)
{
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{
//注意:不往回路爆炸展开,防止栈溢出 && show[x + i][y + j] == '*' ,不等于 '*' ,则是展开过的地方
//爆炸展开边界 && x + i >= 1 && x + i <= row && y + j >= 1 && y + j <= col
if (x + i >= 1 && x + i <= row && y + j >= 1 && y + j <= col && show[x + i][y + j] == '*')
CountMine(board, x + i, y + j, row, col);
}
}
}
}
//检查非雷格子数目
int CheckMine(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)//中心无雷才能到这一步,所以不用排除中心
{
if (board[i][j] != '*')
count++;
}
}
return count;
}
//彩色打印函数
//格式 \033[输入属性m 代码属性;前景色;后景色
// 0 重置 1 高亮
//前景色 31 红 32 绿 33 黄 34 蓝
//后景色 40 黑 41 红
void printf_red(char* s)
{
printf("\033[0m\033[1;31m%s\033[0m", s);
}
void printf_green(char* s)
{
printf("\033[0m\033[1;32m%s\033[0m", s);
}
void printf_yellow(char* s)
{
printf("\033[0m\033[1;33m%s\033[0m", s);
}
void printf_blue(char* s)
{
printf("\033[0m\033[1;34m%s\033[0m", s);
}
函数中出现的clear()本来打算清空缓存区无用输入,不过现在没有思路,先留着
//清空缓存区无用输入
void clear()
{
//暂时没有思路
}
将上文中提到的函数放在game.h中声明
#pragma once
//宏定义
//棋盘数量
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//地雷数量
#define easy_count 10
//头文件
#include
#include
#include
//变量声明
//雷布置
char mine[ROWS][COLS];
//扫雷展示界面
char show[ROWS][COLS];
//时间记录
time_t start, end;
//存储标记坐标
int mark[60][2];
int mark_;
//函数声明
//菜单
void menu();
//游戏
void game();
//棋盘初始化
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 board[ROWS][COLS],int row,int col);//保证棋盘大小的一致性
//扫雷
void FindMine(char board[ROWS][COLS],int row,int col);
//显示附近的雷
void CountMine(char board[ROWS][COLS], int x, int y, int row, int col);
//检查非雷格子数目
int CheckMine(char board[ROWS][COLS], int row, int col);
//彩色打印函数
void printf_red(char* s);
void printf_green(char* s);
void printf_yellow(char* s);
void printf_blue(char* s);
//清空缓存区无用输入
void clear();
上文将头文件集中放在game.h
所以在game.c和test.c中需要引用#include “game.h”
#define _CRT_SECURE_NO_WARNINGS是为了解决visual sutdio 2022中scanf()警告的问题.
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
#pragma once
//宏定义
//棋盘数量
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//地雷数量
#define easy_count 10
//头文件
#include
#include
#include
//变量声明
//雷布置
char mine[ROWS][COLS];
//扫雷展示界面
char show[ROWS][COLS];
//时间记录
time_t start, end;
//存储标记坐标
int mark[60][2];
int mark_;
//函数声明
//菜单
void menu();
//游戏
void game();
//棋盘初始化
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 board[ROWS][COLS],int row,int col);//保证棋盘大小的一致性
//扫雷
void FindMine(char board[ROWS][COLS],int row,int col);
//显示附近的雷
void CountMine(char board[ROWS][COLS], int x, int y, int row, int col);
//检查非雷格子数目
int CheckMine(char board[ROWS][COLS], int row, int col);
//彩色打印函数
void printf_red(char* s);
void printf_green(char* s);
void printf_yellow(char* s);
void printf_blue(char* s);
//清空缓存区无用输入
void clear();
#define _CRT_SECURE_NO_WARNINGS
//数组应用,扫雷游戏2.0
//功能优化:
// 1.爆炸式边界展开
// 2.增加标记功能 (功能优化3.0)
// 3.操作步数记录 (为了更具有意义,改为时间记录)
//头文件
#include "game.h"
//游戏
void game()
{
//存储标记坐标
int mark[60][2] = { 0 };
int mark_ = 0;//序号
//棋盘初始化
InitBoard(mine, ROWS, COLS, '0');//数组名,数组首元素的地址
InitBoard(show, ROWS, COLS, '*');
//打印棋盘
DisplayBoard(show, ROW, COL,0,0,0);
//布置地雷
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL,0,0,0);//测试代码用,作弊
//扫雷
FindMine(mine, ROW, COL);
}
int main()
{
//输入值
int input = 0;
//雷布置
char mine[ROWS][COLS] = { 0 };
//扫雷展示界面
char show[ROWS][COLS] = { 0 };
//随机种子
srand((unsigned int) time(NULL));
do
{
//菜单
menu();
//选择
printf("请输入选择\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
start = time(NULL);
//游戏
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入.\n");
break;
}
} while (input);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
//菜单
void menu()
{
printf("**************************\n");
printf("******** 扫雷 *******\n");
printf("******** 1.play *******\n");
printf("******** 0.exit *******\n");
printf("**************************\n");
}
//棋盘初始化
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
arr[i][j] = set;
}
}
}
//打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("----------扫雷游戏------------\n");
for (j = 0; j <= col; j++)//打印列号
{
//printf("%c ", j + '0');
printf("%-2d ", j);//打印的棋盘,不改变原有棋盘,所以这里可以为 整形 ,不用 字符型
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%-2d ", i);//打印行号
for (j = 1; j <= col; j++)
{
int jump = 0;//用于跳出多重 for循环
//标记坐标
for (int k = 0; k < mark_; k++)
{
if ((i == mark[k][0]) && (j == mark[k][1]) && (arr[i][j] == '*'))
{
printf_red("* ");
jump = 1;
continue;
}
}
if (jump == 1)
{
jump = 0;//还原
continue;
}
//不同地雷数目的格子用不同颜色打印
if (arr[i][j] == '1')
{
char tmp[4] = { arr[i][j],32,32,'\0' };//用于与printf_green参数一致.32为空格的ASCII码值,其实也可以用' ',不过懒得换了
printf_green(tmp);
continue;
}
if (arr[i][j] == '2')
{
char tmp[4] = { arr[i][j],32,32,'\0' };
printf_blue(tmp);
continue;
}
if (arr[i][j] == '3')
{
char tmp[4] = { arr[i][j],32,32,'\0' };
printf_yellow(tmp);
continue;
}
if (arr[i][j] > '3')
{
char tmp[4] = { arr[i][j],32,32,'\0' };
printf_red(tmp);
continue;
}
printf("%c ", arr[i][j]);
}
//除了以上特殊打印,剩下的正常打印
printf("\n");
}
printf("----------扫雷游戏------------\n");
}
//布置地雷
//debug: board[][COLS],这里不能是 COL ,否则不完整
void SetMine(char board[ROWS][COLS], int row, int col)
{
//雷坐标
int x = 0;
int y = 0;
//雷数量
int count = easy_count;
while (count)
{
//随机数范围, 1 ~ row
x = rand() % row + 1;
y = rand() % col + 1;
//判断坐标合法性
if (board[x][y] == '0')//随机数范围包含了 x >= 1 && x <= row && y >= 1 && y <= col &&
{
board[x][y] = '1';
count--;
}
}
}
//扫雷
void FindMine(char board[ROWS][COLS], int row, int col)//board[ROWS][COLS] 应该相当于指针变量
{
//非雷格子数目
int all_count = ROW * COL - easy_count;
int count = 1;
while (count < all_count) //如果初始只有 1 个非雷格子,程序漏洞,通关
{
int x = 0;
int y = 0;
int z = 0;
//清空缓存区无用输入
clear();
printf("请选择输入:> 1.扫雷坐标 2.标记坐标 3.取消上次标记 4.取消某点标记\n");
scanf("%d", &z);
switch(z)
{
case 1:
//清空缓存区无用输入
clear();
printf("输入扫雷坐标:>\n");
scanf("%d %d", &x, &y);
//输入坐标合法性检测
if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '*')
{
//有雷,被炸死,游戏结束
if (board[x][y] == '1')
{
printf_red("很遗憾,你被炸死了,任务失败.\n");
goto lable;
break;
}
//无雷,显示附近的雷,游戏继续
if (board[x][y] == '0')
{
//显示附近的雷
CountMine(board, x, y, ROW, COL);//雷的数量
DisplayBoard(show, ROW, COL);//打印界面
//检查非雷格子数目
count = CheckMine(show, ROW, COL);
}
}
else
{
printf("坐标错误,请重新输入.\n");
}
break;
case 2:
printf("输入标记坐标:>\n");
scanf("%d %d", &x, &y);
//输入坐标合法性检测
if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '*')
{
//存入标记坐标
mark[mark_][0] = x;
mark[mark_][1] = y;
mark_++;
DisplayBoard(show, ROW, COL);//打印界面
}
else
{
printf("坐标错误,请重新输入.\n");
}
break;
case 3:
if (mark_ <= 0)
{
printf("已经没有标记\n");
break;
}
printf("取消上一次标记:>\n");
mark[mark_][0] = 0;
mark[mark_][1] = 0;
mark_--;
DisplayBoard(show, ROW, COL);//打印界面
break;
case 4:
//定点清除标记
printf("输入需清除的标记坐标:>\n");
int x0 = 0;
int y0 = 0;
scanf("%d %d", &x0, &y0);
//输入坐标合法性检测
if (x0 >= 1 && x0 <= row && y0 >= 1 && y0 <= col && show[x0][y0] == '*')
{
int i = 0;
for (i = 0; i < mark_; i++)
{
if ((mark[i][0] == x0) && (mark[i][1] == y0))
{
mark[i][0] = 0;
mark[i][1] = 0;
continue;
}
}
DisplayBoard(show, ROW, COL);//打印界面
}
else
{
printf("坐标错误,请重新输入.\n");
}
break;
default:
printf("坐标错误,请重新输入.\n");
}
}
if (count == all_count)
{
end = time(NULL);//结束时间
unsigned int time = (unsigned int)difftime(end,start);//计算耗时 /秒
printf_green("恭喜你,游戏通关!(~ ̄▽ ̄)~\n");
printf("\033[0m\033[1;32m你总共用时: %d 秒\033[0m\n",time);
//清除存储的标记坐标
while (mark_)
{
mark[mark_][0] = 0;
mark[mark_][1] = 0;
mark_--;
}
}
lable:
if (count < all_count)
{
end = time(NULL);//结束时间
unsigned int time = (unsigned int)difftime(end, start);//计算耗时 /秒
printf("\033[0m\033[1;31m你耗费了: %d 秒\033[0m\n", time);
//清除存储的标记坐标
while (mark_)
{
mark[mark_][0] = 0;
mark[mark_][1] = 0;
mark_--;
}
}
}
//显示附近的雷
void CountMine(char board[ROWS][COLS], int x, int y,int row,int col)
{
int i = 0;
int j = 0;
int count = 0;
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{ //&& (i !=0 || j !=0)可省略,因为中心坐标无雷才能进行这一步
if (board[x+i][y+j] == '1' && (i !=0 || j !=0) )//&& (i !=0 || j !=0)作用:i,j不同时为 0
{
count++;
}
}
}
//存入(x,y)坐标周围雷数量
//show[x][y] = 1+ count + '0';//char类型,不是 int ,按照ASCII码转换 +1证明求过该坐标
show[x][y] = count + '0'; //不用 +1 证明,因为原有值 '*' ,不是 '0'
//一个雷也没有,爆炸式展开
if (count == 0)
{
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{
//注意:不往回路爆炸展开,防止栈溢出 && show[x + i][y + j] == '*' ,不等于 '*' ,则是展开过的地方
//爆炸展开边界 && x + i >= 1 && x + i <= row && y + j >= 1 && y + j <= col
if (x + i >= 1 && x + i <= row && y + j >= 1 && y + j <= col && show[x + i][y + j] == '*')
CountMine(board, x + i, y + j, row, col);
}
}
}
//show[x][y] =count + '0' -1; // -1还原坐标
}
//检查非雷格子数目
int CheckMine(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (board[i][j] != '*')
count++;
}
}
return count;
}
//彩色打印函数
//格式 \033[输入属性m 代码属性;前景色;后景色
// 0 重置 1 高亮
//前景色 31 红 32 绿 33 黄 34 蓝
//后景色 40 黑 41 红
void printf_red(char* s)
{
printf("\033[0m\033[1;31m%s\033[0m", s);
}
void printf_green(char* s)
{
printf("\033[0m\033[1;32m%s\033[0m", s);
}
void printf_yellow(char* s)
{
printf("\033[0m\033[1;33m%s\033[0m", s);
}
void printf_blue(char* s)
{
printf("\033[0m\033[1;34m%s\033[0m", s);
}
//清空缓存区无用输入
void clear()
{
//暂时没有思路
}
初学者,存在不足,如果你有好的想法,请在评论区留言,谢谢指教.
B站C语言教程 扫雷
printf彩色输出
c语言如何跳出多层循环描述