IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 扫雷开发C语言 -> 正文阅读

[C++知识库]扫雷开发C语言

扫雷开发

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-20210205180152573

资源文件有数字标记,空白格子,红旗,地图,以及地雷,复制进入工程的当前目录

图片定义一个数组,作为全局变量,这个数组可被各个函数访问修改

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;
}

image-20210207121625293

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);
        
    }
}

布雷之后运行看一下

image-20210209102851067

多次运行,发现真随机的雷区发生变化,由于我们在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个图片
			}
        }
    }
}

image-20210209103711589

对比一下数据,行列是颠倒的,将绘图函数里面新增两个变量,对应起来

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);
        
    }
}

image-20210209105554555

尝试输出一下,程序可能会假死,可能不会,取决于编译器对数组上下限±1的严格程度。

问题出在哪里?思考一下!

1.8雷区在边界,-1,+1操作会越界,内存会溢出,访问不到!

小技巧:增加一个 ±1,作为辅助圈,在11*11格子里面的判断。
#include<stdio.h>
#include<graphics.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9//9行9列的雷区表格
#define COL 9
#define MINE_WID 40
#define MAX_MINE 9
int mine[ROW+2][COL+2]; //辅助圈
IMAGE img[12];
那么,0行,10行与0列,11列成为辅助圈

判断的数字增加的行列从a=1,到小于row+1(b=1到b<COL+1)

for(int a=1;a<ROW+1;a++) // VC6在cpp文件不能重复定义i,j。所以避开一下
    {
        for(int b=1;b<COL+1;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]++;
                        }
                    }
                }
                
            }
        }
    }

image-20210209115651732

现在没有内存溢出的隐患了

我们先输出辅助区,printMap()里面的ROW、COL行列分别+2

void printMap()
{
    for(int i=0;i<ROW+2;i++) //更新辅助区
    {
        for(int j=0;j<COL+2;j++)
        {
            printf("%3d",mine[i][j]);
        }
        printf("\n");
    }
}

image-20210209120119516

但是辅助圈现在作为不越界访问帮忙计数,是不能布雷的

辅助圈可以有数字,但是不能有-1布雷,我们修改rand功能 从1到9布雷

       
//x=rand()%9//从0到8
//y=rand()%9//从0到8
		x=rand()%9+1; //产生从1到9
        y=rand()%9+1;
//绘图是mine数组里面的 1行到9行,1列到9列
void gameDraw()
{
    for(int i=1;i<ROW+1;i++)
    {
        for(int j=1;j<COL+1;j++)
        {
			int x=(j-1)*MINE_WID;//同步更新下标
			int y=(i-1)*MINE_WID;
			if(mine[i][j]==0) //初始化开始为0的时候,全部填充空白砖块
			{
				 putimage(x,y,&img[0]);
			}
			else if(mine[i][j]==-1) //当为-1的时候布雷
			{
				putimage(x,y,&img[9]);
			}
        }
    }
}

void printMap() //数组作为储存数据,把外圈也绘制出来
{
    for(int i=0;i<ROW+2;i++)
    {
        for(int j=0;j<COL+2;j++)
        {
            printf("%3d",mine[i][j]);
        }
        printf("\n");
    }
}

现在前后台就对应上了

image-20210209131907167

1.9数字绘制

然后根据数组里面的数字,填充雷区标记数字,在drawMap()函数里面修改一下

void gameDraw()
{
    for(int i=1;i<ROW+1;i++)
    {
        for(int j=1;j<COL+1;j++)
        {
			int x=(j-1)*MINE_WID;//同步更新下标
			int y=(i-1)*MINE_WID;
			if(mine[i][j]>=0&&mine[i][j]<=8) //初始化开始为0的时候,全部填充空白砖块
			{
				 putimage(x,y,&img[mine[i][j]]); //根据mine[i][j]的数字来绘制对应的图片,注意图片的文件名要与自己显示的东西相符合
			}
			else if(mine[i][j]==-1) //当为-1的时候布雷
			{
				putimage(x,y,&img[9]);
			}
        }
    }
}

运行调试多次,验证随机性,并观察数字与雷区是否对应正确

image-20210209132307371

image-20210209132449688

tips:这里我们更新一下,完整代码如下

