头文件: game.h
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>
#define ROW 10 // 棋盘的行与列数
#define LIN 10
#define ROWS ROW+2 // 数组的行与列数
#define LINS LIN+2
#define NUMBERMINE 10// 雷的个数
// 打印游戏菜单
void meau();
// 具体的扫雷游戏的逻辑
void game();
// 初始化数组
void init_board(char board[ROWS][LINS], int rows, int lins);
// 生成雷
void creat_mine(char board[ROWS][LINS], int row, int lin);
//打印数组,检查是否生成10个雷
void print_board(char board[ROWS][LINS], int row, int lin);
// 存储雷的数量
// 根据board1将数据存储在board2中
void number_mine(char board1[ROWS][LINS], int row, int lin);
// 判断该位置周围雷的数量,并以字符的形式返回
char how_much_mine(char board[ROWS][LINS], int x, int y);
//打印棋盘
void print_mine_board(char board[ROWS][LINS], int row, int lin);
//该位置雷的个数为0个,则需要扩散
void kuo_san(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int x, int y);
//完全扩散
void wanquan_kuosan(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int x, int y, int row, int lin);
//将雷的位置纪录的打印的棋盘上
void writre_mine(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int row, int lin);
//记录标雷的个数
int number_flag(char mine_board[ROWS][LINS], int row, int lin);
//判断标记的位置与雷的位置匹配的个数
int flag_win(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int row, int lin);
//用来查看棋盘的使用个数
int number_of_x(char mine_board[ROWS][LINS], int row, int lin);
游戏代码: game.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
// 打印游戏菜单
void meau()
{
printf("******************\n");
printf("*****1. play *****\n");
printf("*****0. exit *****\n");
printf("******************\n");
}
// 具体的扫雷游戏的逻辑
void game()
{
printf("欢迎进入扫雷游戏,祝您游戏愉快!!\n");
// 首先生成雷,并用数组mine[ROWS][LINS] 存储,雷用字符1表示,非雷用字符0表示
char mine[ROWS][LINS] = { 0 };
// 初始化数组
init_board(mine,ROWS,LINS,'0');
// 生成雷
srand((unsigned int)time(NULL));
creat_mine(mine, ROW, LIN);
// 打印数组,检查是否生成10个雷
//print_board(mine, ROW, LIN); // 测试:成功生成NUMBERMINE个雷
// 存储每个格子周围雷的数量
number_mine(mine, ROW, LIN);
// 打印数组,测试雷的数量是否存储成功
//printf("底层数据:\n");
//print_board(mine, ROW, LIN); // 成功
//用于界面显示的扫雷数组
char mine_board[ROWS][LINS] = { 0 };
//初始化数组
init_board(mine_board, ROWS, LINS,'*');
//打印数组
//print_board(mine_board, ROW, LIN);
// 先打印棋盘
print_mine_board(mine_board, ROW, LIN);
// 第一次点击
int x0 = 0;
int y0 = 0;
int flag0 = 0;
printf("请选择位置点击或标记:\n");
printf("例如您要点击(4,5)处 ,则输入4 5 1\n");
printf("例如您要标记(4,5)处 ,则输入4 5 2\n");
scanf(" %d %d %d", &x0, &y0, &flag0);
//第一次使用只能选择点击模式,保证第一次点击至少扩散出NUMBERMINE格子以上
//可以用扩散的格子数来控制循环
int ksn = 0;
while (ksn <= NUMBERMINE)
{
// 先打印棋盘
print_mine_board(mine_board, ROW, LIN);
//若点击的位置mine不为0,则重新生成mine
if (mine[x0][y0] != '0')
{
// 重新初始化数组
init_board(mine, ROWS, LINS, '0');
//重新生成雷
creat_mine(mine, ROW, LIN);
//重新生成雷数
number_mine(mine, ROW, LIN);
continue;
}
if(mine[x0][y0] == '0')
{
//若点击的位置为0;则要判断是否满足大于NUMBERMINE
printf("底层数据:\n");
print_board(mine, ROW, LIN);
wanquan_kuosan(mine, mine_board, x0, y0, ROW, LIN);
ksn = number_of_x(mine_board, ROW, LIN);
if (ksn > 10)
{
break;
}
else
{
// 重新初始化数组
init_board(mine, ROWS, LINS, '0');
//重新生成雷
creat_mine(mine, ROW, LIN);
//重新生成雷数
number_mine(mine, ROW, LIN);
//棋盘也要初始化
init_board(mine_board, ROWS, LINS, '*');
continue;
}
}
}
while (1)
{
// 先打印棋盘
print_mine_board(mine_board, ROW, LIN);
// 然后选择位置点击
// 点击的位置必须是未没点击过且没有被>标记过
int x = 0;
int y = 0;
int flag = 0;
printf("请选择位置点击或标记:\n");
printf("例如您要点击(4,5)处 ,则输入4 5 1\n");
printf("例如您要标记(4,5)处 ,则输入4 5 2\n");
scanf(" %d %d %d", &x, &y, &flag);
// 若选择点击模式
if (flag == 1)
{
//首先判断是否被点击或标记过,若被点击或过,直接跳入下一次循环
if (mine_board[x][y] == '*')
{
//判断是否是雷,
//若是雷,游戏结束
if (mine[x][y] != '9')
{
// 若不是雷,则显示该位置雷的个数
// 若该位置雷的个数为0,则显示周围的位置
if (mine[x][y] > '0')//该位置雷的个数不为0
{
//将雷的个数存储到mine_board中,并同时记录该位置已经被点击过
mine_board[x][y] = mine[x][y];
//之后打印棋盘
print_mine_board(mine_board, ROW, LIN);
//之后进入下一个循环
continue;
}
else//该位置周围无雷
{
//该位置雷的个数为0个,则需要扩散
//kuo_san(mine, mine_board, x, y);
// 从本位开始,直到扩散本位周围没有0为止
wanquan_kuosan(mine, mine_board, x, y, ROW, LIN);
// 扩散完之后打印棋盘
print_mine_board(mine_board, ROW, LIN);
continue;
}
}
else
{
// 该位置是雷
// 则显示已经点击过的位置,并且将雷的位置显示出来
// 打印出的雷用@
printf("很遗憾,你败了,真是个废物0.0\n");
printf("废物看好了,看好你是怎么输的\n");
//将雷的位置纪录的打印的棋盘上
writre_mine(mine,mine_board,ROW,LIN);
//记录完之后打印棋盘
print_mine_board(mine_board, ROW, LIN);
break;
}
}
else
{
printf("对不起,此位置已被点击过,请重新点击\n");
continue;
}
}
//若选择标记模式
if (flag == 2)
{
//此位置之前未被标记过
if (mine_board[x][y] == '*')
{
//记录标雷的个数,如果雷大于NUMBERMINE个,则无法继续标记
int number = number_flag(mine_board, ROW, LIN);
// 最多标记NUMBERMINE个雷
if (number < NUMBERMINE)
{
mine_board[x][y] = '>';
//当标记满十个以后,判断输赢
if ((number + 1) == NUMBERMINE)
{
//若赢了则恭喜
//若标记的NUMBERMINE个位置与雷的位置不符合,则不显示,知道标记的位置与显示的位置沾满整个棋盘,则提示您可能标记错误
//先判断赢的情况1
int win = flag_win(mine, mine_board, ROW, LIN);
if (win == NUMBERMINE)
{
printf("恭喜你,游戏通关\n");
print_mine_board(mine_board, ROW, LIN);
break;
}
//棋盘满了的情况,标记的位置+显示的位置是满的,此种情况获胜,被上面的情况所包含
}
continue;
}
else
{
printf("对不起,最多只能标记 %d 个位置\n", NUMBERMINE);
continue;
}
}
//若标记过则解除标记状态
if (mine_board[x][y] == '>')
{
mine_board[x][y] = '*';
continue;
}
}
}
}
// 初始化数组
void init_board(char board[ROWS][LINS],int rows,int lins,char ch)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < lins; j++)
{
board[i][j] = ch;
}
}
}
// 生成雷
// 有雷的地方用9表示
void creat_mine(char board[ROWS][LINS], int row, int lin)
{
int i = 0;
int j = 0;
// 统计雷的个数
int count = 0;
while (1)
{
// 生成随机的坐标用来放雷
i = (rand() % row) + 1;
j = (rand() % lin) + 1;
if (board[i][j] == '0')
{
board[i][j] = '9';
count++;
}
if (count == NUMBERMINE)
{
break;
}
}
}
//打印数组,检查是否生成10个雷
void print_board(char board[ROWS][LINS], int row, int lin)
{
int i = 0;
int j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= lin; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
// 存储雷的数量
// 根据board1将数据存储在board1中
void number_mine(char board[ROWS][LINS], int row, int lin)
{
int i = 0;
int j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= lin; j++)
{
//将该位置雷的个数以字符的形式存储在
if (board[i][j] != '9')
{
board[i][j] = how_much_mine(board, i, j);
}
}
}
}
// 判断该位置周围雷的数量,并以字符的形式返回
char how_much_mine(char board[ROWS][LINS], int x, int y)
{
int sum = 0;
sum = board[x-1][y-1] + board[x][y-1] + board[x+1][y-1] +
board[x-1][y] + board[x+1][y] +
board[x-1][y+1] + board[x][y+1] + board[x+1][y+1];
sum = sum - (48 * 8);
return ((sum / 9) + 48);
}
//打印棋盘
void print_mine_board(char board[ROWS][LINS], int row, int lin)
{
int i = 0;
int j = 0;
//打印列数
for (j = 1; j <= lin; j++)
{
if (j == 1)
{
printf(" %-2d", j);
continue;
}
printf(" %-2d", j);
}
printf("\n");
//打印上边界
for (j = 1; j <= lin; j++)
{
if (j == 1)
{
printf(" ---");
continue;
}
printf(" ---");
}
printf("\n");
//打印剩下的网格
for (i = 1; i <= row; i++)
{
for (j = 1; j <= lin; j++)
{
if (j == 1)
{
printf("%-2d| %c |",i,board[i][j]);
continue;
}
printf(" %c |", board[i][j]);
}
printf("\n");
for (j = 1; j <= lin; j++)
{
if (j == 1)
{
printf(" ---");
continue;
}
printf(" ---");
}
printf("\n");
}
}
//该位置雷的个数为0个,则需要扩散
void kuo_san(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int x, int y)
{
//要保证扩散的同时也要标记扩散的那些位置标记已经被使用过
if (mine[x][y] == '0')
{
int i = x;
int j = y;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
//标记的假定被认为是雷,此时不需要扩散
if (mine_board[i][j] != '>')
{
//若周围没有标记,则为0的地方显示空格
//是数字则显示数字
if (mine[i][j] == '0' || mine[i][j] ==' ')
{
mine_board[i][j] = ' ';
}
else
{
mine_board[i][j] = mine[i][j];
}
}
}
}
}
}
//完全扩散
void wanquan_kuosan(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int x, int y,int row,int lin)
{
//若本位不为0 或者为‘ ’时也不需要扩散 或被标记过,则不需要扩散
if (mine[x][y] != '0' || mine_board[x][y] == '>' || mine[x][y] == ' ' || mine[x][y] == '9')
{
return;
}
//先让本位扩散一边,然后标记一下,本位扩散过
kuo_san(mine, mine_board, x, y);
mine[x][y] = ' ';
int i = 0;
int j = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
//保证在棋盘内
if (((i>=1)&&(i<=row))&&((j>=1)&&(j<=lin)))
{
if ((mine[i][j] != ' ') && (mine[i][j] == '0'))
{
kuo_san(mine, mine_board, i, j);
wanquan_kuosan(mine, mine_board, i, j, ROW, LIN);
}
}
}
}
}
//将雷的位置纪录的打印的棋盘上
void writre_mine(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int row, int lin)
{
int i = 0;
int j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= lin; j++)
{
if (mine[i][j] == '9')
{
//如果此位置时雷,则记录到打印的棋盘中
mine_board[i][j] = '@';
}
}
}
}
//记录标雷的个数
int number_flag(char mine_board[ROWS][LINS], int row, int lin)
{
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= lin; j++)
{
if (mine_board[i][j] == '>')
{
count++;
}
}
}
return count;
}
//判断标记的位置与雷的位置匹配的个数
int flag_win(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int row, int lin)
{
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= lin; j++)
{
if ((mine[i][j] == '9') && (mine_board[i][j] == '>'))
{
count++;
}
}
}
return count;
}
//用来查看棋盘的使用个数
int number_of_x(char mine_board[ROWS][LINS], int row, int lin)
{
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= lin; j++)
{
if (mine_board[i][j] != '*')
{
count++;
}
}
}
return count;
}
代码实现:test.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
int main()
{
//输入选择游戏模式
int input = 0;
do
{
printf("============================================================\n");
meau();
printf("请输入您要选择的模式 :\n");
scanf(" %d", &input);
switch (input)
{
case 1:
//具体的扫雷游戏的逻辑
//printf("玩游戏\n");
game();
break;
case 0:
printf("已成功退出扫雷游戏,谢谢使用\n");
break;
default:
printf("对不起,您输入的模式非法!\n");
break;
}
}
while(input);
return 0;
}