开发环境
Visual Stdio 2022.
总体实现流程
在调试窗口界面打印一个简易的游戏开始界面 -> 初始化棋盘 -> 布置雷 -> 显示棋盘 -> 玩家输入坐标排雷或者标记玩家设想雷的位置 -> 排除所有雷或者选中雷 -> 游戏结束;
具体实现思路及代码
开始界面
在调试窗口打印玩家可以做出的选择:开始游戏/退出游戏。模块代码实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//扫雷
void windows()//游戏开始界面
{
printf("********************\n");
printf("******1.play********\n");
printf("******0.exit********\n");
printf("********************\n");
printf("请输入您的选择:");
}
void windows1()//该把游戏结束后的界面
{
printf("********************\n");
printf("******1.go on********\n");
printf("******0.exit********\n");
printf("********************\n");
printf("请输入您的选择:");
}
int main()
{
int choose = 0;
srand((unsigned int)(time(NULL)));
windows();
do
{
scanf("%d",&choose);
switch (choose)
{
case 1:
game();
windows1();
break;
case 0: printf("退出游戏");
break;
default:printf("输入错误,请重新输入:");
break;
}
} while (choose);
return 0;
}
棋盘设置
本代码实现的在9*9的棋盘中进行扫雷的,根据扫雷的游戏规则当选中的方格为非雷时,应该在该位置显示以此为中心的3*3方格中雷的个数,代码中实际所设置的棋盘为11*11的规格,这样就可以使边界线上的方格使用和其它方格一样的方法统计周围雷的个数,方便运算。
棋盘初始化
在代码中设置两个大小相同的棋盘,一个为真正的含雷的棋盘(mine[][]),另一个则是呈现在玩家眼前的棋盘(展示棋盘)(show[][])。在真正含雷的棋盘中通过用字符 '1' 表示雷,字符 '0' 表示非雷;在展示棋盘中通过用字符 '*' 表示未进行的排雷的方格。因此在开始阶段中mine[][]数组应该全部初始化为字符 '0' ,而展示棋盘应该全部初始化为字符 '*' 。为了便于观察每个方格的坐标,可以在调试窗口打印x,y轴的刻度值(1~9)。其模块化代码实现:
void ckboard(char arr[ROWS][COLS], int row ,int col,char str)//棋盘赋值
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
arr[i][j] = str;
}
}
}
void display(char arr[ROWS][COLS], int row, int col)//棋盘在调试窗口打印的函数
{
int i = 0, j = 0;
for (i = 0; i < row - 1; i++)
{
for (j = 0; j < col - 1; j++)
{
if (i == 0)
printf("%d ", j);
else if (j == 0)
printf("%d ", i);
else
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
//调用方法
// ckboard(mine, ROWS, COLS, '0');//初始化真正的棋盘为字符'0';
// ckboard(show, ROWS, COLS, '*');//初始化呈现在玩家眼前的棋盘为字符'*';
布置雷
系统每次产生两个1~9的随机数分别对应x,y的值,即组合成对应的坐标,并将该坐标中对应的字符赋值为 '1' 表示此处放置雷;依次执行上述步骤直到所有雷都布置完成。其实现代码:
void set_mine(char arr[ROWS][COLS], int row, int col)
{
int set = 0, x = 0, y = 0 ;
set = mine_count;//所放置雷的总个数
while (set)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
set--;
}
}
}
排雷
其思路就是,玩家输入一个坐标,然后程序检测该坐标在真正的含雷棋盘中对应的是不是雷(字符 '1' ),如果不是则在展示棋盘show[][]中该坐标对应的字符赋值为其周围雷的个数,由于mine[][]数组中只有 ‘1’ ,和 ‘0’ 两个字符,因此mine[][]中的字符和字符 '0'进行做差后的值为1(表示该坐标为雷)或者0(该坐标为非雷),将做差后的值进行累加,即可表示,该区域内所含雷的个数。
一次排多个
为了让游戏能有更好的体验,如果玩家选中的坐标周围雷的个数为零的时候,就把与该坐标四周连续的坐标(四个角的坐标也算),并且该连续的坐标周围雷的个数也为零的坐标进行排除,直到遇见一个周围雷的个数不为0是,才结束本轮的一次多排任务。
标记雷
玩家可以通过输入两个都大于9并且相同的数,以此来表示玩家选择进入标记模式,然后根据系统提示输入要标记的坐标,输入坐标后就可以在show[][]棋盘对应的坐标点中展示字符 '!' ,以此对雷进行标记。当玩家把所有雷都排除了所有雷,便结束游戏,系统打印"恭喜您,闯关成功",提示玩家通关了;或者玩家选中的坐标为雷,此时游戏也将结束,并且系统打印"您已经被炸死了"。当游戏结束后,系统同时也会提示玩家是否还要继续玩,然后玩家可以根据提示继续做出选择。其模块化代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
char mine[ROWS][COLS];//真正含雷棋盘
char show[ROWS][COLS];//展示棋盘
int cho_x = 0, cho_y = 0;//选择的坐标
int flag = 0;
int number = 0;
int account_mine(char arr[ROWS][COLS], int x, int y)//该坐标周围的雷数
{
return arr[x - 1][y - 1] + arr[x - 1][y] + arr[x - 1][y + 1] +
arr[x][y - 1] + arr[x][y + 1] +
arr[x + 1][y - 1] + arr[x + 1][y] + arr[x + 1][y + 1] - 8 * '0';
}
void exc_mine(char arr[ROWS][COLS], int x, int y)//排雷 一次多排
{
int i = 0;
if (show[x][y] == '*')
{
if (arr[x][y] != '1')
{
show[x][y] = arr[x][y] + account_mine(arr, x, y);
number++;
for (i = 1; i <= ROW - x; i++)
{
if (account_mine(arr, x + i, y) == 0 && arr[x + i][y] != '1')
{
show[x + i][y] = arr[x + i][y] + account_mine(arr, x + i, y);
number++;
}
else
break;
}
for (i = 1; i <= ROW - y; i++)
{
if (account_mine(arr, x, y + i) == 0 && arr[x][y + i] != '1')
{
show[x][y + i] = arr[x][y + i] + account_mine(arr, x, y + i);
number++;
}
else
break;
}
for (i = 1; i < ROW - x; i++)
{
if (account_mine(arr, x + i, y + i) == 0 && arr[x + i][y + i] != '1')
{
show[x + i][y + i] = arr[x + i][y + i] + account_mine(arr, x + i, y + i);
number++;
}
else
break;
}
}
else
{
printf("您已经被炸死了\n");
flag = 1;
}
}
else
printf("该坐标已经排查,请重输!\n");
}
void mark_mine(char arr[ROWS][COLS], int x, int y)//标记雷
{
arr[x][y] = '!';
}
void game()//核心
{
flag = 0;
number = 0;
ckboard(mine, ROWS, COLS, '0');//初始化真正的棋盘为字符'0';
ckboard(show, ROWS, COLS, '*');//初始化呈现在玩家眼前的棋盘为字符'*';
set_mine(mine, ROW, COL);//将预设的雷依次放入真正的棋盘中
display(show, ROWS, COLS);//在调试界面显示
//display(mine, ROWS, COLS);
while (number!= (ROW*COL- mine_count))
{
mark_ok:
printf("请输入您选择的坐标:");
flag_in:
scanf("%d %d", &cho_x, &cho_y);
if (cho_x > 9 && cho_y > 9 && cho_x == cho_y)//进入标记模式 一次只能标记一个
{
printf("请输入您标记的坐标:");
scanf("%d %d", &cho_x, &cho_y);
mark_mine(show, cho_x, cho_y);
display(show, ROWS, COLS);
goto mark_ok;
}
else if(cho_x > 9 && cho_y > 9 && cho_x != cho_y)
{
printf("输错了请重新输入:");
goto flag_in;
}
exc_mine(mine, cho_x, cho_y);
display(show, ROWS, COLS);
//display(mine, ROWS, COLS);
if (flag == 1)//炸死了;
break;
}
if (number == (ROW * COL - mine_count))
{
printf("********************\n");
printf("恭喜您,闯关成功\n");
printf("********************\n");
printf("雷的分布如下:\n");
display(mine, ROWS, COLS);
}
}
结束
以上就是我在近期所学C语言编程过程中,所总结出实现扫雷游戏的整个过程。