#include<stdio.h>
#include<graphics.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9//9行9列的雷区表格
#define COL 9
#define MINE_WID 40
#define MAX_MINE 9
int mine[ROW+2][COL+2];
IMAGE img[12];

void printMap() //数组作为储存数据,把外圈也绘制出来
{
    for(int i=0;i<ROW+2;i++)
    {
        for(int j=0;j<COL+2;j++)
        {
            printf("%3d",mine[i][j]);
        }
        printf("\n");
    }
}
//在二维数组里面随机获取9个下标,赋值为-1
void gameInit()
{
    //随机化给下标为x,y的赋值为-1,标记为雷区,并且要判断不要有 重合的下标
    int x,y;
	srand((unsigned int)time(0));
    for(int m=0;m<MAX_MINE;)//注意m++的操作,不在这里
    {

        x=rand()%9+1;
        y=rand()%9+1;
        //判断是否重复
        
		if(mine[x][y]==0) //没有雷的情况下,就埋雷,有雷就没做了
        {
            mine[x][y]=-1;
            //当布雷成功了,m才++
            m++;//放在判断这里++,才会保证一定布满9个雷
        }
		
    }
    // 遍历数组,对雷九宫格进行+1操作.
for(int a=1;a<ROW+1;a++) // VC6在cpp文件不能重复定义i,j。所以避开一下
    {
        for(int b=1;b<COL+1;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);
        
    }
}
//绘图是mine数组里面的 1行到9行,1列到9列
void gameDraw()
{
    for(int i=1;i<ROW+1;i++) //遍历数据区域
    {
        for(int j=1;j<COL+1;j++)
        {
			int x=(j-1)*MINE_WID;//同步更新下标
			int y=(i-1)*MINE_WID;
			if(mine[i][j]>=0&&mine[i][j]<=8) //初始化开始为0的时候,全部填充空白砖块
			{
				 putimage(x,y,&img[mine[i][j]]); //根据mine[i][j]的数字来绘制对应的图片,注意图片的文件名要与自己显示的东西相符合
			}
			else if(mine[i][j]==-1) //当为-1的时候布雷
			{
				putimage(x,y,&img[9]);
			}
        }
    }
}
 int main()
{
	initgraph(MINE_WID*ROW,MINE_WID*COL,1); //参数 1,是同时绘图与打开控制台
	gameInit(); //资源初始化
	gameDraw();//绘制
	printMap();//控制台作为后台数据帮忙分析
	system("pause");//记得 #include<stdlib>
	
	return 0;
}

2.游戏加密与交互操作

2.1加密

刚刚只是做好了数据系统,现在我们要做加密掩盖和交互,不然直接显示最终的结果了。

加密格子,把数组里面(数据区,不要包含辅助圈)每一个值+一个数,这里为20

for(int i=1;i<=ROW;i++)
{
    for(int j=1;j<=COL;j++)
    {
        mine[i][j]+=20;
    }
}

我们更新一下gameInit()函数,如果编译器对临时下标i,j检查严格,就不要在for循环里面反复int i=0,重复使用下标也可以。

void gameInit()
{
    //随机化给下标为x,y的赋值为-1,标记为雷区,并且要判断不要有 重合的下标
    int x,y;
	srand((unsigned int)time(0));
    for(int m=0;m<MAX_MINE;)//注意m++的操作,不在这里
    {

        x=rand()%9+1;
        y=rand()%9+1;
        //判断是否重复
        
		if(mine[x][y]==0) //没有雷的情况下,就埋雷,有雷就没做了
        {
            mine[x][y]=-1;
            //当布雷成功了,m才++
            m++;//放在判断这里++,才会保证一定布满9个雷
        }
		
    }
    // 遍历数组,对雷九宫格进行+1操作.
for(int a=1;a<ROW+1;a++) // VC6在cpp文件不能重复定义i,j。所以避开一下
    {
        for(int b=1;b<COL+1;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]++;
                        }
                    }
                }
                
            }
        }
    }

