赞
踩
START
我们平时玩的扫雷小游戏,可以通过C语言简易实现,当然,设计这个小游戏,需要具备严谨的逻辑,一步接一步的思维引领。
首先,扫雷这个小程序,我们分析游戏规则得知:当我们排查雷的时候,如果所排查位置是雷的话,那我们就被炸死了;如果所排查处不是雷,为了降低游戏难度,我们可以显示所排查之处周围有多少个雷。
由于扫雷代码偏长,为了使程序员编写条理井然有序,并可以多人进行对一个项目的编写,后续维修、检查Bug方便,因此分装成多个文件处理:main.c (扫雷小程序的主体框架)、game.c(扫雷游戏功能的实现)、game.h(扫雷游戏功能中自定义函数的声明)。
扫雷小程序面向用户,美观且通俗易懂的菜单当然是必不可少的,由于菜单并不是很复杂,我们将菜单(menu)函数放在主函数中也是可以的。
- void menu()
- {
- printf(" +---+---+---+---+---+---+---+---+---+\n");
- printf(" | <欢迎使用扫雷游戏> |\n");
- printf(" +---+---+---+---+---+---+---+---+---+\n");
- printf(" * * * * * * * * * * * * * * * * * * *\n");
- printf(" +---+---+---+---+---+---+---+---+---+\n");
- printf(" | 请选择你要执行的操作>> |\n");
- printf(" +---+---+---+---+---+---+---+---+---+\n");
- printf(" | 【1】开始游戏 |\n");
- printf(" +---+---+---+---+---+---+---+---+---+\n");
- printf(" | 【0】退出游戏 |\n");
- printf(" +---+---+---+---+---+---+---+---+---+\n");
- }
通过这个菜单,我们将“1"设置为 开始游戏,并将”0“作为退出游戏。
- int main()
- {
- int input = 0;
- srand((unsigned int)time(NULL));
- do
- {
- menu();
- printf("请选择 ->");
- scanf("%d", &input);
- printf("\n");
- switch (input)
- {
- case 1:
- game();
- break;
- case 0:
- printf("退出游戏");
- printf("\n");
- break;
- default:
- printf("选择错误,请重新选择");
- printf("\n");
- break;
- }
- return 0;
- } while (input);
- }

当我们选择”1“的时候,进入游戏主体,若当我们选择”0“的时候,将退出游戏,如果选择其他数时,将提示”选择错误,请重新选择。通过while循环,将我们输入的数字进行反馈。
首先,我们想,在一个扫雷的棋盘中,棋盘里的数据用什么存储是“雷”和“非雷”,很容易会想到:“1"表示是”雷“,”0“表示"非雷”,但是问题来了,如果我们想呈现所排查的坐标周围有多少个雷的时候,数字逻辑就相互矛盾了,但是我们可以创建两个数组分开进行操作。
- #define ROW 9
- #define COL 9
由于我们在排查时,发现当排查坐标在边缘角落时,有一些数据越界了,因此,我们将棋盘加个“边框”就能很好地解决这个问题。
- #define ROWS ROW+2
- #define COLS COL+2
通过宏定义ROW,COL方便后续进行修改
- char mine[ROWS][COLS];
- char show[ROWS][COLS];
定义mine数组为布置雷的数组,show数组为展示排查的数组
自定义Initboard为初始化函数,将mine和show两个数组中数据分别初始化为“0”、“*”。主函数调用Initboard函数时,传数组时,记得传的是数组名(即首元素地址)。
- Initboard(mine, ROWS, COLS, '0');
- Initboard(show, ROWS, COLS, '*');
自定义Displayboard函数进行数组的打印,同时,主函数调用Displayboard函数时,传数组时,记得传的是数组名(即首元素地址)。
Displayboard(show, ROW, COL);
自定义Setmine函数进行对mine数组布置雷的坐标,当然,主函数调用Setmine函数时,传数组时,记得传的是数组名(即首元素地址)。
Setmine(mine, ROW, COL);
自定义Findmine函数,将从mine数组中排查中的数据通过show数组展现出来,因此,在调用Findmine函数时,应该传入mine和show这两个数组。
Findmine(mine, show, ROW, COL);
< 接下来,在game.c中我们将我们上述的自定义函数逐个实现 >
在Initboard函数中,形参有一个字符数组用于接收初始化的数组,行(rows)、(cols)以及想要初始化成的数据,即通过for循环嵌套for循环>>
- void Initboard(char board[ROWS][COLS], int rows, int cols, char set)
- {
- for (int i = 0; i < rows; i++)
- {
- for (int j = 0; j < cols; j++)
- {
- board[i][j] = set;
- }
- }
- }
在Displayboard函数中,形参传入一个字符数组,所展示的棋盘不需要包括边框,因此形参传的是row和col。为了外观更美观,我们也可以通过for循环将行、列号打印出来>>
- void Displayboard(char board[ROWS][COLS], int row, int col)
- {
- //呈现可以进行改善-美观!!!
- printf("<-------扫雷------>\n");
- for (int i = 0; i <= col; i++)
- {
- printf("%d ", i);
- }
- printf("\n");
- for (int i = 1; i <= row; i++)
- {
- printf("%d ", i);
- for (int j = 1; j <= row; j++)
- {
- printf("%c ", board[i][j]);
- }
- printf("\n");
- }
- }

