1.涉及知识
数组,函数(除递归),分支与循环
2.功能
I.可实现的功能
1.输入坐标可判断该坐标是否有雷,以及周围雷的个数
2.仅是简单难度版扫雷(格子9*9, 10雷)
II.无法实现的功能
1.选择难度(仅做出菜单,未实现功能)
2.选择计时器功能(仅做出菜单,未实现功能)
3.输入坐标后若周围没雷会自动向周围散开,直至出现周围有雷的区域。
3.实现扫雷游戏(简单难度)的思路
I.基本逻辑
1.9行9列的格子,每个格子要么是雷,要么不是雷。
2.失败条件:点到雷;胜利条件:不踩雷的情况下点开剩下的71个格子。
3.点到一个非雷的格子,要能够显示周围有多少颗雷。
II.逻辑实现
基本逻辑1:9行9列的格子可以用二维数组实现。对于每个格子,要么是雷,要么不是雷,是不是雷对于游戏很关键,所以可以在创建二维数组的时候,给雷与非雷不同的字符。
基本逻辑2:对于失败条件,需要在游戏过程中使用一个函数:这个函数的功能是通过判断数组的字符,来检测玩家输入的坐标格子是不是雷,是雷就触发失败相应的内容,不是雷就继续;对于胜利条件,我们需要用一个step变量来储存玩家操作次数,如果step=71且最后一次没踩雷,则触发胜利相应的内容。
基本逻辑3:当检测玩家输入的坐标格子为非雷后,还需要一个函数:这个函数的功能是检测周围雷的个数,并且返回相应的数量给到坐标格子显示。
4.逐步实现思路
I.菜单制作
为方便后续添加更多功能,此处菜单将无法实现的功能提前加上了,下面为方便讲解,提前放出主函数文件的所有代码,接下来会一 一讲解:
菜单制作环节,运用了分支与循环的逻辑。让玩家玩完后仍可以继续,故需要用循环时刻检测玩家的状态。这个地方还需要注意玩家可能会输入其它数字,所以要做个default分支来反馈不合法输入。
//主函数文件
#include "game.h"
#include "option.h"
void menu() //菜单页面
{
printf("---------------------\n");
printf("--------1.play-------\n");
printf("-------2.option------\n");
printf("--------0.quit--------\n");
printf("----------------------\n");
}
void game() //游戏运行函数
{
//初始化
char real[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
init(real,ROWS,COLS,'0');
init(show,ROWS,COLS,'*');
//打印
print(show, ROW, COL);
//生成雷
MineMaker(real,ROW,COL);
//排雷
MineFinder(real, show, ROWS, COLS);
}
int main()
{
srand((unsigned int)time(NULL)); //后续生成雷需要使用随机数,此处先初始化种子
int start = 0;
printf("欢迎来到\"扫雷\"游戏!\n");
do
{
menu();
printf("请输入数字:");
scanf("%d", &start);
system("cls"); //输入数字后清屏,用来优化游戏体验
switch (start)
{
case 1:
{
game();
break;
}
case 2:
{
option();
break;
}
case 0:
{
printf("退出游戏\n");
break;
}
default:
{
printf("输入不合法,请重新输入\n");
break;
}
}
} while (start);
return 0;
}
II.游戏运行逻辑
1.实现"逻辑实现一"
创建所谓“格子”的二维数组,但需要注意的是,在一开始我们需要向玩家展示的应该是没有差别的未知格子" * ",而我们对于每个格子都要有“雷”与“非雷”两个标签,这其中的差异需要我们创建两个数组:一个叫real意味实际的“格子”,用于我们判断与检测雷;一个叫show意味展示给玩家的“格子”,用于给玩家展示。
PS:在检测雷的时候,我们需要对格子四周进行检测,如果只创建9*9的二维数组会越界报错,所以此处应创建11*11的二维数组,给玩家展示的时候仅需要打印show中间9*9的数组元素。
下面先进行数组的初始化:
#define EasyMine 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void init(char arr[ROWS][COLS], int r, int c, char set)
{
for (int i = 0;i < r;i++)
{
for (int j = 0;j < c;j++)
{
arr[i][j] = set;
}
}
}
//创建数组
char real[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化数组
init(real,ROWS,COLS,'0'); //字符'0'代表非雷,先统一生成'0',后用随机数生成雷
init(show,ROWS,COLS,'*');
初始化完后,需要向玩家展示界面:
#define EasyMine 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void print(char arr[ROWS][COLS], int r, int c)
{
for (int i = 0;i <= r;i++)
{
printf("%d ", i);
}
printf("\n");
for (int i = 1;i <= r;i++)
{
printf("%d ", i);
for (int j = 1;j <= c;j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
print(show, ROW, COL);
下面来随机生成雷:
#define EasyMine 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//生成雷
void MineMaker(char arr[ROW][COL], int r, int c)
{
int count = EasyMine;
while (count)
{
int x = rand() % r + 1;
int y = rand() % c + 1;
if (arr[x][y] != '1')
{
arr[x][y] = '1';
count--;
}
}
}
MineMaker(real,ROW,COL); //生成的雷应该在9*9范围内,故传的两个参数都为9
2.实现“逻辑实现2”
#define EasyMine 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void MineFinder(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int r, int c)
{
int step = 0;
while (step <= ROW * COL - 10)
{
int output = 0;
int input_x = 0;
int input_y = 0;
printf("请输入坐标:");
int num = scanf("%d%d", &input_x, &input_y);
if (num != 2) { // 未成功读取两个整数
printf("输入不合法,请重新输入\n");
// 清空缓冲区直到换行符
while (getchar() != '\n');
continue; // 跳过本次循环后续操作
}
if (input_x >= 1 && input_x <= ROW && input_y >= 1 && input_y <= COL)
{
switch (arr1[input_x][input_y] - 48)
{
case 1:
{
printf("你被炸死了\n\n");
print(arr1, ROW, COL);
printf("\n即将返回到主菜单");
Sleep(7000);
system("cls");
return;
}
case 0:
{
check_mine(arr1[ROWS][COLS], arr2[ROWS][COLS], input_x, input_y, step);
}
}
}
else
{
printf("输入不合法,请重新输入\n");
Sleep(1000);
}
system("cls");
print(arr2, ROW, COL);
}
printf("恭喜你扫雷成功!\n");
print(arr1, ROW, COL);
}
MineFinder(real, show, ROWS, COLS);
这段代码较为复杂,下面进行讲解:
1.需要统计step来判断是否胜利,故创建个step变量,并且找雷动作需要在游戏过程中反复执行,故需要step<=71作为while循环条件
2.游戏过程中,玩家需要输入坐标来排雷,故需要接收接受玩家输入的坐标,此处用input_x与input_y接收。为防止用户乱输入字符存入缓存区,scanf无法读取导致死循环,需要引入num在每次输入后检测输入的是否为数字,若不是则清除缓存重新输入。
3.为防止玩家输入的数字超过9*9范围引发越界等问题,也需要检查玩家输入的数字是否合法,合法则进行相应判断,不合法也得重新输入。
4.用户输入合法后,我们需要判断是不是雷。由于初始化时用的是字符'0'与'1',此处switch判断需要减去'0'的ASCII码48。是雷就触发相应的失败内容,不是雷就对检测周围的雷数。
5.若玩家71步下来均未踩雷,则触发相应胜利内容。
3.实现"逻辑实现3"
#define EasyMine 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void check_mine(char arr1[ROWS][COLS],char arr2[ROWS][COLS],int x,int y,int step)
{
int output = 0;
//检测周围八个格子
for (int i = -1;i <= 1;i++)
{
for (int j = -1;j <= 1;j++)
output += arr1[x + i][y + j];
}
output -= 432; //如果周围都不是雷,则9个'0'的ASCII码和为432
arr2[x][y] = output + '0';
step++;
}
5.分文件管理
将“play”相应的代码放到game.c中,将"option"相应的代码放到option.c中,另加相应头文件声明。用到的库函数头文件如下:
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>
6.源代码分享
附上我gitee上的源代码: 7.31 · whitedoor/作业 - 码云 - 开源中国

1万+

被折叠的 条评论
为什么被折叠?



