一:头文件部分
#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<math.h>
#include<Windows.h>
#include<errno.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9 // 行 扫雷以及布雷的时候用
#define COL 9 //列
#define ROWS ROW+2 //创建棋盘考虑判断时候用
#define COLS COL+2
#define bomb 10 //地雷的数量
//菜单
void menu();
//游戏主体
void game();
//初始化
void lnitboard(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void displayboard(char board[ROWS][COLS], int row, int col);//board只是数组名在这段函数中的名称而已 不影响数据
//设置雷区
//因为传输的rows cols的棋盘 所以自然也用同样的规格接收
void setmine(char board[ROWS][COLS], int row, int col, char set);//set是雷的代号
//计算选中坐标周围的雷区
int count(char board[ROWS][COLS], int i, int j);
//爆破棋盘
void Bombboard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int n, int m);
//排雷
void playmove(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
二:函数实现部分
#define _CRT_SECURE_NO_WARNINGS 1
#include"zhk.h"
//菜单
void menu()
{
printf("*********************欢迎来到征氏扫雷游戏!************************\n");
printf("*********************祝你游玩愉快!********************************\n");
printf("**********************1. play 0.exit********************************\n");
}
//初始化
void lnitboard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
//设置雷区
void setmine(char board[ROWS][COLS], int row, int col, char set)
{
int i, j;//i j是行标和列标 c代表要布置多少地雷
int c = 0;
while (1)
{
//行标与列标的范围是1-9
i = rand() % row + 1;//一个数的余数只能是0~被除数-1 否则进一了
j = rand() % col + 1;
if (i <= row && j <= col && board[i][j] == '0')//需要此区域并没有布过雷 而且坐标的输入在规定的区域
{
board[i][j] = set;//如果符合这个规范则将随机的坐标变为雷区
c++;
}
if (c== bomb)
{
break;
}
}
}
//打印棋盘
void displayboard(char board[ROWS][COLS], int row, int col)
{
int i, j;
printf("*******************扫雷游戏***********************\n");
for (j = 0; j<= col; j++)//打印每一行的列标
{
printf("%d ", j);//就用列标j 反正会重新赋值为0
}
printf("\n");//打印完列标换行
for (i = 1; i <= row; i++)//i为行标 j为列标
{
printf("%d ", i);//打印每一行的行标 行标从1开始就行
for (j = 1; j <= col; j++)//打印每一行的数据
{
printf("%c ", board[i][j]);//打印每一行的数据 数据内容由所传输的数组决定
}
printf("\n");//一行打印完换下一行
}
printf("*******************扫雷游戏***********************\n");
}
//显示选中坐标周围雷的数量
int count(char board[ROWS][COLS], int i, int j)
{
int a = 0, b = 0,c=0;//创建变量用于作为坐标 与 计算雷区
for (a = i - 1; a < i + 2; a++)//行
{
for (b = j - 1; b < j + 2; b++)//列
{
if (board[a][b] == '$')//如果附近有雷就加一 没有就还是0
{
c++;
}
}
}
return c;//将附近雷的数量返回
}
//爆破棋盘
void Bombboard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,int n,int m)
{
int z = count(mine, n, m);//计算坐标附近雷区数量并赋值
if (mine[n][m] == '0')//想要爆破首先自己这边就不能是雷;
{
//只有周围没有雷的时候才会将周围的数目变成空格 同理只有周围没有雷的时候才会进入下一层递归 否则返回上一层递归
if (z== 0)//如果附近没有雷 则将附近包括自己3*3的区域赋值为空格
{
for (int a = n - 1; a < n + 2; a++)//a n为行标 b m为列标
{//然后确定自己这一圈有没有雷 否则不爆破
int b = 0;
for (b = m - 1; b < m + 2; b++)
{
if (mine[a][b] == '0')
{
if (show[a][b] == '*')//被展开变为空格的不递归 直接跳过
{
show[a][b] = ' ';//如果被选中区域不是雷区 那么在显示棋盘上改为空格
Bombboard(mine, show, row, col, a, b);
}
}
}
}
}
else
{
show[n][m] = z + '0';//整型数字+数字字符可将整型数字转换为数字字符 反之同理
}
}
else
{
printf("gameover 游戏结束!\n");
printf("运气不好,下次努力哦\n");
printf("你共排雷:0颗\n");
displayboard(mine, row, col);
}
}
//显示爆破之后排雷的数量 然后计入到总进度中
int showwin(char board[ROWS][COLS], int row, int col)
{
int i = 0,z=0;//i为行标 j为列标 z表示空格的数量在棋盘中
for (i = 1; i <= row; i++)//每一行的个数
{
int j = 0;
for (j = 1; j <= col; j++)
{
if (board[i][j] != '*')//计算排除的数量
{
z++;//z代表排除的数量
}
}
}
return z;
}
//排雷
void playmove(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//因是扫雷 正常的规格
{
int i = 0, j = 0;
int win = 0;//i j表示坐标 win表示剩余空格数
int z = 0;//表示周围有几个雷
printf("请输入你要爆破的区域(如1空格1 然后回车) 如果选中区域不是雷区 将展开棋盘上临近位置不是雷的棋子\n");
int n = 0, m = 0;
scanf("%d%d", &n, &m);
Bombboard(mine, show, ROW, COL, n, m);//传输棋盘基本数据以及需要爆破的区域 将空格数传输爆破一次加一次
displayboard(show, row, col);//爆破完成 打印棋盘
win = showwin(show, row, col);
while (win < row * col - bomb)//如果不符合规定就一直处于输入状态
{
if (win == 0)//第一次进入时提示输入样例
{
printf("输入的坐标 一般为0 0 第一个0表示行 第二个0表示列 中间空格隔开\n");
}
printf("请输入坐标>?:");
scanf("%d%d", &i, &j);//输入坐标
if (show[i][j] == '*' && (i >= 1 && i <= row) && (j >= 1 && j <= col))
{
if (mine[i][j] == '0')//如果输入的坐标有雷 就返回@结束循环
{
z = count(mine, i, j);//因为是计算雷的数量 自然要传输雷区的数据
win++;//代表排雷一颗
show[i][j] = z + '0';//探查完之后再赋值给相应显示棋盘的坐标 将整型数组 转换为字符数字
displayboard(show, row, col);
printf("恭喜你排雷成功,你离成功又进了%d步\n", win);
}
else
{
if (win < 10)
{
printf("gameover 游戏结束!\n");
printf("运气不好,下次努力哦\n");
printf("你共排雷:% d颗\n", win);
displayboard(mine, row, col);
break;
}
if (win <= 30)
{
printf("还可以,再接再厉吧!\n");
printf("你共排雷:% d颗\n", win);
displayboard(mine, row, col);
break;
}
if (win <= 50)
{
printf("太可惜了,下次一定成功!加油!\n");
printf("你共排雷:% d颗\n", win);
displayboard(mine, row, col);
break;
}
break;
}
}
else
{
printf("输入坐标非法,请重新输入\n");
}
}
if (win == ROW * COL - bomb)
{
printf("恭喜这位勇士,排雷成功\n");
displayboard(mine, row, col);
};
}
//游戏主体
void game()
{
srand((unsigned int)time(NULL));
char mine[ROWS][COLS] = { 0 };//布置雷区
char show[ROWS][COLS] = { 0 };//扫雷使用
lnitboard(mine, ROWS, COLS, '0');//初始化布雷区
lnitboard(show, ROWS, COLS, '*');//初始化扫雷区
setmine(mine, ROW, COL,'$');//设置雷区 用$来表示雷
displayboard(show, ROW, COL);
playmove(mine,show,ROW,COL);//因为同时要用到所以两个都传输
}
三:测试部分
#define _CRT_SECURE_NO_WARNINGS
#include "zhk.h"
int main()
{
menu();//显示菜单
int n = 0;//创建变量以便于选择项目
do
{
printf("请输入>?:");
scanf("%d", &n);//输入选择数值
switch (n)
{
case 0:
{
printf("正在退出游戏请稍后,欢迎下次再来!\n");
Sleep(250);//250微秒后执行
printf("游戏退出完成\n");
break;
}
case 1:
{
printf("欢迎游玩本游戏!\n"); \
game();//运行游戏主体
break;
}
default :
{
printf("输入错误,请重新输入\n");
break;
}
}
} while (n);
}