扫雷是一款大众类的益智小游戏,于1992年发行。游戏目标是在最短的时间内根据点击格子出现的数字找出所有非雷格子,同时避免踩雷,踩到一个雷即全盘皆输。
接下来我们来用上一章所说的多文件方式来编写代码实现扫雷游戏
game.h
game,c
test,c
void menu()
{
printf("**************************\n");
printf("******* 1.play ********\n");
printf("******* 0.exit ********\n");
printf("**************************\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);switch (input)
{
case 1:
game();
break;
case 0:
return 0;
printf("退出游戏");
break;
default:
printf("选择错误,请重新选择");
break;
}
} while (input);}
由主函数可知需要编写一个game()函数作为游戏模块。它需要包含初始化棋盘,打印棋盘,布置雷以及扫雷这几项功能。
棋盘样式:可以想到要可以用二维数组来实现棋盘
* |
规定:有雷的地方用
在棋盘中有雷的地方用1表示,没有雷的地方用0来表示
但是扫雷游戏还要实现一个功能就是如果选中单元格不是雷的话就显示周围一圈雷的数量,所以如果周围一圈只有一个雷,这里显示的数字1就会和雷1混淆起来,所以我们才用在两个棋盘上打印的方法一个进行布置雷的操作,一个进行显示周围雷的数量的操作(初始化为‘*’)。
看上表格中‘*’位置,如果此时排查到这个地方就会发现如果对周围一圈进行排查就会溢出数组,所以我们需要扩建数组。这是棋盘变成11*11,但是游戏操作还是在9*9内进行。
game.h
#pragma once
#include
#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//申明函数//set说明:因为mine要初始化成‘0’ show要初始化成‘*’所以加入一个初始化参数
game.c
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++)
board[i][j] = set;
}
}
game.h
//打印棋盘
void Display(char arr[ROWS][COLS], int row, int col);
game.c
void Display(char arr[ROWS][COLS], int row, int col)
{
int i = 0, j = 0;//打印列坐标
for (i = 0; i <= col; i++)
{
printf("%d ",i);//打印行坐标
}
putchar('\n');
for (i = 1; i <=row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
printf("%c ", arr[i][j]);
printf("\n");
}
}
效果展示:
mine
show
每次布置的雷肯定都是随机的,所以采用rand和srand结合产生随机数(与之前的猜数字游戏思想一样) ,同时还要设置雷的数量(10)
game.h
#include
#include#define EASY_count 10
//布置雷
void SetMine(char arr[ROWS][COLS], int row, int col);
game.c
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = EASY_count;
while (count)
{
int x = rand() % row + 1;//1~9
int y = rand() % col + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}}
//rand在test.c中的主函数编写(后面会讲到)
效果展示:
上面提到排雷包括两方面,一个是查找位置是雷游戏结束,还有一个是查找位置不是雷返回周围一圈雷的数量
game.h
//排雷
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col);
game.c
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row, int col)
{
int win = 0;//查找次数
int x = 0, y = 0;
while (win < row * col - EASY_count)//总格数-雷数等于没有雷的个数
{
printf("请输入要排查的坐标:");
scanf("%d %d", &x, &y);
if (x > 0 && x <= row && y > 0 && y <= col)//判断查找坐标不能跃出数组界限
{
if (mine[x][y] == '1')
{
printf("很遗憾你被炸死了\n");
Display( mine,ROW, COL);
break;
}
else //show是char 类型的里面存放字符
{ //数字字符ASCll是连续的由‘1’-‘0’=1可得‘0’+1=‘1’
show[x][y] = CountMine(mine, x, y)+'0';//返回周围一圈雷的数量
Display(show, ROW, COL);
win++;
}
}
else
{
printf("输入非法坐标,请重新输入");
}
}
if (win == row * col - EASY_count)
{
printf("恭喜你,排雷成功\n");
Display(mine, ROW, COL);
}
}
由上述代码可知想要返回周围雷的个数还需定义编写一个函数CountMine(char mine[ROWS][COLS], int x, int y)
game.c
int CountMine(char mine[ROWS][COLS], int x, int y)
{
int sum = 0;
int i = 0, j = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
sum += mine[i][j] - '0';//数字字符‘0’,‘1’……的ASCll是连续的‘1’-‘0’=4
}
return sum;
}
这样就完成了扫雷游戏代码的编写。最后我们来一个汇总
game.h
#pragma once
#include
#include
#include#define EASY_count 10
#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//打印棋盘
void Display(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);
game.c
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"int CountMine(char mine[ROWS][COLS], int x, int y)
{
int sum = 0;
int i = 0, j = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
sum += mine[i][j] - '0';
}
return sum;
}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++)
board[i][j] = set;
}
}void Display(char arr[ROWS][COLS], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i <= col; i++)
{
printf("%d ",i);
}
putchar('\n');
for (i = 1; i <=row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
printf("%c ", arr[i][j]);
printf("\n");
}
}void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = EASY_count;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}}
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row, int col)
{
int win = 0;
int x = 0, y = 0;
while (win < row * col - EASY_count)
{
printf("请输入要排查的坐标:");
scanf("%d %d", &x, &y);
if (x > 0 && x <= row && y > 0 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遗憾你被炸死了\n");
Display( mine,ROW, COL);
break;
}
else
{
show[x][y] = CountMine(mine, x, y)+'0';
Display(show, ROW, COL);
win++;
}
}
else
{
printf("输入非法坐标,请重新输入");
}
}
if (win == row * col - EASY_count)
{
printf("恭喜你,排雷成功\n");
Display(mine, ROW, COL);
}
}
test.c
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void menu()
{
printf("**************************\n");
printf("******* 1.play ********\n");
printf("******* 0.exit ********\n");
printf("**************************\n");
}void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');//Display(mine, ROW, COL);
//Display(show, ROW, COL);SetMine(mine,ROW,COL);
Display(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("退出游戏");
break;
default:
printf("选择错误,请重新选择");
break;
}
} while (input);return 0;
}
最后这只是一个扫雷游戏的基础实现与网页扫雷可以标记雷的位置以及可以一次性扫开一片区域还有一定差距。下章我们会实现扫雷代码升级,想要了解的小伙伴点点关注,支持一下。
目录
实现步骤:
1.打印菜单
2. 编写主函数(同猜数字游戏)
3.game()函数实现
扫雷游戏需要一个棋盘来进行相应操作这里以9*9为例