版权声明:Zhining https://blog.csdn.net/weixin_43214609/article/details/83349979
要实现的结果:
- 实现扫雷游戏的基本功能
- 能够展开一片无雷区域
- 能够在输入的坐标显示附近八邻域的雷数
- 不要让玩家走第一步就被"炸死"
实现的思路及代码:
1.想清楚这个游戏应该分为几个板块,什么函数并实现什么功能,函数应放在那个板块等等,然后再一点点填充函数定义。
这个游戏我计划用两个源文件test.c和game.c,头文件game.h。
- test.c实现的功能是接收玩家选项、实现游戏整体的流程。
- game.c实现的是扫雷游戏,分为棋盘的初始化、棋盘的输出、布雷、接受玩家输入坐标、返回附近雷数等函数块。
- game.h实现的是宏常量的定义、头文件定义、函数声明等,可以作为game.c文件的"目录"。.c文件只用调用game.h即可,省去了重复的头文件调用。
2.菜单选项
- 不管什么游戏,第一个要创建的一定是菜单,用来接收玩家的选项,这里设置输入1代表玩游戏,0代表退出。在test.c中实现并测试整个流程,避免出现复杂的问题。
#include"game.h"
int main()
{
do
{
int input = 1;
printf("##############################\n");
printf("######### 1. play ########\n");
printf("######### 0. exit ########\n");
printf("##############################\n");
printf("请选择:>\n");
scanf("%d", &input);
system("cls");
switch (input)
{
case 1:
game();
break;
case 0:
printf("<游戏已退出!>\n");
break;
default:
printf("选择错误,请重新输入:>\n");
break;
}
}while(1);
system("pause");
return 0;
}
3.现在来填充game.h文件,按照游戏预期效果来设置,
- 创建棋盘->玩家走第一步->设置随机分布的雷->打印棋盘并在棋盘上输出附近雷数展开安全区->玩家走->判断是否可走->再打印…->①玩家踩雷->游戏结束->输出雷的分布棋盘; ②棋盘满但没有被"炸死"->玩家扫雷成功->输出雷的分布棋盘;
这是我的大致思路,先走第一步是为了不让玩家第一步被"炸死";接下来再game.h中实现声明。
#ifndef __GAME_H__
#define __GAME__H__
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#define ROW 12
#define COL 12
#define COUNT 10//雷数
extern char show[ROW][COL];//展示数组
extern char mine[ROW][COL];//布雷数组
void player(char mine[ROW][COL], int row, int col, int x, int y);
//玩家走
void init(char show[ROW][COL], char mine[ROW][COL], int row, int col);
//初始化数组函数
void set_min( char mine[ROW][COL], int row, int col);
//随机布雷
int count_mine(char show[ROW][COL], char mine[ROW][COL], int row, int col);
//统计周围雷的个数
void print_player(char show[ROW][COL], char mine[ROW][COL], int row, int col);
//打印玩家棋盘
void print_mine( char mine[ROW][COL], int row, int col);
//打印有雷棋盘
int game();
//扫雷函数
void open_mine(int x, int y);
//展开函数
int count_show_mine(char show[ROW][COL], char mine[ROW][COL],int row,int col);
//判断玩家棋盘剩余未知区域的个数
#endif
3.接下来逐个填充函数
- 首先从game()开始,将每个函数分配在游戏过程中。
int game()
{
srand((unsigned int)time(0));
char show[ROW][COL] = { 0 };
char mine[ROW][COL] = { 0 };
int x = 0, y = 0;
int row = ROW, col = COL;
init_board(show[ROW][COL], mine[ROW][COL], row, col);//初始化雷阵
print_player(show[ROW][COL], mine[ROW][COL], row, col);
printf("请输入坐标:>");
scanf("%d %d", &x, &y);
show[x][y] = 0;//第一步不会炸死
print_player(show[ROW][COL], mine[ROW][COL], row, col);//输出棋盘
set_min(mine[ROW][COL], row, col);//放雷
int ret = player(show[ROW][COL], row, col);//玩家走并判断
if (ret )
{
printf("很遗憾,你被'炸死'了\n");
}
else
{
player(show[ROW][COL], row, col);
}
return 1;
}
- 初始化两个数组
void init(char show[ROW][COL], char mine[ROW][COL], int row, int col)//初始化两个雷阵
{
int i = 0;
int j = 0;
for (int i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
show[i][j] = '*';
mine[i][j] = '0';
}
}
}
- 输出布雷棋盘和玩家可视棋盘
void print_player(char show[ROW][COL], char mine[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i <row - 1; i++)
{
printf("%d ", i);//打印横标(0--10)
}
printf("\n");
for (i = 1; i <row - 2; i++)//打印竖标(1--10)
{
printf("%d ", i);
for (j = 1; j < col - 1; j++)
{
printf("%c ", show[i][j]);//玩家棋盘数组
}
printf("\n");
}
printf("10 ");//开始打印最后一行
for (i = 1; i < row - 1; i++)
{
printf("%c ", show[10][i]);
}
printf("\n");
}
void print_mine(char mine[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i <row - 1; i++)
{
printf("%d ", i);//打印横标(0--10)
}
printf("\n");
for (i = 1; i <row - 2; i++)//打印竖标(1--10)
{
printf("%d ", i);
for (j = 1; j < col - 1; j++)
{
printf("%c ", mine[i][j]);
}
printf("\n");
}
printf("10 ");//开始打印最后一行
for (i = 1; i < row - 1; i++)
{
printf("%c ", mine[10][i]);
}
printf("\n");
}
- 玩家输入坐标
int player(char show[ROW][COL],int row, int col)
{
int x = 0, y = 0;
printf("请输入坐标:>");
scanf("%d %d", &x, &y);
while (1)
{
if ((x >= 1 && x <= 10) && (y >= 1 && y <= 10))//判断输入坐标是否有误
{
if (mine[x][y] == '0')//没踩到雷
{
char ch = count_mine(x, y);
show[x][y] = ch + '0';//数字对应的ASCII值和数字字符对应的ASCII值相差48,即'0'的ASCII值
open_mine(show[ROW][COL], mine[ROW][COL], row, col, x, y);//展开
print_player(show[ROW][COL], row, col);
if (count_show_mine(show[ROW][COL], mine[ROW][COL], row, col) == COUNT)//判断剩余未知区域的个数,个数为雷数时玩家赢
{
print_mine( mine[ROW][COL], row, col);
printf("玩家赢!>\n");
break;
}
}
else if (mine[x][y] == '1')//踩到雷
{
return 1;
}
}
else
{
printf("输入错误重新输入\n");
}
return 0;//没踩到雷
}
}
- 布雷并展开
void set_min(char mine[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
int count = COUNT;//雷总数
while (count)//雷布完后跳出循环
{
int x = rand() % 10 + 1;//产生1到10的随机数
int y = rand() % 10 + 1;
if (mine[x][y] == '0')//找不是雷的地方布雷
{
mine[x][y] = '1';
count--;
}
}
}
void open_mine(char mine[ROW][COL], int row, int col,int x, int y)//坐标周围展开函数
{
if (mine[x - 1][y - 1] == '0')
{
show[x - 1][y - 1] = count_mine(x - 1, y - 1) + '0';//显示该坐标周围雷数
}
if (mine[x - 1][y] == '0')
{
show[x - 1][y] = count_mine(x - 1, y) + '0';//显示该坐标周围雷数
}
if (mine[x - 1][y + 1] == '0')
{
show[x - 1][y + 1] = count_mine(x - 1, y + 1) + '0';//显示该坐标周围雷数
}
if (mine[x][y - 1] == '0')
{
show[x][y - 1] = count_mine(x, y - 1) + '0';//显示该坐标周围雷数
}
if (mine[x][y + 1] == '0')
{
show[x][y + 1] = count_mine(x, y + 1) + '0';//显示该坐标周围雷数
}
if (mine[x + 1][y - 1] == '0')
{
show[x + 1][y - 1] = count_mine(x + 1, y - 1) + '0';//显示该坐标周围雷数
}
if (mine[x + 1][y] == '0')
{
show[x + 1][y] = count_mine(x + 1, y) + '0';//显示该坐标周围雷数
}
if (mine[x + 1][y + 1] == '0')
{
show[x + 1][y + 1] = count_mine(x + 1, y + 1) + '0';//显示该坐标周围雷数
}
}
- 判断周围8邻域的雷个数
int count_show_mine(char mine[ROW][COL], int row, int col)
//判断剩余未知区域的个数,个数为雷数时玩家赢
{
int count = 0;
int i = 0;
int j = 0;
for (i = 1; i <= row - 2; i++)
{
for (j = 1; j <= col - 2; j++)
{
if (show[i][j] == '*')
{
count++;
}
}
}
return count;
}
结论:
- 扫雷游戏就是创建两个棋盘。
- 在玩家输入第一个坐标后,在玩家可见棋盘上返回那个位置的附近雷数为0。
- 在玩家不可见的棋盘里随机生成雷。
- 重复性的输入坐标、判断坐标有效性、判断是否踩雷、判断是否赢得游戏。
- 展开附近坐标的周围雷数。
- 重复上步。