for(int i=1;i<=ROW;i++)
{
    for(int j=1;j<=COL;j++)
    {
        mine[i][j]+=20;
    }
}



    
    
    char temp[20]=" "; 
    for(i=0;i<12;i++) //对于检查严格的编译器,临时变量可重复使用了,不要再int i=0
    {
        sprintf(temp,"%d.jpg",i);//
        loadimage(&img[i],temp,MINE_WID,MINE_WID);
        
    }
}

加密之后,数据区+20,图没有贴了,未加密前数据最小是-1,最大是8

+20之后,最小是19,最大是28,增加分支判断,在这个区域覆盖掩盖图片(这个图片可以仍然为空白,为了掩饰效果,我们换一个不一样的图)

image-20210209133324661

绘图函数更新

void gameDraw()
{
    for(int i=1;i<ROW+1;i++)
    {
        for(int j=1;j<COL+1;j++)
        {
			int x=(j-1)*MINE_WID;//同步更新下标
			int y=(i-1)*MINE_WID;
			if(mine[i][j]>=0&&mine[i][j]<=8) //初始化开始为0的时候,全部填充空白砖块
			{
				 putimage(x,y,&img[mine[i][j]]); //根据mine[i][j]的数字来绘制对应的图片,注意图片的文件名要与自己显示的东西相符合
			}
			else if(mine[i][j]==-1) //当为-1的时候布雷
			{
				putimage(x,y,&img[9]);
			}
			else if(mine[i][j]>=19&&mine[i][j]<=28) //所有的数字在-1到19范围,+20之后在19到28贴掩盖图片
			{
				putimage(x,y,&img[10]); //贴掩盖图片

			}
        }
    }
}

image-20210209134100539

2.2鼠标操作

开头增加鼠标消息定义 MOUSEMSG msg;
任务:点击之后,加密后的数据解密(实现方法??)
点击之后,鼠标消息一般配合 无限循环反复贴图!

#include<stdio.h>
#include<graphics.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9//9行9列的雷区表格
#define COL 9
#define MINE_WID 40
#define MAX_MINE 9
int mine[ROW+2][COL+2];
IMAGE img[12];
MOUSEMSG msg;
void gameMouse()
{
    if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
        //扫雷有标记功能,判断鼠标左右键。左键确定,右键标记为红旗
        if(msg.uMsg==WM_LBUTTONDOWN)
        {
           //加密的格子进行减操作
            mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]-=20;
            //这里的y和x对调,是因为横向是x,纵向是y,然后只绘制数据区
            
        }
        else if(msg.uMsg==WM_RBUTTONDOWN)
        {
            
        }
            
    }
    
            
}

现在我们在主函数调用试一下,要反复绘图,记得主函数中把点击操作与绘图操作放入死循环中

 int main()
{
	initgraph(MINE_WID*ROW,MINE_WID*COL,1); //参数 1,是同时绘图与打开控制台
	gameInit(); //资源初始化
	while(1)//死循环重复绘图
	
	{
		gameDraw();//绘制

		gameMouse();
	}
	printMap();//控制台作为后台数据帮忙分析
	system("pause");//记得 #include<stdlib>
	
	return 0;
}

image-20210209135154001
扫雷左键是做什么?
右键是做什么??

void gameMouse()
{
    if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
        //扫雷有标记功能,判断鼠标左右键。左键确定,右键标记为红旗
        if(msg.uMsg==WM_LBUTTONDOWN)
        {
           //加密的格子进行减操作
            mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]-=20;
            
        }
        else if(msg.uMsg==WM_RBUTTONDOWN)//判断右键点击进行标记
        {
			if( mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]<30) //简化处理,没有放置标记红旗的都是在小于30
			{
				 mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]+=20;//直接+20,让数字大于30,给放置红旗做准备(-1到8+了20,从19~28,大于30简化)

			}
			else //否则什么? 否则就是 大于30,有红旗了
			{
				 mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]-=20; //如果本来就有红旗,就-20,取消红旗标记
				 //注意在 gameDraw ()里面更新	else if(mine[i][j]>30) putimage(x,y,&img[11]);
			

			}
            
        }
            
    }
    
            
}

gameDraw()更新一下

