互联网做网站属于什么行业,传奇网页,辽宁省建设厅网站升级何时结束,公司微信网站开发平台#x1f341; 博客主页:江池俊的博客_CSDN博客 #x1f341; 如果觉得博主的文章还不错的话#xff0c;请点赞#x1f44d;收藏#x1f31f; 三连支持一下博主#x1f49e; ✉️每一次努力都是一次进步#xff0c;每一次尝试都是一次机会。无论遇到什么困难#xff0c;… 博客主页:江池俊的博客_CSDN博客 如果觉得博主的文章还不错的话请点赞收藏 三连支持一下博主 ✉️每一次努力都是一次进步每一次尝试都是一次机会。无论遇到什么困难都要坚定地向 前迈进。相信自己并相信自己的潜力您注定会取得非凡的成就 编译环境Visual Studio 2022 目录
一、游戏介绍
游戏规则
游戏玩法
二、游戏实现思路
三、创建文件
1.test.c文件
menu菜单函数的实现
game函数的实现
main函数的实现
2.game.c文件
书写初始化棋盘函数
书写打印棋盘信息的函数
书写设置雷的函数是雷则为‘1’
书写统计周围雷个数的函数
书写展开一片非雷区域的函数
书写计算非雷和非标记的位置个数
书写排查雷的函数 3.game.h文件
需要使用的头文件
定义棋盘行列
定义雷的个数
初始化棋盘
打印棋盘
布置雷
排查雷
四、总代码
一game.h文件
二game.c文件
三test.c文件
五、效果展示 前言 本篇文章主要是讲解用C语言实现扫雷游戏与三子棋的实现思路类似可以参考我前面的两篇文章《三子棋》http://t.csdn.cn/oQQhS 《猜数字游戏》 http://t.csdn.cn/njZHu 下面我们回归正题让我来详细讲解如何实现扫雷游戏。 这里我们以9*9的网格为例。 一、游戏介绍 扫雷是一款经典的单人益智游戏目标是在一个由方格组成的区域中找到并标记出所有的地雷同时避免触雷。下面是扫雷游戏的网页链接你可以通过玩下方的游戏加深自己对游戏的逻辑和原理的理解。 扫雷游戏网页版 - Minesweeper 上面依次是游戏进行、失败和胜利的界面 。
游戏规则 1.游戏开始时整个区域被分割成一系列方格其中一些方格中隐藏有地雷。 2.方格可以是未被揭开的状态也可以是已被揭开或标记过的状态。 3.点击一个方格可以揭开它如果该方格中没有地雷则会显示数字表示周围8个方格中地 雷的数量。 4.如果揭开的方格没有地雷数量则会自动会揭开周围相邻的空方格。 5.如果揭开的方格中有地雷游戏结束玩家失败。 游戏玩法 1.目标是找到并标记出所有的地雷而不触雷。 2.揭开方格时根据方格周围的地雷数量判断周围的方格是否安全。数字表示周围有多少颗地雷。 3.如果您确定某个方格中有地雷可以标记该方格为雷。这有助于您记住哪些方格是地雷也可以帮助您避免不小心触雷。 4.使用推理和逻辑来判断哪些方格一定是地雷哪些方格一定是安全的。通过标记地雷并推断周围的数字逐渐揭开更多的方格直到找到所有的地雷。 二、游戏实现思路 1.创建游戏棋盘使用二维数组表示游戏棋盘每个格子可以是开放状态、地雷或者标记状态。 2.随机布雷使用随机数生成地雷的位置并在对应位置上设置地雷。 3.计算周围地雷数量遍历游戏棋盘对于每个非地雷格子统计周围八个格子中地雷的数量。 4.游戏循环进入游戏循环每次循环包括以下步骤 a. 显示游戏棋盘。 b. 接收用户输入包括选择要打开的格子或标记地雷。 c. 根据用户选择更新游戏棋盘状态。 d. 检查游戏是否胜利或失败。 5.判断游戏是否胜利检查游戏棋盘中所有非地雷格子是否被正确打开。 6.判断游戏是否失败当玩家选择打开一个格子时如果该格子是地雷则游戏失败。 7.标记地雷当玩家选择标记一个格子时在游戏棋盘中该格子的状态为已标记。 8.打开格子当玩家选择打开一个格子时根据该格子的状态进行相应操作 a. 如果该格子已经被标记则忽略。 b. 如果该格子是地雷则游戏失败。 c. 如果该格子是数字格子则显示该数字。 d. 如果该格子是空白格子则继续打开周围的空白格子直到遇到数字格子。(使用递归思想) 10.继续游戏或退出在游戏胜利或失败后询问玩家是否继续游戏。 三、创建文件
由于该游戏的实现需要大量的代码为了提高代码的可读性已经方便后续写代码时的自我检查这里我们创建三个文件来实现该游戏我们依次将三个文件命名为game.h \ game.c \ test.c。 game.h文件用来定义游戏棋盘的行列以及包含该过程中需要用到的头文件和声明各种函数。 game.c文件最为重要它主要是来写实现各种游戏功能的函数即初始化棋盘打印棋盘信息设置棋盘雷的位置统计雷的个数展开无雷的一片区域判断游戏输赢以及标记雷的位置。 test.c文件则是为了打印游戏菜单和实现game游戏函数。 1.test.c文件 menu菜单函数的实现
void menu()
{printf(\t\t\t\t\t\t\t\t\t\t\t\n);printf(*********************\n);printf(***** 1. play *****\n);printf(***** 0. exit *****\n);printf(*********************\n);
}
打印结果 game函数的实现 主要功能如下 1.创建并初始化棋盘 2.设置雷的位置使用rand函数 3.打印棋盘信息 4.排查雷a.展开一片非雷区域 b.显示周围雷的个数 c.判断游戏输赢 void game()
{char mine[ROWS][COLS] { 0 };//存放布置好的雷的信息char show[ROWS][COLS] { 0 };//存放排查出的雷的信息//初始化数组的内容为指定内容//mine数组在没有布置雷的时候都是‘0’InitBoard(mine, ROWS, COLS,0);//show数组在没有排查雷的时候都是‘*’InitBoard(show, ROWS, COLS, *); //设置雷Setmine(mine, ROW, COL);DisplayBoard(show, ROW, COL);//DisplayBoard(mine, ROW, COL);//排查雷FindMine(mine, show, ROW, COL);}这里我们需要创建两个数组作为棋盘但是棋盘比实际的要大一圈这是因为在对边上的格子进行排查时往往不满八个格子对9*9之外的格子访问时会越界这时我们需要手动创建它周围的格子使得它能够成功访问这样的话创建的数组棋盘就从9*9变成了11*11。 当访问棋盘右上角的格子时右上角黄色方框中的格子就是排查时要访问的格子 这里我们要设置两个棋盘其中一个棋盘名字为mine存放雷的信息另一个棋盘名字为show存放排查雷的信息这里我们初始化mine棋盘为字符‘0’show棋盘为字符‘*’。 打印结果 main函数的实现
int main()
{int input 0;srand((unsigned int)time(NULL));do{menu();printf(请选择:);scanf(%d, input);switch (input){case 1:system(cls); game();break;case 0:printf(退出游戏\n);break;default:printf(选择错误请重新输入\n);break;}} while (input);return 0;
}
这里我们通过do while循环和switch语句来实现游戏的持续进行和对不同输入的选择输入1进入游戏输入0退出游戏输入其他时输出“选择错误请重新输入”。
打印结果 2.game.c文件 书写初始化棋盘函数
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{int i 0;int j 0;for(i0;irows;i)for (j 0; j cols; j){board[i][j] set;}
}
因为有两个棋盘所以我们需要一个字符型变量charset 来设置棋盘初始化的值如果是mine棋盘则 set ‘0’如果是show棋盘则 set ‘*’ 。
书写打印棋盘信息的函数
//打印棋盘信息
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{int i 0;int j 0;printf(------扫雷游戏------\n);printf(════════════════════\n);//美化棋盘for (j 0; j col; j){printf(%d|, j);}printf(\n-|══════════════════);//美化棋盘printf(\n);for (i 1; i row; i){printf(%d|, i);for (j 1; j col; j){printf(%c|, board[i][j]);}printf(\n);}printf(════════════════════\n);//美化棋盘printf(------扫雷游戏------\n\n);
}
打印结果 书写设置雷的函数是雷则为‘1’
//设置雷的函数
void Setmine(char board[ROWS][COLS], int row, int col)
{int count EASY_COUNT;//行1-9 列1-9while (count){int x rand() % row 1;int y rand() % col 1;if (board[x][y] 0){board[x][y] 1;count--;}}
}下面我会针对遇到的问题进行解答
如何随机设置雷的位置
使用srand()来随机设置雷的坐标
//test.c
srand((unsigned int)time(NULL));//设置随机数的生成起点 如何控制雷的坐标位置合理
int x rand() % row 1;//生成1-9的随机数
int y rand() % col 1;//生成1-9的随机数
利用rand() 函数取row或col的模再1来得到1-9的随机数这样就可以控制雷的位置在棋盘上。
书写统计周围雷个数的函数
//统计周围雷数的函数
int get_mine_count(char board[ROWS][COLS], int row, int col,int x,int y)
{int count 0;for(int i-1;i1;i)for (int j -1; j 1; j){if (board[x i][y j] 1)count;}return count;/*return (board[x - 1][y] board[x - 1][y - 1] board[x][y - 1] board[x 1][y - 1] board[x 1][y] board[x 1][y 1] board[x][y 1] board[x - 1][y 1] - 8 * 0);*/
} 当排查的位置为xy时根据上图可知周围八个格子的坐标计算周围雷的个数当这八个位置每有一个雷时我们就加一。 书写展开一片非雷区域的函数
//递归展开一片区域的函数
void OpenArea(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col,int x, int y)
{int count get_mine_count(mine,ROW,COL, x, y);if (count 0) {show[x][y] ;for (int i x - 1; i x 1; i) {for (int j y - 1; j y 1; j) {if (show[i][j] * x 1 x row y 1 y col) {OpenArea(mine, show,ROW,COL, i, j);}}}}else {show[x][y] count 0;}
}因为需要对存储雷位置的棋盘和显示棋盘信息的棋盘进行操作所以形参中需要两个棋盘。 当周围没有雷时将此位置的show棋盘上显示为 ‘ ’ (空格)同时对周围八个坐标位置的格子进行判断如果这些坐标合理在9*9的棋盘上则再次对他们进行同样的判断此时就需要利用递归的思想即再次调用展开一片非雷区域的函数当周围有雷这时就需要统计雷的个数并将雷的个数显示在show棋盘上。 注意 因为show棋盘上存储的是字符char而统计的数是整型所以我们需要将整型转换为字符型即让数字加上字符‘0’。 书写计算非雷和非标记的位置个数
//计算非雷和非标记的位置个数
int get_win(char board[ROWS][COLS], int row, int col)
{int win 0;for(int i1;irow;i)for (int j 1; j col; j){if (board[i][j]!*board[i][j]!!)win;}return win;
} 该函数作用是为了判断游戏输赢。 书写排查雷的函数
//排雷的函数
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{//1.输入排查的坐标//2.检查该坐标处是不是雷//(1) 是雷 - 很遗憾你被炸死了 - 游戏结束//(2) 不是雷 - 统计坐标周围有几个雷 - 存储排查雷的信息到show数组游戏继续int x 0;int y 0;int win 0;int select 0;while (win row * col - EASY_COUNT){printf(请选择1.排查雷 2.标记雷\t);scanf(%d, select);if (select 1) {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\n很遗憾你被炸死了\n);printf(雷的分布情况其中1表示雷\n);DisplayBoard(mine, ROW, COL);break;}else{OpenArea(mine, show,ROW,COL, x, y);//显示排查出的信息DisplayBoard(show, ROW, COL);//计算已经排出的非雷位置的个数win get_win(show, ROW, COL);//win;}}else{printf(该位置已被排查过请重新输入\n);}}else{printf(坐标不合法请重新输入\n);}}else if (select 2){printf(请输入要标记的坐标);scanf(%d %d, x, y);//判断坐标合法性if (x 1 x row y 1 y col) {if (show[x][y] *){show[x][y] !;DisplayBoard(show, ROW, COL);}else if(show[x][y]!){printf(该位置已被标记请重新选择\n);}else{printf(该位置不能标记请重新选择\n);}}else {printf(坐标不合法请重新输入\n);}}else {printf(输入有误请重新输入\n);}printf(win%d\n, win);}if (win row * col - EASY_COUNT) {printf(\n恭喜你排雷成功\n);printf(雷的分布情况其中1表示雷\n);DisplayBoard(mine, ROW, COL);}
}//基础功能拓展功能
//1.标记功能用!
//2.展开一片区域的功能使用递归
//*当排查下xy坐标时1该坐标不是雷 2该坐标周围没有雷 3该坐标没有被排查过
如何排查雷 基本思路 1.输入排查的坐标 2.检查该坐标处是不是雷 ❌ 是雷 - 很遗憾你被炸死了 - 游戏结束 ✔️不是雷 - 统计坐标周围有几个雷 - 存储排查雷的信息到show数组游戏继续 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\n很遗憾你被炸死了\n);printf(雷的分布情况其中1表示雷\n);DisplayBoard(mine, ROW, COL);break;}else{OpenArea(mine, show,ROW,COL, x, y);//显示排查出的信息DisplayBoard(show, ROW, COL);//计算已经排出的非雷位置的个数win get_win(show, ROW, COL);//win;}}else{printf(该位置已被排查过请重新输入\n);}}else{printf(坐标不合法请重新输入\n);}
如何标记雷 因为排查雷和标记雷是两个不同的过程所以这时我们需要通过使用if-else语句来选择排查雷还是标记雷标记雷的位置用‘ ’来表示。 //printf(请选择1.排查雷 2.标记雷\t);
//scanf(%d, select);
else if (select 2){printf(请输入要标记的坐标);scanf(%d %d, x, y);//判断坐标合法性if (x 1 x row y 1 y col) {if (show[x][y] *){show[x][y] !;DisplayBoard(show, ROW, COL);}else if(show[x][y]!){printf(该位置已被标记请重新选择\n);}else{printf(该位置不能标记请重新选择\n);}}else {printf(坐标不合法请重新输入\n);}}else {printf(输入有误请重新输入\n);}//printf(win%d\n, win);} 如何判断输赢
if (win row * col - EASY_COUNT) {printf(\n恭喜你排雷成功\n);printf(雷的分布情况其中1表示雷\n);DisplayBoard(mine, ROW, COL);} 当show棋盘上非雷位置和非标记位置个数与mine棋盘上‘0’的个数即非雷个数相等时打印“恭喜你排雷成功”并打印mine棋盘的雷的分布情况。若不等于则继续进行排雷或标记雷的步骤。 打印结果 3.game.h文件 需要使用的头文件
#includestdio.h
#includestdlib.h
#includetime.h;定义棋盘行列
#define ROW 9
#define COL 9#define ROWS ROW2
#define COLS COL2 打印棋盘信息时使用9*9的棋盘在进行初始化设置雷排查雷标记雷等操作时使用11*11的棋盘。 定义雷的个数
#define EASY_COUNT 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);排查雷
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row,int col);四、总代码
注意此代码分为三个部分的代码
一game.h文件
#includestdio.h
#includestdlib.h
#includetime.h;#define ROW 9
#define COL 9#define ROWS ROW2
#define COLS COL2#define EASY_COUNT 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);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row,int col);二game.c文件
#define _CRT_SECURE_NO_WARNINGS 1#includegame.h
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{int i 0;int j 0;for(i0;irows;i)for (j 0; j cols; j){board[i][j] set;}
}
//打印棋盘信息
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{int i 0;int j 0;printf(------扫雷游戏------\n);printf(════════════════════\n);//美化棋盘for (j 0; j col; j){printf(%d|, j);}printf(\n-|══════════════════);//美化棋盘printf(\n);for (i 1; i row; i){printf(%d|, i);for (j 1; j col; j){printf(%c|, board[i][j]);}printf(\n);}printf(════════════════════\n);//美化棋盘printf(------扫雷游戏------\n\n);
}
//设置雷的函数
void Setmine(char board[ROWS][COLS], int row, int col)
{int count EASY_COUNT;//行1-9 列1-9while (count){int x rand() % row 1;int y rand() % col 1;if (board[x][y] 0){board[x][y] 1;count--;}}
}
//统计周围雷数的函数
int get_mine_count(char board[ROWS][COLS], int row, int col,int x,int y)
{int count 0;for(int i-1;i1;i)for (int j -1; j 1; j){if (board[x i][y j] 1)count;}return count;/*return (board[x - 1][y] board[x - 1][y - 1] board[x][y - 1] board[x 1][y - 1] board[x 1][y] board[x 1][y 1] board[x][y 1] board[x - 1][y 1] - 8 * 0);*/
}//递归展开一片区域的函数
void OpenArea(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col,int x, int y)
{int count get_mine_count(mine,ROW,COL, x, y);if (count 0) {show[x][y] ;for (int i x - 1; i x 1; i) {for (int j y - 1; j y 1; j) {if (show[i][j] * x 1 x row y 1 y col) {OpenArea(mine, show,ROW,COL, i, j);}}}}else {show[x][y] count 0;}
}// 计算非雷和非标记的位置个数
int get_win(char board[ROWS][COLS], int row, int col)
{int win 0;for(int i1;irow;i)for (int j 1; j col; j){if (board[i][j]!*board[i][j]!!)win;}return win;
}//排雷的函数
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{//1.输入排查的坐标//2.检查该坐标处是不是雷//(1) 是雷 - 很遗憾你被炸死了 - 游戏结束//(2) 不是雷 - 统计坐标周围有几个雷 - 存储排查雷的信息到show数组游戏继续int x 0;int y 0;int win 0;int select 0;while (win row * col - EASY_COUNT){printf(请选择1.排查雷 2.标记雷\t);scanf(%d, select);if (select 1) {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\n很遗憾你被炸死了\n);printf(雷的分布情况其中1表示雷\n);DisplayBoard(mine, ROW, COL);break;}else{OpenArea(mine, show,ROW,COL, x, y);//显示排查出的信息DisplayBoard(show, ROW, COL);//计算已经排出的非雷位置的个数win get_win(show, ROW, COL);//win;}}else{printf(该位置已被排查过请重新输入\n);}}else{printf(坐标不合法请重新输入\n);}}else if (select 2){printf(请输入要标记的坐标);scanf(%d %d, x, y);//判断坐标合法性if (x 1 x row y 1 y col) {if (show[x][y] *){show[x][y] !;DisplayBoard(show, ROW, COL);}else if(show[x][y]!){printf(该位置已被标记请重新选择\n);}else{printf(该位置不能标记请重新选择\n);}}else {printf(坐标不合法请重新输入\n);}}else {printf(输入有误请重新输入\n);}//printf(win%d\n, win);}if (win row * col - EASY_COUNT) {printf(\n恭喜你排雷成功\n);printf(雷的分布情况其中1表示雷\n);DisplayBoard(mine, ROW, COL);}
}//基础功能拓展功能
//1.标记功能用!
//2.展开一片区域的功能使用递归
//*当排查下xy坐标时1该坐标不是雷 2该坐标周围没有雷 3该坐标没有被排查过三test.c文件
#define _CRT_SECURE_NO_WARNINGS 1#includegame.hvoid menu()
{printf(\t\t\t\t\t\t\t\t\t\t\t\n);printf(*********************\n);printf(***** 1. play *****\n);printf(***** 0. exit *****\n);printf(*********************\n);
}void game()
{char mine[ROWS][COLS] { 0 };//存放布置好的雷的信息char show[ROWS][COLS] { 0 };//存放排查出的雷的信息//初始化数组的内容为指定内容//mine数组在没有布置雷的时候都是‘0’InitBoard(mine, ROWS, COLS,0);//show数组在没有排查雷的时候都是‘*’InitBoard(show, ROWS, COLS, *); //设置雷Setmine(mine, ROW, COL);DisplayBoard(show, 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:system(cls); game();break;case 0:printf(退出游戏\n);break;default:printf(选择错误请重新输入\n);break;}} while (input);return 0;
}
五、效果展示 扫雷游戏展示 扫雷游戏展示 好了 今天的内容就分享到这里了。愿这篇博客能够为您带来新的思考和启示。感谢您的耐心阅读和支持。无论在人生的道路上遇到怎样的困难和挑战记住相信自己的力量努力前行。期待与您共同探索更多精彩的内容。再次感谢