vs2005做网站,优化设计答案大全英语,wordpress页面关键词和描述,浙江高端网站扫雷是一款经典的小游戏#xff0c;那如何使用C语言实现一个扫雷游戏呢#xff1f;
一、全部源码
直接把全部源码放在开头#xff0c;如有需要#xff0c;直接拿走。
源码分为三个文件#xff1a;
test.cpp/c
主函数的位置
#include game.hint main()
{…扫雷是一款经典的小游戏那如何使用C语言实现一个扫雷游戏呢
一、全部源码
直接把全部源码放在开头如有需要直接拿走。
源码分为三个文件
test.cpp/c
主函数的位置
#include game.hint main()
{int deep[ROW][COL];//深层用来记录布置好的地雷和数字及埋藏在下层的内容char face[ROW][COL];//表面用来打印和记录玩家操作表层对玩家操作进行记录int menu1 0;//外层菜单0为退出游戏1为进入游戏int menu2 0;//内层菜单0为返回上一步1为简单难度2为中等难度3为大师难度do{GameMenu(1);//外菜单打印scanf(%d, menu1);//接收选择switch(menu1){case 0://退出游戏printf(你已退出游戏\n);break;case 1://内层菜单选择难度GameMenu(2);//内层菜单打印scanf(%d, menu2);//接收选择switch(menu2){case 0://返回上一界面break;case 1:GameEasy(deep, face);//简单难度break;case 2:GameMedium(deep, face);//中等难度break;case 3:GameExpert(deep, face);//大师难度break;case 4:GameNightmare(deep, face);//噩梦难度break;default:printf(ERROR!\n);break;}break;default :printf(ERROR!\n);break;}} while (menu1);//只要非零就一直循环进行游戏为0则退出游戏return 0;
}
gane.cpp/c
几乎所有游戏功能函数的位置
#include game.h//用来打印菜单
void GameMenu(int x)
{switch(x){case 1://外层菜单printf(----------------------------\n);printf(------ 1 for start ---------\n);printf(------ 0 for exit ----------\n);printf(----------------------------\n);break;case 2://内层菜单printf(----------------------------\n);printf(------ 1 for Easy ----------\n);printf(------ 2 for Medium --------\n);printf(------ 3 for Expert --------\n);printf(------ 4 for Nightmare -----\n);printf(------ 0 for back ----------\n);printf(----------------------------\n);break;default :printf(ERROR!\n);break;}
}//用来初始化深层数组difficulty用来传难度不同难度初始化大小不同
void DeepBoardIntial(int deep[ROW][COL], int difficulty)
{int i 0, j 0;for (i 0; i difficulty; i){for (j 0; j difficulty; j){deep[i][j] 0;//初始化为0以便之后填充数字}}
}//用来初始化表面数组difficulty用来传难度不同难度初始化大小不同
void FaceBoardIntial(char face[ROW][COL],int difficulty)
{int i 0, j 0;for (i 0; i difficulty; i){for (j 0; j difficulty; j){face[i][j] _;//初始化为 _ 表示未揭示的格子}}
}//打印内容对应打印可视化面板这个是打印内容
void ContentPrint(int deep[ROW][COL], char face[ROW][COL], int i, int j)
{if (face[i][j] x)//只要是玩家揭示的直接打印deep中的内容如果是炸弹通过IsGameWin函数判断就直接失败了不会打印{printf( %d |, deep[i][j]);}else if (face[i][j] L)//这里实现的是连续揭示原版的一种操作连续解释的赋值为 L 方便实现当玩家探索一个没有雷的空块时程序应该自动揭示与该空块相邻的所有空块直到遇到数字即与雷相邻的块。这个特性是原版扫雷游戏的关键特点加快游戏进程{if (deep[i][j] 0)//只要数字是零则直接打印空格实现原版的周围八个格没有雷则打印空格{printf( |);}else{printf( %d |, deep[i][j]);//数字不是零则打印这个数字}}else{printf( %c |,face[i][j]);//没有揭示的格子直接打印 _ 表示未揭示的格子}
}//打印可视化面板
void BoardPrint(int deep[ROW][COL], char face[ROW][COL],int difficulty)
{int i 0, j 0;printf(|);for (j 0; j difficulty; j){printf((%-2d|, j 1);}printf(\n);printf(|);for (j 0; j difficulty; j){printf(___|);}printf(___);printf(\n);for (i 0; i difficulty; i){printf(|);for (j 0; j difficulty; j){ContentPrint(deep,face,i,j);//只有这个是内容打印其他是打印表格为了更加美观}printf((%-2d, i 1);printf(\n);printf(|);for (j 0; j difficulty; j){printf(___|);}printf(___);printf(\n);}
}//随即放置地雷
void RandomMineGenerate(int deep[ROW][COL],int difficulty,int minesnum)
{int x 0;int y 0;int i 0;srand((unsigned int)time(NULL));//设置随机种子for(i 0;i minesnum;i){x rand() % difficulty;//产生0~8的数字表示随机的行y rand() % difficulty;//产生0~8的数字表示随机的列if(deep[x][y] ! MINE)//确保这个位置不是雷只要不是已经是地雷的格子则放一个地雷防止重复放置导致的地雷数目减少{deep[x][y] MINE;//将这个随机生成的坐标设为雷}else//如果是雷则重新生成{i--;//i--可以实现此次作废再来生成一次的效果}}
}//检查是否胜利0为输1为赢2为继续
int IsGameWin(int deep[ROW][COL], char face[ROW][COL], int row, int col, int difficulty)
{if (deep[row][col] MINE face[row][col] x)//只要是雷且玩家点击返回0即输{return 0;}int i 0, j 0;for (i 0; i difficulty; i){for (j 0; j difficulty; j){if (deep[i][j] ! MINE face[i][j] _)//只要还有非雷格子没探索返回2就继续{return 2;}}}return 1;//没有踩雷且没有非雷格子未探索返回1则赢
}//连续揭示点的是周围没有雷的格子即数字零周围就会连续揭示,实现原版操作
//连续揭示原版的一种操作连续解释的赋值为 L 方便实现当玩家探索一个没有雷的空块时程序应该自动揭示与该空块相邻的所有空块直到遇到数字即与雷相邻的块。这个特性是原版扫雷游戏的关键特点加快游戏进程
void LinkChange(int deep[ROW][COL], char face[ROW][COL], int i, int j,int difficulty)
{//由于下面使用了递归必须加入一些条件使得递归不会一直递归下去if (!CheckIfValid(i, j, difficulty))//只要超出雷区范围直接返回函数返回值为void直接return不带任何值{return;}if (face[i][j] L)//已经设置为连续揭示标志 L 的则直接返回{return;}if (deep[i][j] 0 deep[i][j] 9)//在数字0旁边的非零数字也设置为 L 并且返回{face[i][j] L;return;}if (deep[i][j] 9)//是地雷则直接返回{return;}if (deep[i][j] 0)//一个位置为0将这个位值设为 L 并且探索它周围八个格子进行递归{face[i][j] L;LinkChange(deep, face, i - 1, j - 1, difficulty);LinkChange(deep, face, i - 1, j, difficulty);LinkChange(deep, face, i - 1, j 1, difficulty);LinkChange(deep, face, i, j - 1, difficulty);LinkChange(deep, face, i, j 1, difficulty);LinkChange(deep, face, i 1, j - 1, difficulty);LinkChange(deep, face, i 1, j, difficulty);LinkChange(deep, face, i 1, j 1, difficulty);}
}//装填数字计算非雷格子中应该是数字几来表示周围雷的个数装填在数组中
void FillinNum(int deep[ROW][COL],int difficulty)
{int i 0, j 0;for (i 0; i difficulty; i){for (j 0; j difficulty; j){if (deep[i][j] MINE)//如果坐标(i,j)是雷则将雷旁边的八个格子都加一{if (CheckIfValid(i - 1,j - 1,difficulty) deep[i - 1][j - 1] ! MINE )//判断格子是否是雷并且判断坐标是否有效格子有效且不是地雷才能加一{deep[i - 1][j - 1];}if (CheckIfValid(i - 1, j, difficulty) deep[i - 1][j] ! MINE){deep[i - 1][j];}if (CheckIfValid(i - 1, j 1, difficulty) deep[i - 1][j 1] ! MINE){deep[i - 1][j 1];}if (CheckIfValid(i, j - 1, difficulty) deep[i][j - 1] ! MINE){deep[i][j - 1];}if (CheckIfValid(i, j 1, difficulty) deep[i][j 1] ! MINE){deep[i][j 1];}if (CheckIfValid(i 1, j - 1, difficulty) deep[i 1][j - 1] ! MINE){deep[i 1][j - 1];}if (CheckIfValid(i 1, j, difficulty) deep[i 1][j] ! MINE){deep[i 1][j];}if (CheckIfValid(i 1, j 1, difficulty) deep[i 1][j 1] ! MINE){deep[i 1][j 1];}}}}
}//检查坐标是否有效
int CheckIfValid(int row, int col,int difficulty)
{if (row 0 row difficulty col 0 col difficulty)//检查坐标是否在雷区内{return 1;//在雷区内为有效返回1为有效}return 0;//不在雷区内为无效返回0为无效
}//简单难度
void GameEasy(int deep[ROW][COL], char face[ROW][COL])
{DeepBoardIntial(deep, 9);//简单难度格子为 9 * 9 大小FaceBoardIntial(face, 9);RandomMineGenerate(deep, 9,9);//随机生成地雷FillinNum(deep, 9);//装填数字int row 0, col 0;//用来接收玩家输入行列int check 0;//检查是否胜利0为失败1为胜利2为继续do{system(cls);//清屏BoardPrint(deep, face, 9);//打印while(1){printf(输入行列);scanf(%d %d, row, col);if (CheckIfValid(row - 1, col - 1,9) face[row - 1][col - 1] ! x face[row - 1][col - 1] ! L)//有效且是没被揭开的则输入成功{face[row - 1][col - 1] x;break;//输入成功则直接退出循环}else if (CheckIfValid(row - 1, col - 1, 9) (face[row - 1][col - 1] x || face[row - 1][col - 1] L))//输入的坐标为已经揭示的格子则重新输入{printf(已经揭示的格子请不要重复操作重新输入\n);}else//不在范围内重新输入{printf(范围错误重新输入\n);}}check IsGameWin(deep, face,row - 1,col - 1,9);//检查是否胜利或失败以及游戏是否继续if(check 2)//只要游戏继续就判断是否连续揭示{if(deep[row - 1][col - 1] 0)//揭示的格子是空格(即格子是0周围八个格子没有地雷)则尝试连续揭示{LinkChange(deep, face, row - 1, col - 1,9);//对于这个输入的格子进行连续揭示}}} while (check 2);//只要check为2则继续则循环继续则游戏继续check为1或0(即赢或输)是退出循环if (check 1)//check为1时胜利{printf(你赢了\n);}else if(check 0)//check为0时失败{printf(你输了\n);}else//错误{printf(ERROR!\n);}
}//中等难度
void GameMedium(int deep[ROW][COL], char face[ROW][COL])
{DeepBoardIntial(deep, 16);//中等难度格子为 16 * 16 大小FaceBoardIntial(face, 16);RandomMineGenerate(deep, 16,32);//随机生成地雷FillinNum(deep, 16);//装填数字int row 0, col 0;//用来接收玩家输入行列int check 0;//检查是否胜利0为失败1为胜利2为继续do{system(cls);//清屏BoardPrint(deep, face, 16);//打印while (1){printf(输入行列);scanf(%d %d, row, col);if (CheckIfValid(row - 1, col - 1, 16) face[row - 1][col - 1] ! x face[row - 1][col - 1] ! L)//有效且是没被揭开的则输入成功{face[row - 1][col - 1] x;break;//输入成功则直接退出循环}else if (CheckIfValid(row - 1, col - 1, 16) (face[row - 1][col - 1] x || face[row - 1][col - 1] L))//输入的坐标为已经揭示的格子则重新输入{printf(已经揭示的格子请不要重复操作重新输入\n);}else//不在范围内重新输入{printf(范围错误重新输入\n);}}check IsGameWin(deep, face, row - 1, col - 1, 16);//检查是否胜利或失败以及游戏是否继续if (check 2)//只要游戏继续就判断是否连续揭示{if (deep[row - 1][col - 1] 0)//揭示的格子是空格(即格子是0周围八个格子没有地雷)则尝试连续揭示{LinkChange(deep, face, row - 1, col - 1, 16);//对于这个输入的格子进行连续揭示}}} while (check 2);//只要check为2则继续则循环继续则游戏继续check为1或0(即赢或输)是退出循环if (check 1)//check为1时胜利{printf(你赢了\n);}else if (check 0)//check为0时失败{printf(你输了\n);}else//错误{printf(ERROR!\n);}
}//大师难度
void GameExpert(int deep[ROW][COL], char face[ROW][COL])
{DeepBoardIntial(deep, 30);//大师难度格子为 30 * 30 大小FaceBoardIntial(face, 30);RandomMineGenerate(deep, 30,90);//随机生成地雷FillinNum(deep, 30);//装填数字int row 0, col 0;//用来接收玩家输入行列int check 0;//检查是否胜利0为失败1为胜利2为继续do{system(cls);//清屏BoardPrint(deep, face, 30);//打印while (1){printf(输入行列);scanf(%d %d, row, col);if (CheckIfValid(row - 1, col - 1, 30) face[row - 1][col - 1] ! x face[row - 1][col - 1] ! L)//有效且是没被揭开的则输入成功{face[row - 1][col - 1] x;break;//输入成功则直接退出循环}else if (CheckIfValid(row - 1, col - 1, 30) (face[row - 1][col - 1] x || face[row - 1][col - 1] L))//输入的坐标为已经揭示的格子则重新输入{printf(已经揭示的格子请不要重复操作重新输入\n);}else//不在范围内重新输入{printf(范围错误重新输入\n);}}check IsGameWin(deep, face, row - 1, col - 1, 30);//检查是否胜利或失败以及游戏是否继续if (check 2)//只要游戏继续就判断是否连续揭示{if (deep[row - 1][col - 1] 0)//揭示的格子是空格(即格子是0周围八个格子没有地雷)则尝试连续揭示{LinkChange(deep, face, row - 1, col - 1, 30);//对于这个输入的格子进行连续揭示}}} while (check 2);//只要check为2则继续则循环继续则游戏继续check为1或0(即赢或输)是退出循环if (check 1)//check为1时胜利{printf(你赢了\n);}else if (check 0)//check为0时失败{printf(你输了\n);}else//错误{printf(ERROR!\n);}
}//噩梦难度
void GameNightmare(int deep[ROW][COL], char face[ROW][COL])
{DeepBoardIntial(deep, 50);//噩梦难度格子为 50 * 50 大小FaceBoardIntial(face, 50);RandomMineGenerate(deep, 50, 250);//随机生成地雷FillinNum(deep, 50);//装填数字int row 0, col 0;//用来接收玩家输入行列int check 0;//检查是否胜利0为失败1为胜利2为继续do{system(cls);//清屏BoardPrint(deep, face, 50);//打印while (1){printf(输入行列);scanf(%d %d, row, col);if (CheckIfValid(row - 1, col - 1, 50) face[row - 1][col - 1] ! x face[row - 1][col - 1] ! L)//有效且是没被揭开的则输入成功{face[row - 1][col - 1] x;break;//输入成功则直接退出循环}else if (CheckIfValid(row - 1, col - 1, 50) (face[row - 1][col - 1] x || face[row - 1][col - 1] L))//输入的坐标为已经揭示的格子则重新输入{printf(已经揭示的格子请不要重复操作重新输入\n);}else//不在范围内重新输入{printf(范围错误重新输入\n);}}check IsGameWin(deep, face, row - 1, col - 1, 50);//检查是否胜利或失败以及游戏是否继续if (check 2)//只要游戏继续就判断是否连续揭示{if (deep[row - 1][col - 1] 0)//揭示的格子是空格(即格子是0周围八个格子没有地雷)则尝试连续揭示{LinkChange(deep, face, row - 1, col - 1, 50);//对于这个输入的格子进行连续揭示}}} while (check 2);//只要check为2则继续则循环继续则游戏继续check为1或0(即赢或输)是退出循环if (check 1)//check为1时胜利{printf(你赢了\n);}else if (check 0)//check为0时失败{printf(你输了\n);}else//错误{printf(ERROR!\n);}
}
game.cpp/c
函数声明
#pragma once
#include stdio.h
#include stdlib.h
#include time.h#define ROW 50//宏定义方便更改
#define COL 50
#define MINE 9//宏定义定义9为雷//菜单打印
void GameMenu(int x);//深层数组初始化
void DeepBoardIntial(int deep[ROW][COL],int difficulty);//表面数组初始化
void FaceBoardIntial(char face[ROW][COL],int difficulty);//连续揭示打印
void LinkChange(int deep[ROW][COL], char face[ROW][COL], int i, int j,int difficulty);//实际打印实现
void ContentPrint(int deep[ROW][COL], char face[ROW][COL], int i, int j);//面板打印
void BoardPrint(int deep[ROW][COL], char face[ROW][COL],int difficulty);//随机生成雷
void RandomMineGenerate(int deep[ROW][COL], int difficulty,int minesnum);//检查是否胜利
int IsGameWin(int deep[ROW][COL], char face[ROW][COL], int row, int col, int difficulty);//填入数字
void FillinNum(int deep[ROW][COL], int difficulty);//检查输入坐标是否有效
int CheckIfValid(int row, int col, int difficulty);//简单难度
void GameEasy(int deep[ROW][COL], char face[ROW][COL]);//中等难度
void GameMedium(int deep[ROW][COL], char face[ROW][COL]);//大师难度
void GameExpert(int deep[ROW][COL], char face[ROW][COL]);//噩梦难度
void GameNightmare(int deep[ROW][COL], char face[ROW][COL]);
可以自行运行测试下面有测试图片以及一些问题的解决办法在在第七大段。
二、面板
要想扫雷首先要有可视化的面板能显示相关的信息例如显示出数字表示周围八个格子中有几个雷。所以我们先实现面板同时还要存储数据存储雷的位置以及记录玩家操作的位置。所以我们要定义两个数组一个用来存储雷的位置和数字一个用来打印面板和存储玩家操作位置。 int deep[ROW][COL];//深层用来记录布置好的地雷和数字及埋藏在下层的内容char face[ROW][COL];//表面用来打印和记录玩家操作表层对玩家操作进行记录
1、游戏菜单
同时我们还要有游戏菜单供玩家选择难度和退出游戏。两个菜单一个外层一个内层。
//用来打印菜单
void GameMenu(int x)
{switch(x){case 1://外层菜单printf(----------------------------\n);printf(------ 1 for start ---------\n);printf(------ 0 for exit ----------\n);printf(----------------------------\n);break;case 2://内层菜单printf(----------------------------\n);printf(------ 1 for Easy ----------\n);printf(------ 2 for Medium --------\n);printf(------ 3 for Expert --------\n);printf(------ 4 for Nightmare -----\n);printf(------ 0 for back ----------\n);printf(----------------------------\n);break;default :printf(ERROR!\n);break;}
}
同时配合switch语句实现退出或开始游戏与难度选择
GameMenu(1);//外菜单打印
scanf(%d, menu1);//接收选择
switch(menu1)
{
case 0://退出游戏printf(你已退出游戏\n);break;
case 1://内层菜单选择难度GameMenu(2);//内层菜单打印scanf(%d, menu2);//接收选择switch(menu2){case 0://返回上一界面break;case 1:GameEasy(deep, face);//简单难度break;case 2:GameMedium(deep, face);//中等难度break;case 3:GameExpert(deep, face);//大师难度break;case 4:GameNightmare(deep, face);//噩梦难度break;default:printf(ERROR!\n);break;}break;
default :printf(ERROR!\n);break;
}
2、初始始化面板
在定义了两个数组用来存储数据后我们还要对这两个数组初始化初始化的内容是对于整型数组直接初始化为0方便后面数字打印字符型数组初始化为 _ 用来代表没有被揭示的地块。
//用来初始化深层数组difficulty用来传难度不同难度初始化大小不同
void DeepBoardIntial(int deep[ROW][COL], int difficulty)
{int i 0, j 0;for (i 0; i difficulty; i){for (j 0; j difficulty; j){deep[i][j] 0;//初始化为0以便之后填充数字}}
}//用来初始化表面数组difficulty用来传难度不同难度初始化大小不同
void FaceBoardIntial(char face[ROW][COL],int difficulty)
{int i 0, j 0;for (i 0; i difficulty; i){for (j 0; j difficulty; j){face[i][j] _;//初始化为 _ 表示未揭示的格子}}
}
3、面板打印
为了使面板可见我们还需要一个面板打印函数并且在两个数组发生变化时也能打印变化过的面板。也就是在玩家操作后数组内容进行了更新打印的内容也要进行更新。
(1)表格打印
这里只是用来打印表格使界面更美观。
//打印可视化面板
void BoardPrint(int deep[ROW][COL], char face[ROW][COL],int difficulty)
{int i 0, j 0;printf(|);for (j 0; j difficulty; j){printf((%-2d|, j 1);}printf(\n);printf(|);for (j 0; j difficulty; j){printf(___|);}printf(___);printf(\n);for (i 0; i difficulty; i){printf(|);for (j 0; j difficulty; j){ContentPrint(deep,face,i,j);//只有这个是内容打印其他是打印表格为了更加美观}printf((%-2d, i 1);printf(\n);printf(|);for (j 0; j difficulty; j){printf(___|);}printf(___);printf(\n);}
}
(2)内容打印
这个是打印内容实现扫雷过程中内容更新后的打印。
//打印内容对应打印可视化面板这个是打印内容
void ContentPrint(int deep[ROW][COL], char face[ROW][COL], int i, int j)
{if (face[i][j] x)//只要是玩家揭示的直接打印deep中的内容如果是炸弹通过IsGameWin函数判断就直接失败了不会打印{printf( %d |, deep[i][j]);}else if (face[i][j] L)//这里实现的是连续揭示原版的一种操作连续解释的赋值为 L 方便实现当玩家探索一个没有雷的空块时程序应该自动揭示与该空块相邻的所有空块直到遇到数字即与雷相邻的块。这个特性是原版扫雷游戏的关键特点加快游戏进程{if (deep[i][j] 0)//只要数字是零则直接打印空格实现原版的周围八个格没有雷则打印空格{printf( |);}else{printf( %d |, deep[i][j]);//数字不是零则打印这个数字}}else{printf( %c |,face[i][j]);//没有揭示的格子直接打印 _ 表示未揭示的格子}
}
两个函数配合完成打印工作。
三、游戏功能
1、地雷随机生成
//随即放置地雷
void RandomMineGenerate(int deep[ROW][COL],int difficulty,int minesnum)
{int x 0;int y 0;int i 0;srand((unsigned int)time(NULL));//设置随机种子for(i 0;i minesnum;i){x rand() % difficulty;//产生0~8的数字表示随机的行y rand() % difficulty;//产生0~8的数字表示随机的列if(deep[x][y] ! MINE)//确保这个位置不是雷只要不是已经是地雷的格子则放一个地雷防止重复放置导致的地雷数目减少{deep[x][y] MINE;//将这个随机生成的坐标设为雷}else//如果是雷则重新生成{i--;//i--可以实现此次作废再来生成一次的效果}}
}
利用rand函数随机产生坐标将这个坐标设为地雷。
2、装填数字
根据这个格子周围八个格子有几个地雷就把这个格子设为数字几。
//装填数字计算非雷格子中应该是数字几来表示周围雷的个数装填在数组中
void FillinNum(int deep[ROW][COL],int difficulty)
{int i 0, j 0;for (i 0; i difficulty; i){for (j 0; j difficulty; j){if (deep[i][j] MINE)//如果坐标(i,j)是雷则将雷旁边的八个格子都加一{if (CheckIfValid(i - 1,j - 1,difficulty) deep[i - 1][j - 1] ! MINE )//判断格子是否是雷并且判断坐标是否有效格子有效且不是地雷才能加一{deep[i - 1][j - 1];}if (CheckIfValid(i - 1, j, difficulty) deep[i - 1][j] ! MINE){deep[i - 1][j];}if (CheckIfValid(i - 1, j 1, difficulty) deep[i - 1][j 1] ! MINE){deep[i - 1][j 1];}if (CheckIfValid(i, j - 1, difficulty) deep[i][j - 1] ! MINE){deep[i][j - 1];}if (CheckIfValid(i, j 1, difficulty) deep[i][j 1] ! MINE){deep[i][j 1];}if (CheckIfValid(i 1, j - 1, difficulty) deep[i 1][j - 1] ! MINE){deep[i 1][j - 1];}if (CheckIfValid(i 1, j, difficulty) deep[i 1][j] ! MINE){deep[i 1][j];}if (CheckIfValid(i 1, j 1, difficulty) deep[i 1][j 1] ! MINE){deep[i 1][j 1];}}}}
}
3、检查是否胜利
//检查是否胜利0为输1为赢2为继续
int IsGameWin(int deep[ROW][COL], char face[ROW][COL], int row, int col, int difficulty)
{if (deep[row][col] MINE face[row][col] x)//只要是雷且玩家点击返回0即输{return 0;}int i 0, j 0;for (i 0; i difficulty; i){for (j 0; j difficulty; j){if (deep[i][j] ! MINE face[i][j] _)//只要还有非雷格子没探索返回2就继续{return 2;}}}return 1;//没有踩雷且没有非雷格子未探索返回1则赢
}
检查是否胜利或者是否失败以及游戏是否要继续。
4、连续揭示
连续揭示原版的一种操作连续解释的赋值为 L 方便实现当玩家探索一个没有雷的空块时程序应该自动揭示与该空块相邻的所有空块直到遇到数字即与雷相邻的块。这个特性是原版扫雷游戏的关键特点可以加快游戏进程。避免玩家只能一个坐标一个坐标探索浪费太多时间。
//连续揭示点的是周围没有雷的格子即数字零周围就会连续揭示,实现原版操作
//连续揭示原版的一种操作连续解释的赋值为 L 方便实现当玩家探索一个没有雷的空块时程序应该自动揭示与该空块相邻的所有空块直到遇到数字即与雷相邻的块。这个特性是原版扫雷游戏的关键特点加快游戏进程
void LinkChange(int deep[ROW][COL], char face[ROW][COL], int i, int j,int difficulty)
{//由于下面使用了递归必须加入一些条件使得递归不会一直递归下去if (!CheckIfValid(i, j, difficulty))//只要超出雷区范围直接返回函数返回值为void直接return不带任何值{return;}if (face[i][j] L)//已经设置为连续揭示标志 L 的则直接返回{return;}if (deep[i][j] 0 deep[i][j] 9)//在数字0旁边的非零数字也设置为 L 并且返回{face[i][j] L;return;}if (deep[i][j] 9)//是地雷则直接返回{return;}if (deep[i][j] 0)//一个位置为0将这个位值设为 L 并且探索它周围八个格子进行递归{face[i][j] L;LinkChange(deep, face, i - 1, j - 1, difficulty);LinkChange(deep, face, i - 1, j, difficulty);LinkChange(deep, face, i - 1, j 1, difficulty);LinkChange(deep, face, i, j - 1, difficulty);LinkChange(deep, face, i, j 1, difficulty);LinkChange(deep, face, i 1, j - 1, difficulty);LinkChange(deep, face, i 1, j, difficulty);LinkChange(deep, face, i 1, j 1, difficulty);}
}
5、检查坐标是否有效
//检查坐标是否有效
int CheckIfValid(int row, int col,int difficulty)
{if (row 0 row difficulty col 0 col difficulty)//检查坐标是否在雷区内{return 1;//在雷区内为有效返回1为有效}return 0;//不在雷区内为无效返回0为无效
}
四、游戏难度部分
1、简单难度
简单难度的格子为9*9大小有9个地雷。
//简单难度
void GameEasy(int deep[ROW][COL], char face[ROW][COL])
{DeepBoardIntial(deep, 9);//简单难度格子为 9 * 9 大小FaceBoardIntial(face, 9);RandomMineGenerate(deep, 9);//随机生成地雷FillinNum(deep, 9);//装填数字int row 0, col 0;//用来接收玩家输入行列int check 0;//检查是否胜利0为失败1为胜利2为继续do{system(cls);//清屏BoardPrint(deep, face, 9);//打印while(1){printf(输入行列);scanf(%d %d, row, col);if (CheckIfValid(row - 1, col - 1,9) face[row - 1][col - 1] ! x)//有效且是没被揭开的则输入成功{face[row - 1][col - 1] x;break;//输入成功则直接退出循环}else if (CheckIfValid(row - 1, col - 1, 9) (face[row - 1][col - 1] x || face[row - 1][col - 1] L))//输入的坐标为已经揭示的格子则重新输入{printf(已经揭示的格子请不要重复操作重新输入\n);}else//不在范围内重新输入{printf(范围错误重新输入\n);}}check IsGameWin(deep, face,row - 1,col - 1,9);//检查是否胜利或失败以及游戏是否继续if(check 2)//只要游戏继续就判断是否连续揭示{if(deep[row - 1][col - 1] 0)//揭示的格子是空格(即格子是0周围八个格子没有地雷)则尝试连续揭示{LinkChange(deep, face, row - 1, col - 1,9);//对于这个输入的格子进行连续揭示}}} while (check 2);//只要check为2则继续则循环继续则游戏继续check为1或0(即赢或输)是退出循环if (check 1)//check为1时胜利{printf(你赢了\n);}else if(check 0)//check为0时失败{printf(你输了\n);}else//错误{printf(ERROR!\n);}
}
2、中等难度
中等难度大小为16*16有32个地雷。
//中等难度
void GameMedium(int deep[ROW][COL], char face[ROW][COL])
{DeepBoardIntial(deep, 16);//中等难度格子为 16 * 16 大小FaceBoardIntial(face, 16);RandomMineGenerate(deep, 16,32);//随机生成地雷FillinNum(deep, 16);//装填数字int row 0, col 0;//用来接收玩家输入行列int check 0;//检查是否胜利0为失败1为胜利2为继续do{system(cls);//清屏BoardPrint(deep, face, 16);//打印while (1){printf(输入行列);scanf(%d %d, row, col);if (CheckIfValid(row - 1, col - 1, 16) face[row - 1][col - 1] ! x face[row - 1][col - 1] ! L)//有效且是没被揭开的则输入成功{face[row - 1][col - 1] x;break;//输入成功则直接退出循环}else if (CheckIfValid(row - 1, col - 1, 16) (face[row - 1][col - 1] x || face[row - 1][col - 1] L))//输入的坐标为已经揭示的格子则重新输入{printf(已经揭示的格子请不要重复操作重新输入\n);}else//不在范围内重新输入{printf(范围错误重新输入\n);}}check IsGameWin(deep, face, row - 1, col - 1, 16);//检查是否胜利或失败以及游戏是否继续if (check 2)//只要游戏继续就判断是否连续揭示{if (deep[row - 1][col - 1] 0)//揭示的格子是空格(即格子是0周围八个格子没有地雷)则尝试连续揭示{LinkChange(deep, face, row - 1, col - 1, 16);//对于这个输入的格子进行连续揭示}}} while (check 2);//只要check为2则继续则循环继续则游戏继续check为1或0(即赢或输)是退出循环if (check 1)//check为1时胜利{printf(你赢了\n);}else if (check 0)//check为0时失败{printf(你输了\n);}else//错误{printf(ERROR!\n);}
}
3、大师难度
大师难度格子为30*30有90个地雷。
//大师难度
void GameExpert(int deep[ROW][COL], char face[ROW][COL])
{DeepBoardIntial(deep, 30);//大师难度格子为 30 * 30 大小FaceBoardIntial(face, 30);RandomMineGenerate(deep, 30,90);//随机生成地雷FillinNum(deep, 30);//装填数字int row 0, col 0;//用来接收玩家输入行列int check 0;//检查是否胜利0为失败1为胜利2为继续do{system(cls);//清屏BoardPrint(deep, face, 30);//打印while (1){printf(输入行列);scanf(%d %d, row, col);if (CheckIfValid(row - 1, col - 1, 30) face[row - 1][col - 1] ! x face[row - 1][col - 1] ! L)//有效且是没被揭开的则输入成功{face[row - 1][col - 1] x;break;//输入成功则直接退出循环}else if (CheckIfValid(row - 1, col - 1, 30) (face[row - 1][col - 1] x || face[row - 1][col - 1] L))//输入的坐标为已经揭示的格子则重新输入{printf(已经揭示的格子请不要重复操作重新输入\n);}else//不在范围内重新输入{printf(范围错误重新输入\n);}}check IsGameWin(deep, face, row - 1, col - 1, 30);//检查是否胜利或失败以及游戏是否继续if (check 2)//只要游戏继续就判断是否连续揭示{if (deep[row - 1][col - 1] 0)//揭示的格子是空格(即格子是0周围八个格子没有地雷)则尝试连续揭示{LinkChange(deep, face, row - 1, col - 1, 30);//对于这个输入的格子进行连续揭示}}} while (check 2);//只要check为2则继续则循环继续则游戏继续check为1或0(即赢或输)是退出循环if (check 1)//check为1时胜利{printf(你赢了\n);}else if (check 0)//check为0时失败{printf(你输了\n);}else//错误{printf(ERROR!\n);}
}
4、噩梦难度
噩梦难度格子为50*50地雷为250个。
//噩梦难度
void GameNightmare(int deep[ROW][COL], char face[ROW][COL])
{DeepBoardIntial(deep, 50);//噩梦难度格子为 50 * 50 大小FaceBoardIntial(face, 50);RandomMineGenerate(deep, 50, 250);//随机生成地雷FillinNum(deep, 50);//装填数字int row 0, col 0;//用来接收玩家输入行列int check 0;//检查是否胜利0为失败1为胜利2为继续do{system(cls);//清屏BoardPrint(deep, face, 50);//打印while (1){printf(输入行列);scanf(%d %d, row, col);if (CheckIfValid(row - 1, col - 1, 50) face[row - 1][col - 1] ! x face[row - 1][col - 1] ! L)//有效且是没被揭开的则输入成功{face[row - 1][col - 1] x;break;//输入成功则直接退出循环}else if (CheckIfValid(row - 1, col - 1, 50) (face[row - 1][col - 1] x || face[row - 1][col - 1] L))//输入的坐标为已经揭示的格子则重新输入{printf(已经揭示的格子请不要重复操作重新输入\n);}else//不在范围内重新输入{printf(范围错误重新输入\n);}}check IsGameWin(deep, face, row - 1, col - 1, 50);//检查是否胜利或失败以及游戏是否继续if (check 2)//只要游戏继续就判断是否连续揭示{if (deep[row - 1][col - 1] 0)//揭示的格子是空格(即格子是0周围八个格子没有地雷)则尝试连续揭示{LinkChange(deep, face, row - 1, col - 1, 50);//对于这个输入的格子进行连续揭示}}} while (check 2);//只要check为2则继续则循环继续则游戏继续check为1或0(即赢或输)是退出循环if (check 1)//check为1时胜利{printf(你赢了\n);}else if (check 0)//check为0时失败{printf(你输了\n);}else//错误{printf(ERROR!\n);}
}
五、主函数部分
主函数集成游戏的功能。
int main()
{int deep[ROW][COL];//深层用来记录布置好的地雷和数字及埋藏在下层的内容char face[ROW][COL];//表面用来打印和记录玩家操作表层对玩家操作进行记录int menu1 0;//外层菜单0为退出游戏1为进入游戏int menu2 0;//内层菜单0为返回上一步1为简单难度2为中等难度3为大师难度do{GameMenu(1);//外菜单打印scanf(%d, menu1);//接收选择switch(menu1){case 0://退出游戏printf(你已退出游戏\n);break;case 1://内层菜单选择难度GameMenu(2);//内层菜单打印scanf(%d, menu2);//接收选择switch(menu2){case 0://返回上一界面break;case 1:GameEasy(deep, face);//简单难度break;case 2:GameMedium(deep, face);//中等难度break;case 3:GameExpert(deep, face);//大师难度break;case 4:GameNightmare(deep, face);//噩梦难度break;default:printf(ERROR!\n);break;}break;default :printf(ERROR!\n);break;}} while (menu1);//只要非零就一直循环进行游戏为0则退出游戏return 0;
}
六、头文件
头文件声明函数。
#pragma once
#include stdio.h
#include stdlib.h
#include time.h#define ROW 50//宏定义方便更改
#define COL 50
#define MINE 9//宏定义定义9为雷//菜单打印
void GameMenu(int x);//深层数组初始化
void DeepBoardIntial(int deep[ROW][COL],int difficulty);//表面数组初始化
void FaceBoardIntial(char face[ROW][COL],int difficulty);//连续揭示打印
void LinkChange(int deep[ROW][COL], char face[ROW][COL], int i, int j,int difficulty);//实际打印实现
void ContentPrint(int deep[ROW][COL], char face[ROW][COL], int i, int j);//面板打印
void BoardPrint(int deep[ROW][COL], char face[ROW][COL],int difficulty);//随机生成雷
void RandomMineGenerate(int deep[ROW][COL], int difficulty,int minesnum);//检查是否胜利
int IsGameWin(int deep[ROW][COL], char face[ROW][COL], int row, int col, int difficulty);//填入数字
void FillinNum(int deep[ROW][COL], int difficulty);//检查输入坐标是否有效
int CheckIfValid(int row, int col, int difficulty);//简单难度
void GameEasy(int deep[ROW][COL], char face[ROW][COL]);//中等难度
void GameMedium(int deep[ROW][COL], char face[ROW][COL]);//大师难度
void GameExpert(int deep[ROW][COL], char face[ROW][COL]);//噩梦难度
void GameNightmare(int deep[ROW][COL], char face[ROW][COL]);
七、一些问题和解决办法
1、打印显示问题
在游玩专家难度及以上的难度时或者在游玩你自己改进的难度时你可以通过更改宏ROW和COL的大小实现更大的格子范围会发现打印出现下列状况 打印出来的格子错位了。
这个问题可以通过全屏控制台解决若还不行的话可能是格子范围太大可以通过使用Ctrl 鼠标滚轮来对控制台缩放Ctrl 鼠标滚轮下滑可以缩放控制台使得格子复位。在你不能看到完整的雷区时也可以使用这个方法。
2、输入设置
默认输入坐标是 scanf(%d %d, row, col);
输入坐标时中间要加一个空格或回车分开例如 或 中间不能加其他字符加其他字符会出错你也可以改为 scanf(%d,%d, row, col);
这样就只能用 , 进行分隔了不能用其他字符分隔了。