void gameDraw()
{
    for(int i=1;i<ROW+1;i++)
    {
        for(int j=1;j<COL+1;j++)
        {
			int x=(j-1)*MINE_WID;//同步更新下标
			int y=(i-1)*MINE_WID;
			if(mine[i][j]>=0&&mine[i][j]<=8) //初始化开始为0的时候,全部填充空白砖块
			{
				 putimage(x,y,&img[mine[i][j]]); //根据mine[i][j]的数字来绘制对应的图片,注意图片的文件名要与自己显示的东西相符合
			}
			else if(mine[i][j]==-1) //当为-1的时候布雷
			{
				putimage(x,y,&img[9]);
			}
			else if(mine[i][j]>=19&&mine[i][j]<=28) //所有的数字在-1到19范围,+20之后在19到28贴掩盖图片
			{
				putimage(x,y,&img[10]);

			}
			else if(mine[i][j]>30)
			{
				putimage(x,y,&img[11]);
			}

        }
    }
}

调试一下,验证红旗标记,数字标记,雷区标记,与红旗标记,取消红旗标记功能

image-20210210094333553

2.3判断游戏结束与胜利

什么是输?
就是踩到雷了!踩雷之后,是点击事件发生,已经发生了数据解密,与-1进行比较

void gameWinorLose()
{
    //复制一下鼠标消息的代码
  if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
       if(mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]==-1) //注意点击之后的判断进行了解密操作,对-1进行判断,有时候是对加密后的数据进行判断,要自己学会区分
           //include加入对话框弹出结束游戏 #include<Windows.h>
       {
          MessageBox(hwnd,"中雷了!","Game Over",MB_OK); 
           //全局变量区加入 HWND hwnd=NULL;
		  exit(0);
       
	   }
  }
           
}

现在我们调用一下

int main()
{
	initgraph(MINE_WID*ROW,MINE_WID*COL,1); //参数 1,是同时绘图与打开控制台
	gameInit(); //资源初始化
	printMap();//控制台作为后台数据帮忙分析
	while(1)
	
	{
		
	    gameDraw();//绘制
		gameMouse();
		gameDraw();//绘制二次,弹出窗口
		gameWinorLose();
	}
	
	system("pause");//记得 #include<stdlib>
	
	return 0;
}

当然游戏还有更完善的功能,比如点击空白区域,全部展开,我们需要更新一下代码,将鼠标坐标作为全局坐标方便传递参数,将鼠标消息的坐标赋值给openx,openy,代码会更简洁

#include<stdio.h>
#include<graphics.h>
#include<Windows.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9//9行9列的雷区表格
#define COL 9
#define MINE_WID 40
#define MAX_MINE 9
int mine[ROW+2][COL+2];
int openx,openy;
IMAGE img[12];
MOUSEMSG msg;
HWND hwnd=NULL;
//全局变量方便访问,mine[openx][openy]更简洁一些
void gameMouse()
{
    if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
        //扫雷有标记功能,判断鼠标左右键。左键确定,右键标记为红旗
        if(msg.uMsg==WM_LBUTTONDOWN)
        {
			openx=msg.y/MINE_WID+1;
			openy=msg.x/MINE_WID+1;
           //加密的格子进行减操作
            mine[openx][openy]-=20; 
            
        }
        else if(msg.uMsg==WM_RBUTTONDOWN) //判断右键点击进行标记
        {
			if( mine[openx][openy]<30) //简化处理,没有放置标记红旗的都是在小于30
			{
				 mine[openx][openy]+=20;//直接+20,让数字大于30,给放置红旗做准备

			}
			else
			{
				 mine[openx][openy]-=20; //如果本来就有红旗,就-20,取消红旗标记
				 //注意在 drawMap()里面更新	else if(mine[i][j]>30) putimage(x,y,&img[11]);
			

			}
            
        }
            
    }
    
            
}
//同样这里可以简单的处理一下
void gameWinorLose()
{
    //复制一下鼠标消息的代码
  if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
       if(mine[openx][openy]==-1) //注意点击之后的判断进行了解密操作,对-1进行判断,有时候是对加密后的数据进行判断,要自己学会区分
           //include加入对话框弹出结束游戏 #include<Windows.h>
       {
          MessageBox(hwnd,"中雷了!","Game Over",MB_OK); 
           //全局变量区加入 HWND hwnd=NULL;
		  exit(0);
       
	   }
  }
           
}

