代码分析
我的这个扫雷是简单版的,复杂版的点到周围没有雷的格子,会扩散展开一大片区域,我们的这个扫雷游戏只能一个一个格子地排雷,望读者周知。
首先,要实现一个简单的扫雷游戏,我们需要确定雷用什么表示,没有雷用什么表示,我们这个游戏的雷用1字符表示,没有雷用0字符表示,这里可能会出现分歧,因为当我们的格子周围有1个雷的时候,显示的是1,所以为了避免这种分歧,我们可以创建两个棋盘,一个是可以展示出所有雷信息的棋盘,一个是遮挡住信息的棋盘。有人很疑惑,为什么雷设置为1和格子周围有一个雷显示为1起了冲突,我还是要将雷设置为1。这里需要涉及一个小心眼:我们都知道0字符的ASCLL码值是32,当我们想让0数字和0字符之间转换的时候,数字0+0字符的ASCLL码值就得到了0字符的ASCLL码值,同样的,任何一个数字加上0字符的ASCLL码值同样等于对应字符的ASCLL码值,对应字符的ASCLL码值减去0字符的ASCLL码值等于对应数字。这在我们后面计算这一个格子周围有多少雷提供了便利。
创建棋盘
我们先要创建一个菜单来供玩家选择开始游戏还是退出游戏,然后我们要创建两个棋盘,一个棋盘是放置雷的棋盘,另一个棋盘是用于玩家排雷的棋盘,两个棋盘互不干扰,又相互联系。我们要在自己创建 的头文件里定义ROW COL为9定义ROWS COLS为11,后面肯定有很多地方要用到9和11这两个数字,这样定义标识符常量,后期我们就好使用了。
然后初始化棋盘,创建两个二维数组,这里我们要考虑到棋盘边缘的格子,电脑判断的还是他周围的8个格子,因此在创建棋盘的时候我们要创建11×11的棋盘,防止判断棋盘边缘地区的时候出现溢出现象,但实际上我们玩家要判断的区域只有9×9的棋盘。然后初始化棋盘,先把放置雷的棋盘里面全部设置为0,也就是先不放置雷在里面,然后玩家游玩的那个棋盘全部放置*,代表未知。这里我们可以用同一个函数实现,只不过是放置的字符不同罢了,我们可以传递0字符和*字符给函数就可以完成一个函数初始化两个棋盘的工作。
这就是初始话棋盘的代码:
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;
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");
}
这里需要主义的就是,我在其中实现了一个行和列的提示。
放置雷
接下来就需要往棋盘里面放置雷,9×9的棋盘里面有10个雷,所以我们需要随机放置10个雷,这里涉及一个时间戳d的概念,具体可以自行在csdn里面搜索了解。用到了rand()和srand()函数,rand就是随机取数值的函数,这里我们只需要1-9之间的数字,也就是只需要在9×9的格子里放置炸弹,所以我们用rand()%9得到的数字是0-8,写成rand()&9+1就是1-9之间的数字了。
void Setmine(char board[ROWS][COLS], int row, int col)
{
int count = NUM;
while (count)
{
int y = rand() % col + 1;
int x = rand() % row + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
排雷
我们排雷的时候需要放置雷的那个棋盘的反馈,也就是反馈那一个格子周围有多少个雷,由此可以看出两个棋盘互不干扰,但是因为游戏的缘故又互相联系,所以在排雷的这个函数,我们需要传递两个二维数组的信息过去,以便于在放置雷的棋盘判断周围有多少个雷,然后反馈雷的数字给玩家游玩的棋盘。
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;//win是排雷次数,因为有10个雷,81个格子,10个雷,所以排雷个数要达到71个;
while (win < row * col - NUM)
{
printf("请输入要查询的坐标:\n");
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 = Getmine(mine, x, y);
show[x][y] = count + '0';
Displayboard(show, ROW, COL);
win++;
}
}
else
{
printf("坐标输入错误,请重新输入!!\n");
}
}
if (win == row * col - NUM)
{
printf("恭喜您,排雷成功!!\n");
Displayboard(mine, ROW, COL);
}
}
这里,我们也重新创建了一个函数,用来判断,那一个格子周围有多少个雷,用排雷的函数调用判断格子周围有多少个雷的函数即可,这样显得排雷的函数没有这么繁琐,也更加美观。
这里我们要了解的是我们需要判断的是那一个格子周围的格子是否有雷,也就是以那个格子为起点的周围八个格子雷的情况,这里我们可以直接表示了。
int Getmine(char mine[ROWS][COLS], int x, int y)
{
return (mine[x][y - 1] + mine[x][y + 1] + mine[x - 1][y] + mine[x - 1][y - 1] + mine[x - 1][y + 1] + mine[x + 1][y] + mine[x + 1][y - 1] + mine[x + 1][y + 1] - 8 * '0');
}
整个代码
1.主函数代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"test.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];//这是玩家棋盘
//初始化棋盘;
//mine全是0;
Initboard(mine, ROWS, COLS,'0');
//show全是*;
Initboard(show, ROWS, COLS,'*');
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");
}
} while (input);
return 0;
}
2.函数具体实现代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"test.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;
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 board[ROWS][COLS], int row, int col)
{
int count = NUM;
while (count)
{
int y = rand() % col + 1;
int x = rand() % row + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
int Getmine(char mine[ROWS][COLS], int x, int y)
{
return (mine[x][y - 1] + mine[x][y + 1] + mine[x - 1][y] + mine[x - 1][y - 1] + mine[x - 1][y + 1] + mine[x + 1][y] + mine[x + 1][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;//win是排雷次数,因为有10个雷,81个格子,10个雷,所以排雷个数要达到71个;
while (win < row * col - NUM)
{
printf("请输入要查询的坐标:\n");
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 = Getmine(mine, x, y);
show[x][y] = count + '0';
Displayboard(show, ROW, COL);
win++;
}
}
else
{
printf("坐标输入错误,请重新输入!!\n");
}
}
if (win == row * col - NUM)
{
printf("恭喜您,排雷成功!!\n");
Displayboard(mine, ROW, COL);
}
}
3.头文件代码
#pragma once
#include<stdio.h>;
#include<time.h>;
#include<stdlib.h>;
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define NUM 10
void Initboard(char board[ROWS][COLS], int rows, int cols, char set);
void Displayboard(char board[ROWS][COLS], int row, int col);
void Setmine(char board[ROWS][COLS], int row, int col);
可能这个过程有点快,有些步骤没有详细展开说,如果有错误的地方或者不懂的地方,欢迎小伙伴们在评论区讨论或者私信我!!