扫雷这个游戏相信我们大家都有玩过,我们每个电脑里面可能都会有,今天我将用C语言的形式来实现这功能。
目录
一,设计思路
我们电脑中的扫雷游戏就是
我们只要输入坐标就可以扫雷了(因为技术原因........),这样的话就不是很难了,我们只需要运用几个算法模块来实现,会分成main,test,game等几个模块来运行,为了方便可以创建多个项目来实现
那我们就需要用二维数组来打印两个棋盘,假如我们要打印9X9的棋盘,那我们的二维数组元素也要为9X9个吗?,不能,因为我们在设计算法时需要统计坐标周围8个方位雷的个数,假如要统计边界坐标周围雷的个数,那么就会有数组越界的问题,那我们就要在9X9的边界多上一圈元素,也就要定义11X11的数组元素,这些元素我们不要打印出来,心里有数就行
二,功能讲解
1.能让其选择是否加入游戏,在完成一把游戏后,无论输赢,可以自行选择是否再来一把
2.因为自身能力原因,无法实现电脑中那样的画面和衔接,采取坐标的形式来排雷
3.在下的位置显示该点周围雷的个数(在没爆炸的情况下)
三,代码及其游戏步骤及其思路讲解
代码我会按照板块来写注意看哦!!
1.建立数组来保存棋子
#define ROW 9//行
#define COL 9//列
#define ROWS ROW+2
#define COLS COL+2
如同猜数字和三子棋一样的采用宏定义来定义棋盘的大小我们这次玩的是 “9*9” 的扫雷所以我们定义为 9 .
但是下面的ROWS=ROW+2 || COLS=COL+2如同我们上面所说的一样因为我们在设计算法时需要统计坐标周围8个方位雷的个数,假如要统计边界坐标周围雷的个数,那么就会有数组越界的问题,那我们就要在9X9的边界多上一圈元素,也就要定义11X11的数组元素,这些元素我们不要打印出来
#define easy_system 10//给的最小雷数量
我们同样会采用宏定义来给定雷的数量,后期我们也可以,设置初级/中级/高级模式来给定雷的数量,十分方便!!
2.初始化棋盘
initialization_board(mine, ROW, COL, '0');
initialization_board(show, ROW, COL, '*');
在mine数组中,用字符‘0’表示无雷区域,用字符‘1’表示有雷区域
在show数组中,’✳‘来覆盖然后来排雷,排后 用数字来取代,数字代表其周围的雷的个数
//初始化棋盘
void initialization_board(char arr[ROWS][COLS], int row, int col, int set)
{
int i = 0;
int j = 0;
for (i = 0;i <=row; i++)
{
for (j = 0;j <=col;j++)
{
arr[i][j] = set;
}
}
}
3.打印棋盘
show_board(show, ROWS, COLS);
void show_board(char show[ROWS][COLS], int row, int col)
{
{
int i = 0;
int j = 0;
//打印列号
for (i = 0; i < col-1; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i < row-1; i++)
{
printf("%d ", i); //打印行号
for (j = 1; j < col; j++)
{
printf("%c ", show[i][j]);
}
printf("\n"); //打印完一行需要换行
}
}
}
打印出来就是这个样子的
mine_board(mine,ROW,COL);
这个就是其基础的没有✳和其他的只有 ’ 0 ‘和 ’ 1 ‘ ,我们在代码中可能不会出现这个,这是为了大家能更好的理解,列出来,大家也可以试试!
4.随机放置雷
其easy_system,在上面的宏定义部分有讲到,意思是我们选择了简单模式
在mine数组中,用字符‘0’表示无雷区域,用字符‘1’表示有雷区域,我们使用srand和rand函数生成随机数,使得雷的分布为随机位置。
void set_mine(char mine[ROWS][COLS], int row, int col)
{
int count = easy_system;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = 1 + '0';
count--;
}
}
}
rand的话我在 “ 三子棋 ” 和 “ 猜数字 ”的博客中都有提到,大家可以去看看,支持一下,蟹蟹!!
5.玩家排雷
玩家根据show数组展示出的地图开始排雷,选择自己认为不是雷的区域。
在里面nearby_number() boom_board()函数我们会在下面详细写出
void check_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;
while (count < row * col - easy_system)//我们总共循环71=81-10次,当我们已经循环了71次后,就代表我们已经将所有非雷区域全部排除了
{
printf("请输入坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("爆炸了!!");
printf("游戏失败!\n");
show[x][y] = '#';
show_board(show, ROWS, COLS);
break;
}
else
{
boom_broad(mine, show, x, y);
show[x][y] = nearby_number(mine, x, y) + '0';
show_board(show, ROWS, COLS);
count++;
}
}
else
{
printf("坐标输入错误,请重新输入!\n");
}
}
if (count == row * col - easy_system)//我们总共循环71=81-10次,当我们已经循环了71次后,就代表我们已经将所有非雷区域全部排除了
{
printf("恭喜你,你成功了,剩下的都是雷\n");
show_board(mine, row, col);//赢了打印雷在哪里
}
}
我们总共循环71=81-10次,当我们已经循环了71次后,就代表我们已经将所有非雷区域全部排除了,我们在前面定义了一个count如果我们排对了就++,当达到了71次就代表我们已经将所有非雷区域全部排除了。
nearby_number()我们定义的作用主要是来得到其周围雷的个数来重新给到坐标区域
boom_board()以递归的方式拓展式排雷。
6.计算该位置周围雷的个数
统计已选位置周围八个位置中含有雷的个数,并在该位置上数字的形式打印出来
int nearby_number(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - (8 * '0');//周围有8格所以乘8个'0'
}
在圆圈里面那个 为我们下的坐标,我们要计算的是他周围的八个坐标是否为雷
在那里面我们return里面 “ - ‘ 0 ’ ”是因为字符的原因
7.递归拓展已选位置周围的区域
如果只能一个一个雷的排,将会使得此游戏无法进行,故当选择一个位置a后对a周围八个区域进行排除,若其中一个位置b周围八个位置仍没有雷,就继续对b周围的八个位置进行排雷,以此递归的方式不断排除。
boom_broad()
void boom_broad(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
//判断坐标是否越界
if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1)
return;
//判断是否已经被排除
if (show[x][y] != '*')
{
return;
}
int count = nearby_number(mine, x, y);
if (count > 0)
{
show[x][y] = count + '0';
return;
}
//递归拓展地图
else if (count == 0)
{
show[x][y] = '0';
boom_broad(mine, show, x - 1, y);
boom_broad(mine, show, x - 1, y - 1);
boom_broad(mine, show, x, y - 1);
boom_broad(mine, show, x + 1, y - 1);
boom_broad(mine, show, x + 1, y);
boom_broad(mine, show, x + 1, y + 1);
boom_broad(mine, show, x, y + 1);
boom_broad(mine, show, x - 1, y + 1);
}
}
四,总代码总结
game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9//行
#define COL 9//列
#define ROWS ROW+2
#define COLS COL+2
#define easy_system 10//给的最小雷数量
//初始化棋盘
void initialization_board(char arr[ROWS][COLS], int row, int col, int set);
//打印棋盘
void show_board(char show[ROWS][COLS], int row, int col);
//放置雷
void set_mine(char mine[ROWS][COLS], int row, int col);
//排查雷
void check_mine(char ine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
game.c
#include "game.h"
//初始化棋盘
void initialization_board(char arr[ROWS][COLS], int row, int col, int set)
{
int i = 0;
int j = 0;
for (i = 0;i <=row; i++)
{
for (j = 0;j <=col;j++)
{
arr[i][j] = set;
}
}
}
void show_board(char show[ROWS][COLS], int row, int col)
{
{
int i = 0;
int j = 0;
//打印列号
for (i = 0; i < col-1; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i < row-1; i++)
{
printf("%d ", i); //打印行号
for (j = 1; j < col; j++)
{
printf("%c ", show[i][j]);
}
printf("\n"); //打印完一行需要换行
}
}
}
void set_mine(char mine[ROWS][COLS], int row, int col)
{
int count = easy_system;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = 1 + '0';
count--;
}
}
}
int nearby_number(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - (8 * '0');//周围有8格所以乘8个'0'
}
//递归拓展已选位置周围的区域
void boom_broad(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
//判断坐标是否越界
if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1)
return;
//判断是否已经被排除
if (show[x][y] != '*')
{
return;
}
int count = nearby_number(mine, x, y);
if (count > 0)
{
show[x][y] = count + '0';
return;
}
//递归拓展地图
else if (count == 0)
{
show[x][y] = '0';
boom_broad(mine, show, x - 1, y);
boom_broad(mine, show, x - 1, y - 1);
boom_broad(mine, show, x, y - 1);
boom_broad(mine, show, x + 1, y - 1);
boom_broad(mine, show, x + 1, y);
boom_broad(mine, show, x + 1, y + 1);
boom_broad(mine, show, x, y + 1);
boom_broad(mine, show, x - 1, y + 1);
}
}
void check_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;
while (count < row * col - easy_system)
{
printf("请输入坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("爆炸了!!");
printf("游戏失败!\n");
show[x][y] = '#';
show_board(show, ROWS, COLS);
break;
}
else
{
boom_broad(mine, show, x, y);
show[x][y] = nearby_number(mine, x, y) + '0';
show_board(show, ROWS, COLS);
count++;
}
}
else
{
printf("坐标输入错误,请重新输入!\n");
}
}
if (count == row * col - easy_system)
{
printf("恭喜你,你成功了,剩下的都是雷\n");
show_board(mine, row, col);//赢了打印雷在哪里
}
}
test.h
#include "game.h"
void menu()//菜单
{
printf("************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exit *******\n");
printf("************************\n");
}
void game()
{
srand((unsigned int)time(NULL));
//扫雷的实现
//定义含雷数组,来存放布置好的雷的信息
char mine[ROWS][COLS] = { 0 };
//用来存放排查出的雷的信息
char show[ROWS][COLS] = { 0 };
//初始化棋盘
initialization_board(mine, ROW, COL, '0');
initialization_board(show, ROW, COL, '*');
//打印棋盘
/*show_board(show, ROWS, COLS);*/
//放置雷
set_mine(mine, ROW, COL);
show_board(show, ROWS, COLS);
//排查雷
check_mine(mine, show, ROW, COL);
}
int main()
{
int change = 0;
do
{
menu();//菜单
printf("请输入选择:");
scanf("%d", &change);
switch (change)
{
case 1:
printf("扫雷游戏\n");
game();
break;
case 0:
break;
default:
printf("输入错误,重新输入\n");
}
} while (change);
return 0;
}