然后我们来设计打开空白全部展开的函数

void openNull(int x,int y) //传递openx,openy进来
{
    if(mine[x][y]==0)//如果是空白(已经解密了,对0进行操作)
    {
        for (int i=x-1;i<=x+1;i++)//二层遍历周围的方格子
        {
            for(int j=y-1;j<=y+1;j++)
            {
                if(mine[i][j]==20)//周围的格子没有点,没有解密,与20进行判断
                {
                    mine[i][j]-=20;//解密为空格0
                    openNull(i,j);//递归调用到周围所有的空格全部一键打开退出
                }
            }
        }
    }
    
    
}

openNull()函数,在鼠标消息的左键点击判断里面调用,这样就一次展开所有空格,部分代码如下

 if(msg.uMsg==WM_LBUTTONDOWN)
        {
			openx=msg.y/MINE_WID+1;
			openy=msg.x/MINE_WID+1;
           //加密的格子进行减操作
            mine[openx][openy]-=20;
			openNull(openx,openy);//空白格子递归全展开
            
        }

3.结束完整代码(有兴趣的同学,可以加入胜利消息)

#include<stdio.h>
#include<graphics.h>
#include<Windows.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9//9行9列的雷区表格
#define COL 9
#define MINE_WID 40
#define MAX_MINE 9
int mine[ROW+2][COL+2];
int openx,openy;
IMAGE img[12];
MOUSEMSG msg;
HWND hwnd=NULL;

void printMap() //数组作为储存数据,把外圈也绘制出来
{
    for(int i=0;i<ROW+2;i++)
    {
        for(int j=0;j<COL+2;j++)
        {
            printf("%3d",mine[i][j]);
        }
        printf("\n");
    }
}
//在二维数组里面随机获取9个下标,赋值为-1
void gameInit()
{
    //随机化给下标为x,y的赋值为-1,标记为雷区,并且要判断不要有 重合的下标
    int x,y;
	srand((unsigned int)time(0));
    for(int m=0;m<MAX_MINE;)//注意m++的操作,不在这里
    {

        x=rand()%9+1;
        y=rand()%9+1;
        //判断是否重复
        
		if(mine[x][y]==0) //没有雷的情况下,就埋雷,有雷就没做了
        {
            mine[x][y]=-1;
            //当布雷成功了,m才++
            m++;//放在判断这里++,才会保证一定布满9个雷
        }
		
    }
    // 遍历数组,对雷九宫格进行+1操作.
for(int a=1;a<ROW+1;a++) // VC6在cpp文件不能重复定义i,j。所以避开一下
    {
        for(int b=1;b<COL+1;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]++;
                        }
                    }
                }
                
            }
        }
    }