同样,布置雷和展示雷一样,都不需要作用到边框,因此也是传row和col参数,现在,我们要布置雷的个数为NUMBER_MINE ,但是我们确保每次布置雷的位置都是随机的,这里我们需要使用随机种子数(rand),使用随机种子数,我们需要在game.h文件中定义#include<stdlib.h>、#include<time.h>这两个头文件,并且在main.c主体中添加srand((unsigned int)time(NULL));为了确保我们布置的雷满足我们设定的量,当我们布置一个雷的时候,可以做一个标记,即:count--
下面是代码展示>>
- #include<stdlib.h>
- #include<time.h>
srand((unsigned int)time(NULL));
- void Setmine(char board[ROWS][COLS], int row, int col)
- {
- int count = NUMBER_MINE;
- while (count)
- {
- int x = rand() % row + 1;
- int y = rand() % col + 1;
- if (board[x][y] == '0')
- {
- board[x][y] = '1';
- count--;
- }
- }
- }
Tips: int x = rand() % row + 1; 即x的范围属于1~row
首先,调用mine数组,排查所输入的坐标是否是雷;(1)当踩中雷的时候,游戏结束,并展示雷的坐标(Displayboard(mine, ROW, COL); (2) 当没有踩中时,我们可以再自定义一个Getminecount函数将该点周围8个坐标的雷统计出来并打印出来;(3)为确保游戏严谨性,我们还可以将输入不合法的形式进行提示-重新输入。(4)为了游戏顺利结束,我们可以将循环条件设置成输入次数小于row*col-布置的雷数>>
- void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
- {
- int x = 0;
- int y = 0;
- int number = 0;
- while (number < row * col - NUMBER_MINE)
- {
- printf("请输入你要排查的坐标:例如:3 6\n");
- printf("\n");
- scanf("%d %d", &x, &y);
- //排查雷的时候,有合理与不合理之分
- //合理>
- if (x >=1 && x <= row && y >=1 && y <= col)
- {
- //当你踩中雷时
- if (mine[x][y] == '1')
- {
- printf("\a");
- printf("很遗憾,你被炸死了\n");
- Displayboard(mine, ROW, COL);
- break;
- }
- //当你踩的不是雷时
- else
- {
- int ret = Getminecount(mine, x, y);
- show[x][y] = ret + '0';
- Displayboard(show, ROW, COL);
- printf("加油,请继续排查!\n");
- printf("\n");
- printf("\a");
- number++;
- }
- }
- //当输入x,y不满足时,进行重新输入
- else
- {
- printf("输入非法,请重新输入\n");
- printf("\a");
- }
- }
- if (number == row * col - NUMBER_MINE)
- {
- printf("恭喜你,排雷成功!\n");
- printf("\a");
- Displayboard(mine, ROW, COL);
- }
- }
-

该函数设置有返回值,由于“0”的Ascall码是48,“2”的Ascall码是50.因此,两字符相减,所得之值即数字2 ,将周围8个数的Ascall码相减,所得之值便是所求值。
- int Getminecount(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');
- }
将game.c中的函数声明,并包含一些头文件
- #pragma once
-
- #include<stdio.h>
- #include<stdlib.h>
- #include<time.h>
-
- //通过#define 定义行数,列数,方便后续快速修改
- #define ROW 9
- #define COL 9
-
- #define ROWS ROW+2
- #define COLS COL+2
-
- //定义雷的个数
- #define NUMBER_MINE 10
-
- //将数组进行初始化
- void Initboard(char board[ROWS][COLS], int rows, int cols, int set);
-
- //打印展示需要呈现的数组
- void Displayboard(char board[ROWS][COLS],int row, int col);
-
- //通过随机种子数随机布置雷
- void Setmine(char board[ROWS][COLS], int row, int col);
-
- //在mine数组中检测是否是雷,并在show数组中显示详情
- void Findmine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col);
-
- //计算周围雷的个数
- int Getminecount(char mine[ROWS][COLS], int x, int y);

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。