本次讲解扫雷小游戏(小小升级的版本)
游戏规则:根据电脑提示输入位置,当输入的位置让有雷,游戏结束;输入的位置是哪个没有雷,游戏继续,并且会显示周围八个位置的雷的情况
为了让代码更加模块化,首先我们需要分别创建game.h game.c test.c
game.h 里面存放的是头文件的声明、函数的声明、以及雷盘大小的自由化改动
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
//包含头文件
#include
#include
#include
//方便修改雷盘大小
#define ROW 3
#define COL 3
#define ROWS ROW+2
#define COLS COL+2
//声明初始化雷盘函数
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret);
//声明打印雷盘函数
void PrintBoard(char board[ROWS][COLS], int row, int col);
//声明布置雷函数
void setmine(char board[ROWS][COLS], int row, int col, int num);
//声明排查雷的函数
void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row,int col,int num);
根据游戏需求,我们需要一个可以提供玩家选择的游戏菜单
void menu()
{
printf("*************---------------***************\n");
printf("******--------- ---------*******\n");
printf("******--------- 1.玩游戏 ---------*******\n");
printf("\n");
printf("******--------- 0.退出游戏 --------********\n");
printf("******--------- ---------*******\n");
printf("*************---------------***************\n");
}
玩家按照菜单的内容进行选择,根据不同的选择编写 switch 语句
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 0:
system("cls");
system("pause");
printf("欢迎您的下一次体验,再见!\n");
break;
case 1:
game();
break;
default:
printf("输入错误,请重新选择\n");
break;
}
} while (input);
}
创建一个理想雷盘
char Secret[ROWS][COLS] = { 0 }; //秘密雷盘
char Show[ROWS][COLS] = { 0 };//展示的雷盘
正常来说,扫雷游戏只需要一个雷盘,但是这里设置了两个雷盘的原因是: Secret雷盘是用来存储雷的信息的,这里不能给玩家看;Show雷盘是玩家进行游戏的雷盘,两者有不同的作用,所以需要设置两个规模一样的雷盘。
初始化雷盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)
{
memset(board, ret, sizeof(board[0][0]) * rows * cols);
}
因为这里是char类型的数组,所以直接使用memset初始化。
雷盘打印
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
printf("------------------------扫雷游戏-------------------\n");
int i = 0, j = 0;
printf(" ");
for (i = 1; i <= row; i++)
{
printf("%3d ", i);
}
printf("\n");
printf(" +");
for (i = 0; i < row; i++)
{
printf("---+");
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%2d", i);
printf("|");
for (j = 1; j <= col; j++)
{
printf(" %c |", board[i][j]);
}
printf("\n");
printf(" +");
for (j = 0; j < col; j++)
{
printf("---+");
}
printf("\n");
}
printf("------------------------扫雷游戏-------------------\n");
}
布置雷盘
void setmine(char board[ROWS][COLS], int row, int col, int num)
{
//随机布雷
int x = 0;
int y = 0;
for (int i = 0; i < num; )
{
x = rand() % row + 1; //x产生[1,row]之间的坐标
y = rand() % col + 1; //y产生[1,col]之间的坐标
if (board[x][y] == '0')
{
board[x][y] = '1';
i++;
}
}
}
模式选择
玩家可以自行选择困难模式,也可以自定义模式
int ModeSelection()
{
int num = 0;
again: //玩家选择模式错误时返回到这里
printf("欢迎玩家来到扫雷游戏\n");
printf("\n请选择扫雷难度: (num的代表雷的数量)\n");
printf("A.轻松模式:num=5 B.皱眉头模式:num=15 C.出汗模式:num=30 D.DIY难度(玩家自行输入雷的个数)\n ");
char pattern = 0;
getchar();//清空缓存区
scanf("%c", &pattern);
switch (pattern)
{
case 'A':
case 'a':
printf("轻松模式:num=5\n");
num = 5;
return num;
break;
case 'B':
case 'b':
printf("皱眉头模式:num=15\n");
num = 15;
return num;
break;
case 'C':
case 'c':
printf("出汗模式:num=30\n");
num = 30;
return num;
break;
case 'D':
case 'd':
printf("DIY模式:\n");
printf("请输入想要布置雷的个数:\n");
getchar();//清楚缓存区
int intput = 0;
scanf("%d", &intput);//用户自定义的雷的个数
num = intput;
return num;
break;
default:
printf("\n******不好意思,皮蛋还没有此功能按键,请重新选择:******\n\n");
goto again;
break;
}
}
排查雷
void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int num)
{
int x = 0;
int y = 0;
int win = 0; //被排查的个数
while ((row * col - num) > win)
{
printf("请输入排雷坐标(格式:行号 列号)\n");
scanf("%d%d", &x, &y);
if (show[x][y] != '*')
{
printf("该坐标已经被排查过了 请重新输入:\n");
continue;
}
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (secret[x][y] == '1')//如果是1就代表是雷,游戏结束
{
printf("很遗憾,你失败了\n");
printf("请看答案:\n");
PrintBoard(secret, ROW, COL);//失败后,给玩家看答案雷盘
break;
}
else
{
Recursive(secret, show, ROW, COL, x, y); //自动递归排雷函数
win = is_win(show, ROW, COL); //计算已经被排查的位置
PrintBoard(show, ROW, COL);//打印给玩家的雷盘
}
}
else
{
printf("坐标非法,请重新输入:\n");
}
}
if (win == (row * col - num))
{
printf("恭喜你排雷成功\n");
}
}
递归进行自动排雷(显示周围雷的情况)
Recursive(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
int count = countmine(secret, x, y);//计算该坐标周围有几个雷
if (count == 0)
{
show[x][y] = ' ';//周围没有雷的坐标变为空格
int i = 0, j = 0;
for (i = x - 1; i <= x + 1; i++)//观察周围八个坐标
{
for (j = y - 1; j <= y + 1; j++)
{
if (show[i][j] == '*' && (i != x || j != y))//防止重新递归show[x][y]坐标
{
Recursive(secret, show, ROW, COL, i, j);
}
}
}
}
else
{
show[x][y] = count + '0';
}
}
}
计算周围雷的个数
int countmine(char secret[ROWS][COLS], int x, int y)
{
int ret = secret[x - 1][y - 1] + secret[x - 1][y] + secret[x - 1][y + 1]
+ secret[x][y - 1] + secret[x][y + 1]
+ secret[x + 1][y - 1] + secret[x + 1][y] + secret[x + 1][y + 1] - 8 * '0';
return ret;
}
计算已经被排查过的位置,进而判断是否还有空位进行排雷游戏
int is_win(char show[ROWS][COLS], int row, int col)
{
int count1 = 0;//已经被排查的坐标个数
int i = 0, j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (show[i][j] != '*')//只要不是*,表示该坐标已经被排查了.
{
count1++;
}
}
}
return count1;
}
game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
//包含头文件
#include
#include
#include
//方便修改雷盘大小
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//声明初始化雷盘函数
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret);
//声明打印雷盘函数
void PrintBoard(char board[ROWS][COLS], int row, int col);
//声明布置雷函数
void setmine(char board[ROWS][COLS], int row, int col, int num);
//声明排查雷的函数
void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row,int col,int num);
test.c
#include "game.h"
void menu()
{
printf("*************---------------***************\n");
printf("******--------- ---------*******\n");
printf("******--------- 1.玩游戏 ---------*******\n");
printf("\n");
printf("******--------- 0.退出游戏 --------********\n");
printf("******--------- ---------*******\n");
printf("*************---------------***************\n");
}
void game()
{
//创建雷盘
char Secret[ROWS][COLS] = { 0 }; //秘密雷盘
char Show[ROWS][COLS] = { 0 };//展示的雷盘
//初始化雷盘
InitBoard(Secret, ROWS, COLS,'0'); //初始化的答案雷盘
InitBoard(Show, ROWS, COLS, '*'); //初始化的玩家雷盘
//打印雷盘
PrintBoard(Show, ROW, COL); //打印给玩家看的雷盘
//布置雷
int num = ModeSelection(); //模式选择函数,返回雷的数量
setmine(Secret, ROW, COL, num); //布置雷函数
//排查雷
findmine(Secret, Show, ROW, COL, num);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 0:
system("cls");
system("pause");
printf("欢迎您的下一次体验,再见!\n");
break;
case 1:
game();
break;
default:
printf("输入错误,请重新选择\n");
break;
}
} while (input);
}
game.c
#include "game.h"
//初始化雷盘函数的定义
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)
{
memset(board, ret, sizeof(board[0][0]) * rows * cols);
}
//打印雷盘函数的定义
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
printf("------------------------扫雷游戏-------------------\n");
int i = 0, j = 0;
printf(" ");
for (i = 1; i <= row; i++)
{
printf("%3d ", i);
}
printf("\n");
printf(" +");
for (i = 0; i < row; i++)
{
printf("---+");
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%2d", i);
printf("|");
for (j = 1; j <= col; j++)
{
printf(" %c |", board[i][j]);
}
printf("\n");
printf(" +");
for (j = 0; j < col; j++)
{
printf("---+");
}
printf("\n");
}
printf("------------------------扫雷游戏-------------------\n");
}
//模式选择函数的定义(返回设置雷的个数)
int ModeSelection()
{
int num = 0;
again: //玩家选择模式错误时返回到这里
printf("欢迎玩家来到扫雷游戏\n");
printf("\n请选择扫雷难度: (num的代表雷的数量)\n");
printf("A.轻松模式:num=5 B.皱眉头模式:num=15 C.出汗模式:num=30 D.DIY难度(玩家自行输入雷的个数)\n ");
char pattern = 0;
getchar();//清空缓存区
scanf("%c", &pattern);
switch (pattern)
{
case 'A':
case 'a':
printf("轻松模式:num=5\n");
num = 5;
return num;
break;
case 'B':
case 'b':
printf("皱眉头模式:num=15\n");
num = 15;
return num;
break;
case 'C':
case 'c':
printf("出汗模式:num=30\n");
num = 30;
return num;
break;
case 'D':
case 'd':
printf("DIY模式:\n");
printf("请输入想要布置雷的个数:\n");
getchar();//清楚缓存区
int intput = 0;
scanf("%d", &intput);//用户自定义的雷的个数
num = intput;
return num;
break;
default:
printf("\n******不好意思,皮蛋还没有此功能按键,请重新选择:******\n\n");
goto again;
break;
}
}
//定义布置雷函数
void setmine(char board[ROWS][COLS], int row, int col, int num)
{
//随机布雷
int x = 0;
int y = 0;
for (int i = 0; i < num; )
{
x = rand() % row + 1; //x产生[1,row]之间的坐标
y = rand() % col + 1; //y产生[1,col]之间的坐标
if (board[x][y] == '0')
{
board[x][y] = '1';
i++;
}
}
}
//统计坐标周围雷的数量
int countmine(char secret[ROWS][COLS], int x, int y)
{
int ret = secret[x - 1][y - 1] + secret[x - 1][y] + secret[x - 1][y + 1]
+ secret[x][y - 1] + secret[x][y + 1]
+ secret[x + 1][y - 1] + secret[x + 1][y] + secret[x + 1][y + 1] - 8 * '0';
return ret;
}
//自动排雷函数定义
Recursive(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
int count = countmine(secret, x, y);//计算该坐标周围有几个雷
if (count == 0)
{
show[x][y] = ' ';//周围没有雷的坐标变为空格
int i = 0, j = 0;
for (i = x - 1; i <= x + 1; i++)//观察周围八个坐标
{
for (j = y - 1; j <= y + 1; j++)
{
if (show[i][j] == '*' && (i != x || j != y))//防止重新递归show[x][y]坐标
{
Recursive(secret, show, ROW, COL, i, j);
}
}
}
}
else
{
show[x][y] = count + '0';
}
}
}
//计算已经被排查的位置
int is_win(char show[ROWS][COLS], int row, int col)
{
int count1 = 0;//已经被排查的坐标个数
int i = 0, j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (show[i][j] != '*')//只要不是*,表示该坐标已经被排查了.
{
count1++;
}
}
}
return count1;
}
//定义排查雷的函数
void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int num)
{
int x = 0;
int y = 0;
int win = 0; //被排查的个数
while ((row * col - num) > win)
{
printf("请输入排雷坐标(格式:行号 列号)\n");
scanf("%d%d", &x, &y);
if (show[x][y] != '*')
{
printf("该坐标已经被排查过了 请重新输入:\n");
continue;
}
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (secret[x][y] == '1')//如果是1就代表是雷,游戏结束
{
printf("很遗憾,你失败了\n");
printf("请看答案:\n");
PrintBoard(secret, ROW, COL);//失败后,给玩家看答案雷盘
break;
}
else
{
Recursive(secret, show, ROW, COL, x, y); //自动递归排雷函数
win = is_win(show, ROW, COL); //计算已经被排查的位置
PrintBoard(show, ROW, COL);//打印给玩家的雷盘
}
}
else
{
printf("坐标非法,请重新输入:\n");
}
}
if (win == (row * col - num))
{
printf("恭喜你排雷成功\n");
}
}