赞
踩
目录
2.2 若输入的排查点(x,y)周围8个区域均不是雷,则周围8个区域都进行排查,并显示周边雷的数量
在我之前的博客【C语言】扫雷游戏_【Shine】光芒的博客-CSDN博客DN博客中 详细介绍了如何通过C语言代码实现简单的扫雷游戏。并根据网页版扫雷游戏的界面,在基础版扫雷游戏的基础上提出了两点改进优化措施:
本文在之前博客代码的基础之上,对代码进行改进优化,以实现贴合网页版的扫雷游戏。
根据上述两个优化方案,可以推断,我们只需要对扫雷函数FindMine进行优化即可,因为统计一个坐标周围有几个雷是在FindMine函数中调用统计雷个数函数CountMineNum来实现的、加入标记功能也应加到扫雷函数中去。
如图2.1所示为网页版扫雷游戏提供的标记功能,如果玩家认为某个点是雷,则在这个点上插小红旗,以防止玩家踩雷。
为了用C语言实现标记功能,我在FindMine函数中加入字符变量mark来确实是进行标记还是要翻开雷区。这段代码中,我设计如果mark == 'm' 则表示玩家要进行标记操作,mark是其余任何字符均代表玩家想翻开雷区进行排查。
当玩家确定要进行标记操作和输入标记坐标后,如果玩家输入的坐标通过了合法性检验,给显示数组show对应的(x,y)处赋值为'm'。
优化后的扫雷函数FindMine的代码:
- void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col)
- {
- int count_find = 0; //统计排了几个雷
- int x = 0;
- int y = 0;
- char mark = '0';
- while (1)
- {
- printf("请选择你要进行标记还是排雷(m是标记,其余均是排雷): > ");
- mark = getchar();
- getchar(); //清理缓冲区中的'\n'
- printf("请选择你要排查的坐标: > ");
- scanf("%d %d", &x, &y);
- getchar(); // 清理缓冲区
- //检查排查坐标的合法性
- if (x < 1 || x > row || y < 1 || y > col) //坐标超出范围
- {
- printf("你输入的坐标超出范围!\n");
- }
- else //坐标在范围内(未越界)
- {
- //判断该坐标位置是否已经被排查
- if (show[x][y] == '*' || show[x][y] == 'm') //还未被排查
- {
- if (mark == 'm') //输入排查标识m
- {
- show[x][y] = 'm'; //对应显示数组show的(x,y)坐标处改写为m
- DisplayBoard(show, ROW, COL); //数组打印函数
- }
- else
- {
- if (mine[x][y] == '1') //踩雷
- {
- printf("很遗憾,你被炸死了!\n");
- DisplayBoard(mine, ROW, COL); //打印雷区数组
- break;
- }
- else
- {
- ShowMine(mine, show, x, y, ROW, COL, &count_find);
- DisplayBoard(show, ROW, COL); //数组打印函数
- }
- }
- }
- else //输入的坐标已经被排查
- {
- printf("该坐标位置已经被排查!\n");
- }
- }
- if (count_find == ROW * COL - CountMine) //判断是否完成排雷
- {
- printf("恭喜你,完成排雷任务!\n");
- break;
- }
- }
- }
STEP1: 如图2.2所示,按下CTRL+F5运行代码,输入1,开始游戏,系统提示玩家选择是标记还是排雷。
STEP2: 输入m,选择进行标记,在输入排查坐标,这里以(2,5)为例,编译器打印出标记后的显示数组show,可以看到show[2][5]='m',表示此处已被标记。
STEP3:观察完成一次标记后能否顺利进行下一次标记或扫雷操作。 如图2.4所示,标记完一次后,既不影响下一次标记操作,也不影响接下来的扫雷操作。
经检验,程序可以顺利对雷区进行标记,且不影响下面的操作,标记优化程序合理可行。
在网页版扫雷游戏上,对某个点进行排查,若这个点周围没有雷,则展开一片区域。如图2.5所示,一个点周围没有雷则对它周围所有点进行排查,直到所有点周围均至少有一个雷为止。
实现这一优化的最基本思想是递归调用函数。这里,相对于初级版扫雷游戏代码,我引入了一个新的函数:ShowMine(扫雷显示函数)。在ShowMine函数包括7个输入参数,其意义分别为:
在ShowMine中,首先调用雷个数统计函数CountMineNum,统计坐标(x,y)周围有多少个雷,并将CountMine函数的返回值赋给变量n。
如果,这表示排查坐标(x,y)的周围有雷,直接将(x,y)周围雷的个数赋给显示数组show对应的位置,函数调用结束。
如果,表示(x,y)周围没有雷,那么,这里就要涉及到递归调用。首先判断坐标(x,y)周围的点是否在雷区范围内,又是否已经被排查过。如果周围的点既没有超出雷区,又没有被排查,则以这个点的坐标来替代x和y,递归调用函数ShowMine,指到直到所有点周围均至少有一个雷为止。
此外,ShowMine函数还有一个指针参数count,这个参数是用来统计总共有多少个点被排查过了,当所有不是雷的坐标军被排查,则扫雷成功。
ShowMine函数的代码演示:
- #include "game.h"
-
- void ShowMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int row, int col, int* count)
- {
- int n = CountMineNum(mine, x, y); //统计(x,y)周围有几个雷
- if (n == 0)
- {
- show[x][y] = '0'; //将显示数组show对应位置的元素置0
- int i = 0;
- int j = 0;
- //外循环为行,内循环为列,遍历(x,y)周围的8个坐标
- for (i = x - 1; i <= x + 1; i++)
- {
- for (j = y - 1; j <= y + 1; j++)
- {
- //if判断(x,y)周围点坐标(i,j)是否超出雷区范围,是否已经被排查
- //若既没超出雷区范围,也没有被排查,则进行递归调用操作
- if ((i >= 1 && j <= row && i >= 1 && j <= col) && (show[i][j] == '*' || show[i][j] == 'm'))
- {
- (*count)++; //被排查的点 +1
- ShowMine(mine, show, i, j, ROW, COL, count); //递归调用
- }
- }
- }
- }
- else
- {
- (*count)++; //被排查的次数+1
- show[x][y] = n + '0';
- }
- }
STEP1:开始运行代码,系统提示选择是否开始游戏,输入1,开始游戏。
STEP2:系统提示玩家选择进行标记还是排雷,输入f,表示选择排雷操作。之后输入排查坐标,这里以(4,8)为例,看到显示数组可以顺利展开一片。
STEP3:检查是否影响后面的操作。后续扫雷操作顺利进行,优化代码正确代码。
在优化版扫雷项目中,包含一个头文件和8个源文件。
一个头文件:
- game.h 进行函数的声明、头文件的包含、宏的定义
八个源文件:
- test.c 检测文件,选择是否开始游戏,是否结束游戏,是否继续进行游戏
- game.c 游戏大逻辑文件
- InitialBoard.c 初始化数组函数文件
- SetMine.c 布雷函数文件
- DisplayBoard.c 打印数组文件
- FindMine.c 扫雷函数文件
- ShowMine.c 排雷过程显示函数文件
- CountMineNum.c 统计雷个数函数
- #define _CRT_SECURE_NO_WARNINGS 1
- //头文件的包含
- #include<stdio.h>
- #include<stdlib.h>
- #include<time.h>
-
- //宏的定义
- #define ROW 9
- #define COL 9
-
- #define ROWS 11
- #define COLS 11
-
- #define CountMine 10
-
- //函数声明
- void game();
- void InitialBoard(char board[ROWS][COLS], int row, int col, char set);
- void SetMine(char board[ROWS][COLS], int row, int col);
- void DisplayBoard(char board[ROWS][COLS], int row, int col);
- void FindMine(char board[ROWS][COLS], char show[ROWS][COLS], int row, int col);
-
- int CountMineNum(char mine[ROWS][COLS], int x, int y);
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include "game.h"
-
- void menu()
- {
- printf("**************************\n");
- printf("******* 1.play *******\n");
- printf("******* 0.exit *******\n");
- printf("**************************\n");
- }
-
- int main()
- {
- int input = 0;
- srand((unsigned int)time(NULL));
- do
- {
- menu();
- printf("请选择是否开始游戏: > ");
- scanf("%d", &input);
- getchar(); //清理缓冲区
- switch (input)
- {
- case 1:
- printf("扫雷游戏开始!\n");
- game();
- break;
- case 0:
- printf("游戏结束!\n");
- break;
- default:
- printf("选择错误,请重新选择!\n");
- break;
- }
- } while (input);
- return 0;
- }
- #define _CRT_SECURE_NO_WARNINGS 1
- #include "game.h"
-
- void game()
- {
- char mine[ROWS][COLS]; //雷区数组
- char show[ROWS][COLS]; //显示数组
-
- //雷区数组,0表示安全区,1表示雷
- InitialBoard(mine, ROWS, COLS, '0'); //初始化雷区数组,全部赋初值为字符'0'
- InitialBoard(show, ROWS, COLS, '*'); //初始化显示数组,全部赋初值为字符'*'
- SetMine(mine, ROW, COL); //布雷函数
- DisplayBoard(show, ROW, COL); //调用函数打印显示数组
- FindMine(mine, show, ROW, COL); //扫雷函数
- }
- #define _CRT_SECURE_NO_WARNINGS 1
- #include "game.h"
-
- //初始化二维数组函数
- //board为待初始化的二维数组,row为数组行数,col为数组列数,set表示数组元素被初始化后是什么
- void InitialBoard(char board[ROWS][COLS], int row, int col, char set)
- {
- int i = 0;
- int j = 0;
- for (i = 0; i < ROWS; i++)
- {
- for (j = 0; j < COLS; j++)
- {
- board[i][j] = set;
- }
- }
- }
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include "game.h"
-
- void SetMine(char board[ROWS][COLS], int row, int col)
- {
- int count = 0; //统计布雷个数
- while (1)
- {
- int x = rand() % row + 1; //随机生成布雷点坐标
- int y = rand() % col + 1;
- if (board[x][y] == '0') //判断(x,y)坐标处是否已经布雷
- {
- board[x][y] = '1';
- count++; //布雷数+1
- }
- if (CountMine == count) //到了设定雷数后终止布雷操作
- {
- break;
- }
- }
- }
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include "game.h"
-
- void DisplayBoard(char board[ROWS][COLS], int row, int col)
- {
- int i = 0;
- int j = 0;
- //打印列号
- for (i = 0; i <= row; i++)
- {
- printf("%d ", i);
- }
- printf("\n"); //打印完列号后换行
- for (i = 1; i <= row; i++)
- {
- printf("%d ", i); //打印行号
- for (j = 1; j <= col; j++)
- {
- printf("%c ", board[i][j]);
- }
- printf("\n");
- }
- }
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include "game.h"
-
- void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col)
- {
- int count_find = 0; //统计排了几个雷
- int x = 0;
- int y = 0;
- char mark = '0';
- while (1)
- {
- printf("请选择你要进行标记还是排雷(m是标记,其余均是排雷): > ");
- mark = getchar();
- getchar(); //清理缓冲区中的'\n'
- printf("请选择你要排查的坐标: > ");
- scanf("%d %d", &x, &y);
- getchar(); // 清理缓冲区
- //检查排查坐标的合法性
- if (x < 1 || x > row || y < 1 || y > col) //坐标超出范围
- {
- printf("你输入的坐标超出范围!\n");
- }
- else //坐标在范围内(未越界)
- {
- //判断该坐标位置是否已经被排查
- if (show[x][y] == '*' || show[x][y] == 'm') //还未被排查
- {
- if (mark == 'm') //输入排查标识m
- {
- show[x][y] = 'm'; //对应显示数组show的(x,y)坐标处改写为m
- DisplayBoard(show, ROW, COL); //数组打印函数
- }
- else
- {
- if (mine[x][y] == '1') //踩雷
- {
- printf("很遗憾,你被炸死了!\n");
- DisplayBoard(mine, ROW, COL); //打印雷区数组
- break;
- }
- else
- {
- ShowMine(mine, show, x, y, ROW, COL, &count_find);
- DisplayBoard(show, ROW, COL); //数组打印函数
- }
- }
- }
- else //输入的坐标已经被排查
- {
- printf("该坐标位置已经被排查!\n");
- }
- }
- if (count_find == ROW * COL - CountMine) //判断是否完成排雷
- {
- printf("恭喜你,完成排雷任务!\n");
- break;
- }
- }
- }
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include "game.h"
-
- void ShowMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int row, int col, int* count)
- {
- int n = CountMineNum(mine, x, y); //统计(x,y)周围有几个雷
- if (n == 0)
- {
- show[x][y] = '0'; //将显示数组show对应位置的元素置0
- int i = 0;
- int j = 0;
- //外循环为行,内循环为列,遍历(x,y)周围的8个坐标
- for (i = x - 1; i <= x + 1; i++)
- {
- for (j = y - 1; j <= y + 1; j++)
- {
- //if判断(x,y)周围点坐标(i,j)是否超出雷区范围,是否已经被排查
- //若既没超出雷区范围,也没有被排查,则进行递归调用操作
- if ((i >= 1 && j <= row && i >= 1 && j <= col) && (show[i][j] == '*' || show[i][j] == 'm'))
- {
- (*count)++; //被排查的点 +1
- ShowMine(mine, show, i, j, ROW, COL, count); //递归调用
- }
- }
- }
- }
- else
- {
- (*count)++; //被排查的次数+1
- show[x][y] = n + '0';
- }
- }
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include "game.h"
-
- //统计坐标(x,y)周围有几个雷
- int CountMineNum(char mine[ROWS][COLS], int x, int y)
- {
- return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] + mine[x][y - 1] +
- mine[x][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0';
- }
全文结束,感谢大家的阅读,敬请批评指正
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。