扫雷开发
1.前期准备
1.1工具:VC,easyx
基础知识:循环,数组,函数
1.2雷区地图绘制
我们做一个9行9列的二维数组,0和-1代表有雷和无雷
这个数组最好是全局,这样很多函数都可以访问得到(注意全局数组自动初始化为0)
需要的头文件和宏定义如下:
#include<stdio.h>
#include<graphics.h>
#define ROW 9//9行9列的雷区表格
#define COL 9
#define MINE_WID 40//图片宽度
int mine[ROW][COL];
1.3打印 printMap()函数
先做点简单的工作,写一个输出数组的函数,方便后面调用
void printMap()
{
for(int i=0;i<ROW;i++)
{
for(int j=0;j<COL;j++)
{
printf("%3d",mine[i][j]); //格式控制一下,一个数字占3个
}
printf("\n");//每一行就输出一个换行
}
}
main()调用一下
int main()
{
printMap();
return 0;
}
资源文件有数字标记,空白格子,红旗,地图,以及地雷,复制进入工程的当前目录
图片定义一个数组,作为全局变量,这个数组可被各个函数访问修改
IMAGE img[12];
1.4初始化
void gameInit()
{
loadimage(&img[0],"./0.png",MINE_WID,MINE_WID);
loadimage(&img[1],"./1.png",MINE_WID,MINE_WID);
loadimage(&img[2],"./2.png",MINE_WID,MINE_WID);
loadimage(&img[3],"./3.png",MINE_WID,MINE_WID);
}
//上面的代码要复制12次,我们用循环处理简化代码
void gameInit()
{
char temp[20]=" ";
for(int i=0;i<12;i++)
{
sprintf(temp,"%d.jpg",i);//把路径+i吸入temp变量
loadimage(&img[i],temp,MINE_WID,MINE_WID);
}
}
资源加载完了,我们开始绘制图片(贴图)
void gameDraw()
{
for(int i=0;i<ROW;i++)
{
for(int j=0;j<COL;j++)
{
if(mine[i][j]==0) //初始化开始为0的时候,全部填充空白砖块
{
putimage(i*MINE_WID,j*MINE_WID,&img[0]);
}
}
}
}
现在主函数调用一下
int main()
{
initgraph(MINE_WID*ROW,MINE_WID*COL,1); //参数 1,是同时绘图与打开控制台
gameInit(); //资源初始化
gameDraw();//绘制
printMap();//控制台作为后台数据帮忙分析
system("pause");//记得 #include<stdlib>
return 0;
}
1.5开始布雷
雷的数量做一个宏定义,方便后期修改
#define MAX_MINE 9 //雷先少布置一点 方便分析
//在二维数组里面随机获取9个下标,赋值为-1
void gameInit()
{
//随机化给下标为x,y的赋值为-1,标记为雷区,并且要判断不要有 重合的下标
int x,y;
for(int m=0;m<MAX_MINE;)//注意m++的操作,不在这里
{
//srand((unsigned int)time(0));
//加上上一句srand函数,同时和#include<time.h>即为真随机,每次布雷不一样
x=rand()%9;
y=rand()%9;
//判断是否重复
if(mine[x][y]==0) //没有雷的情况下,就埋雷,有雷就没做了
{
mine[x][y]=-1;
//当布雷成功了,m才++
m++;//放在判断这里++,才会保证一定布满9个雷
}
}
char temp[20]=" ";
for(int i=0;i<12;i++)
{
sprintf(temp,"%d.jpg",i);//
loadimage(&img[i],temp,MINE_WID,MINE_WID);
}
}
布雷之后运行看一下
多次运行,发现真随机的雷区发生变化,由于我们在gameDraw()绘图函数里面只定义了当数值为0,没有雷的时候绘制空白砖块,所以当数值为-1的时候,需要绘制地雷
1.6绘制地雷
//根据后台数据,给出绘制雷区定义
//为-1布雷,增加 if else if分支,切忌还要有数字选项,所以不要只写else
void gameDraw()
{
for(int i=0;i<ROW;i++)
{
for(int j=0;j<COL;j++)
{
if(mine[i][j]==0) //初始化开始为0的时候,全部填充空白砖块
{
putimage(i*MINE_WID,j*MINE_WID,&img[0]);
}
else if(mine[i][j]==-1) //当为-1的时候布雷
{
putimage(i*MINE_WID,j*MINE_WID,&img[9]); //新增一个else分支即可,地雷是第9个图片
}
}
}
}
对比一下数据,行列是颠倒的,将绘图函数里面新增两个变量,对应起来
void gameDraw()
{
for(int i=0;i<ROW;i++)
{
for(int j=0;j<COL;j++)
{
int x=j*MINE_WID;
int y=i*MINE_WID;
if(mine[i][j]==0) //初始化开始为0的时候,全部填充空白砖块
{
putimage(x,y,&img[0]);
}
else
{
putimage(x,y,&img[9]);
}
}
}
}
1.7布雷的数字
现在雷区有了,那么一个数字代表周围有多少雷,那么有一个雷,周围数字全部+1
注意,数字进行累加,但是不要把自己也是雷区的数字-1也给变化了,在gameInit()里面进行更改
void gameInit()
{
//随机化给下标为x,y的赋值为-1,标记为雷区,并且要判断不要有 重合的下标
int x,y;
srand((unsigned int)time(0));
for(int m=0;m<MAX_MINE;)//注意m++的操作,不在这里
{
x=rand()%9;
y=rand()%9;
//判断是否重复
if(mine[x][y]==0) //没有雷的情况下,就埋雷,有雷就没做了
{
mine[x][y]=-1;
//当布雷成功了,m才++
m++;//放在判断这里++,才会保证一定布满9个雷
}
}
// 遍历数组,对雷九宫格进行+1操作
for(int a=0;a<ROW;a++) // VC6在cpp文件不能重复定义i,j。所以避开一下
{
for(int b=0;b<COL;b++)
{
//首先要找到是雷的i,j
if(mine[a][b]==-1) //再嵌套一个二层循环
{
for(int k=a-1;k<=a+1;k++)
{
for(int q=b-1;q<=b+1;q++)
{
//周围的遍历,只对非雷区进行操作
if(mine[k][q]!=-1)
{
mine[k][q]++;
}
}
}
}
}
}
char temp[20]=" ";
for(int i=0;i<12;i++)
{
sprintf(temp,"%d.jpg",i);//
loadimage(&img[i],temp,MINE_WID,MINE_WID);
}
}
尝试输出一下,程序可能会假死,可能不会,取决于编译器对数组上下限±1的严格程度。
问题出在哪里?思考一下!
1.8雷区在边界,-1,+1操作会越界,内存会溢出,访问不到!
小技巧:增加一个 ±1,作为辅助圈,在11*11格子里面的判断。
#include<stdio.h>
#include<gra