可以在此处参考代码:gitee仓库代码提交
扫雷游戏实现大致思路:
在9*9的二维数组当中,找到隐藏的10个雷(EASY 版本的实现)
就需要两个二维数组1个存放随机生成的雷,1个存放需要排查雷的棋盘(显示在控制台,用户所看到的)
用户通过排查坐标,来判断雷所在的位置,那么就应该在用户选择坐标显示出周围8格存在雷的个数
选择的坐标若是雷,被炸死,若不是雷,继续排查(循环)全部排查完毕游戏结束
打印菜单,判断用户是否要进行游戏
用户至少进来1次,选择do while循环
代码如下:
#include
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:
printf("扫雷游戏\n");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
基本菜单打印逻辑实现,选择1将让用户进入游戏
那么控制台上应该显示出来所要排雷的99二维数组进行排雷
==重点:>当我们在检测坐标周围8个坐标时,位于边缘的坐标的检测十分不方便。
于是我们构建一个1111的二维数组,方便我们排查边缘坐标的雷,
而放置雷任然存放在99的二维数组当中,控制台显示的也只是99的二维数组==
多说无益,上代码实现
存放雷的二维数组,放置的雷用字符1表示,无雷的位置用字符0表示
在控制台上显示的二维数组,未排查的坐标用字符显示,以表示神秘,排查出来的坐标显示出周围8格的雷数总和(1111)
(显示出来99)
DisplayBoard打印棋盘,传参为ROW,COL 只打印99
但是board[ ][ ]
里面还是ROWS,COLS,因为在创建board的时候就是ROWS和COLS
test.c 中game代码如下:
void game()
{
//分别创建11*11的雷和排查雷的二维数组 mine 和 show
char mine[ROWS][COLS] = { 0 };
//雷棋盘
InitBoard(mine, ROWS, COLS,'0');
//显示雷棋盘
// 放置雷 同样的传参传的是row,col(在9*9的棋盘中放雷)
DisplayBoard(mine, ROW, COL);
//扫描棋盘
char show[ROWS][COLS] = { 0 };
InitBoard(show, ROWS, COLS, '*');
//显示扫描棋盘
DisplayBoard(show, ROW, COL);
}
game.c中 初始化与显示代码
#include "game.h"
//初始化11*11的二维数组
void InitBoard(char board[ROWS][COLS], int rows, int cols , char set)
{
int i = 0, j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
//雷棋盘 初始化全为0
//扫描棋盘 全初始化为*
// 设置set 将要初始化的字符传过来
board[i][j] = set;
}
}
}
// 打印出来9*9 传过来的参数是row*col 下标是从1开始
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0, j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j < col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
放雷就涉及到rand函数生成随机数的问题
// 放雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
//需要循环不断地生成随机雷 用while循环
while (count)
{
//rand 生成的随机数%上row是0~8,所以需要+1
int x = rand() % row + 1;
int y = rand() % col + 1;
//可放置雷的情况
if (board[x][y] == '0')
{
//字符1表示放置了雷
board[x][y] = '1';
count--;
}
}
}
十个雷就在棋盘中放置好了,接下来就是找到这十个雷,当然在排雷之前先对控制台的界面进行优化
1、雷的信息不能被用户看到,也就是不打印雷
2、把坐标标出来方便用户找到所要排查的坐标(优化Display函数)
优化过后的DisplayBoard代码:
// 打印出来9*9 传过来的参数是row*col 下标是从1开始
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0, j = 0;
// 这里加入列号
for (j = 0; j <= col; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
// 这里加入行号
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
只显示出要排雷的二维数组9*9,优化完成。下面就是用户排雷的实现
排雷基本思路,判断坐标处是不是雷,不是雷返回周围雷的个数
//返回周围雷的个数 用int返回个数 这里面的mine[x][y]都是字符,在内存中存储的是对应的ASCII码值 ,所以要减去8个字符0,来确定个数
int MineCount(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x - 1][y] +
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, y = 0;
// 通过win判断循环次数,若棋盘上可以排查的位置都已经找到,那么循环结束
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 (show[x][y] == '*')
{
// 雷
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
break;
}
else
{
// 没踩到雷,返回周围雷的个数
int ret = MineCount(mine, x, y);
show[x][y] = ret + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("不可重复排查,请重新输入\n");
}
}
else
{
printf("输入坐标不合法,请重新输入\n");
}
}
// 通过win判断循环次数,若棋盘上可以排查的位置都已经找到,那么排雷成功
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
}
}
扫雷的难点1:
初始化board是1111的二维数组(为了方便处理边界的坐标周围雷的情况),这个点想不到
扫雷的难点2:
也正是因为1111和9*9 所以在函数传参的过程中,需要想清楚该传ROW还是ROWS
数组传参拿数组接收 board[ROW][COL]
扫雷的难点3:
返回坐标周围的雷的个数 居然只需要return 坐标周围的字符减去8个’0’字符就行,没有采用if…else…这种结构(这样太麻烦了)