for(int i=1;i<=ROW;i++)
{
    for(int j=1;j<=COL;j++)
    {
        mine[i][j]+=20;
    }
}



    
    
    char temp[20]=" "; 
    for(i=0;i<12;i++)
    {
        sprintf(temp,"%d.jpg",i);//
        loadimage(&img[i],temp,MINE_WID,MINE_WID);
        
    }
}
//绘图是mine数组里面的 1行到9行,1列到9列
void gameDraw()
{
    for(int i=1;i<ROW+1;i++)
    {
        for(int j=1;j<COL+1;j++)
        {
			int x=(j-1)*MINE_WID;//同步更新下标
			int y=(i-1)*MINE_WID;
			if(mine[i][j]>=0&&mine[i][j]<=8) //初始化开始为0的时候,全部填充空白砖块
			{
				 putimage(x,y,&img[mine[i][j]]); //根据mine[i][j]的数字来绘制对应的图片,注意图片的文件名要与自己显示的东西相符合
			}
			else if(mine[i][j]==-1) //当为-1的时候布雷
			{
				putimage(x,y,&img[9]);
			}
			else if(mine[i][j]>=19&&mine[i][j]<=28) //所有的数字在-1到19范围,+20之后在19到28贴掩盖图片
			{
				putimage(x,y,&img[10]);

			}
			else if(mine[i][j]>30)
			{
				putimage(x,y,&img[11]);
			}

        }
    }
}
void openNull(int x,int y) //传递openx,openy进来
{
    if(mine[x][y]==0)//如果是空白(已经解密了,对0进行操作)
    {
        for (int i=x-1;i<=x+1;i++)//二层遍历周围的方格子
        {
            for(int j=y-1;j<=y+1;j++)
            {
                if(mine[i][j]==20)//周围的格子没有点,因为还没有解密,与20进行判断
                {
                    mine[i][j]-=20;//解密为空格0
                    openNull(i,j);//递归调用到周围所有的空格全部一键打开退出
                }
            }
        }
    }
    
    
}
void gameMouse()
{
    if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
        //扫雷有标记功能,判断鼠标左右键。左键确定,右键标记为红旗
        if(msg.uMsg==WM_LBUTTONDOWN)
        {
			openx=msg.y/MINE_WID+1;
			openy=msg.x/MINE_WID+1;
           //加密的格子进行减操作
            mine[openx][openy]-=20;
			openNull(openx,openy);//空白格子递归全展开
            
        }
        else if(msg.uMsg==WM_RBUTTONDOWN) //判断右键点击进行标记
        {
			if( mine[openx][openy]<30) //简化处理,没有放置标记红旗的都是在小于30
			{
				 mine[openx][openy]+=20;//直接+20,让数字大于30,给放置红旗做准备

			}
			else
			{
				 mine[openx][openy]-=20; //如果本来就有红旗,就-20,取消红旗标记
				 //注意在 drawMap()里面更新	else if(mine[i][j]>30) putimage(x,y,&img[11]);
			

			}
            
        }
            
    }
    
            
}
void gameWinorLose()
{
    //复制一下鼠标消息的代码
  if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
       if(mine[openx][openy]==-1) //注意点击之后的判断进行了解密操作,对-1进行判断,有时候是对加密后的数据进行判断,要自己学会区分
           //include加入对话框弹出结束游戏 #include<Windows.h>
       {
          MessageBox(hwnd,"中雷了!","Game Over",MB_OK); 
           //全局变量区加入 HWND hwnd=NULL;
		  exit(0);
       
	   }
  }
           
}
 int main()
{
	initgraph(MINE_WID*ROW,MINE_WID*COL,1); //参数 1,是同时绘图与打开控制台
	gameInit(); //资源初始化
	printMap();//控制台作为后台数据帮忙分析
	while(1)
	
	{
		
	    gameDraw();//绘制
		gameMouse();
		gameDraw();//绘制
		gameWinorLose();
	}
	
	system("pause");//记得 #include<stdlib>
	
	return 0;
}

行减操作
            mine[openx][openy]-=20;
			openNull(openx,openy);//空白格子递归全展开
            
        }
        else if(msg.uMsg==WM_RBUTTONDOWN) //判断右键点击进行标记
        {
			if( mine[openx][openy]<30) //简化处理,没有放置标记红旗的都是在小于30
			{
				 mine[openx][openy]+=20;//直接+20,让数字大于30,给放置红旗做准备

			}
			else
			{
				 mine[openx][openy]-=20; //如果本来就有红旗,就-20,取消红旗标记
				 //注意在 drawMap()里面更新	else if(mine[i][j]>30) putimage(x,y,&img[11]);
			

			}
            
        }
            
    }
    
            
}
void gameWinorLose()
{
    //复制一下鼠标消息的代码
  if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
       if(mine[openx][openy]==-1) //注意点击之后的判断进行了解密操作,对-1进行判断,有时候是对加密后的数据进行判断,要自己学会区分
           //include加入对话框弹出结束游戏 #include<Windows.h>
       {
          MessageBox(hwnd,"中雷了!","Game Over",MB_OK); 
           //全局变量区加入 HWND hwnd=NULL;
		  exit(0);
       
	   }
  }
           
}
 int main()
{
	initgraph(MINE_WID*ROW,MINE_WID*COL,1); //参数 1,是同时绘图与打开控制台
	gameInit(); //资源初始化
	printMap();//控制台作为后台数据帮忙分析
	while(1)
	
	{
		
	    gameDraw();//绘制
		gameMouse();
		gameDraw();//绘制
		gameWinorLose();
	}
	
	system("pause");//记得 #include<stdlib>
	
	return 0;
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-26 12:02:17  更:2021-10-26 12:04:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:45:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码