扫雷开发C语言

本文详细介绍了如何使用C++和图形库开发扫雷游戏,包括游戏的前期准备、布雷逻辑、绘制地图、加密与解密、鼠标交互以及游戏结束条件。通过循环、数组、函数等基础知识,逐步实现了一个功能完整的扫雷游戏,涵盖了游戏设计、编程技巧和图形界面的实现。
摘要由CSDN通过智能技术生成

扫雷开发

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<gra
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值