目录标题

  • 迷宫游戏
    • 迷宫的生成
    • BFS寻找路线
    • 最后的一些细枝末节
    • 如何使用程序
    • 链接
    • I TURN COFFEE INTO CODE!

800x800迷宫自动解路径
镇楼图

https://pan.baidu.com/s/1ql-fy9V_vmhQp2huFWhshw
迷宫游戏百度网盘在此

迷宫游戏

本人墨尔本大学大一学生一枚,前段利用暑假在家闲来无事写了一个迷宫游戏。起初只是想锻炼巩固一下BFS,以及链表的知识点,后来逐渐给自己的程序增加了一些自己想要的功能,同时也学习到了很多东西。
主要涉及到了三个部分:
1,迷宫的生成
2,BFS寻找路线,利用队列寻路
3,BMP图片的生成
4,在Console中动态显示BFS求得的路线,运用gotoxy();而不是system(“cls”),避免闪屏。

迷宫的生成

迷宫的生成主要利用了递归分割法,先初始化空白二维矩阵,N by N grid,
递归分割法通俗的说就是在这片空白的区域中砌墙,怎么个砌法呢,就是递归的用墙"切割"这片空白的空间,直到墙和墙之间达到最小的单位宽度,在此也就是一格。
如图所示便是递归分割法:

BFS寻找路线

BFS是一种寻路的很重要的算法,在该类迷宫中BFS可以找到最优的路径。
通俗的说,BFS在我看来就像是往迷宫的起点灌水(蔓延状的遍历整个图),一旦水到了出口,立刻停止灌水,(也就是增加队列),并且开始回溯路径。
当然,水是不能回溯路径的,而存在链表(队列)中的坐标是可以回溯的。我用的方法是创建了一个结构体,包含了当前x,y坐标以及pre_x,pre_y先前坐标,起点处的先前坐标设为-1,-1,也就是在回溯过程中,一旦先前坐标为-1,停止回溯,之后便得到了完整的BFS路径。
另一个问题,
如果有同样长度的路径到达起点,我们应该选择哪一条呢?
不用担心,在添加队列之前我们就应当设定好了一个方向顺序,比如先看当前坐标的"上",之后是"下",“左”,“右”。而刚刚我已经提到过,既然有顺序可言,并且往迷宫内"灌水"的行为是一旦到达目标终点并停止,那么我们只要回溯就能得到路径,根本就无需考虑相同长度的路径,因为即使它可能存在,但是你回溯路径的选择只有一条路。



最后的一些细枝末节

程序的主体大概就是如上所说,其他一些琐碎的东西便是将数据存入txt文档并再读取,用于解路线以及画图。
画图我一开始尝试用matlab,非常方便,但是发现打包之后的matlab的exe并不能在其他电脑上通用,而且体积庞大,于是花了一点时间学习了一下BMP图片的生成,并且动手改写了一下这里的代码,归为己有。
https://blog.csdn.net/sguniver_22/article/details/80379457

先给大家看一下我最后生成的bmp图片。这是最大的一只,800x800的,如果一个有一米长 那么这个迷宫便是一平方公里那么大了。

还有一些小一点的,对浏览者友好。没记错的话这应该就是120x120
图片的单位都是像素。

如何使用程序

为了方便运行,我没有在源代码中加入过多的system(“balabala”);语句,所以写了一个批处理文件 如下 也就是运行过程。

@echo off
color FA
title = AUTO MAZE SOLVER
mode con cols=120 lines=80
::设置颜色,大小和标题
::运行maze.exe会在当前文件夹中生成一个半成品maze.txt储存了block的坐标和迷宫的信息
maze.exe
::如果源文件夹已有迷宫图片自动删除(为了之后生成新的)
del MAZE.bmp
color F9
::BFS解迷宫程序输入信息,完善maze.txt为了下一步给创建BMP使用
maze_solver.exe<maze.txt
::创建BMP文件输入信息,输出MAZE.bmp
creatBMP.exe<maze.txt
pause
::程序完整运行完毕,显示迷宫彩色BMP图片
MAZE.bmp
del maze.txt
Alvin.vbs

在源代码BMP文件夹和MAZE文件夹中的批处理文件则是方便我修改代码时候编译用的,如果各位看客用的也是gcc编译那也可以使用。

链接

链接: https://www.youtube.com/watch?v=KiCBXu4P-2Y&t=878s
油管上BFS的视频

I TURN COFFEE INTO CODE!

下面附上源代码。
第一次写博客希望大家多多支持,代码繁琐之处欢迎大家在评论中指出! 抱拳感谢!
btw:程序的时间复杂度BIG-OH在迷宫尺寸大于四百之后不是很理想,三百尺寸是十秒左右,二百两三秒,一百以内毫秒。上面最大的800X800的图跑了十几分钟,希望大家能指出可以优化的地方!!!
哦对了,程序运行方法还没告诉你们呢,先输入尺寸,然后输入1是不改变默认终点,也就是左上到右下,如果输入0的话那就可以改变终点位置,再输入想要的终点,如 19,5 如果坐标invalid程序会自动提示重新输入。
大家可以讲console字体调到8号或者更小,因为程序设定如果迷宫大小大于130则不显示,所以如果字体过大,屏幕会乱的一塌糊涂,但是最后生成的图片是没问题的。
最后动态显示路线则是使用gotoxy函数实现。
/************************************************************************************/
生成BMP

//bmp.h#ifndef _BMP_H
#define _BMP_H//bmp 图片数据获取
//filePath : 路径
//picMaxSize : 返回图片数据字节数, 不接收置NULL
//width : 返回图片宽(像素), 不接收置NULL
//height : 返回图片高(像素), 不接收置NULL
//per : 返回图片每像素的字节数, 不接收置NULL
//返回 : 图片数据指针, 已分配内存, 用完记得释放
unsigned char *bmp_get(char *filePath, int *picMaxSize, int *width, int *height, int *per);//生成 bmp 图片
//filePath : 路径
//data : 原始数据
//width : 宽(像素)
//height : 高(像素)
//per : 每像素字节数
//返回 : 成功创建的 .bmp 文件大小, 小于0则失败
int bmp_create(char *filePath, unsigned char *data, int width, int height, int per);#endif

```c
//bmp.c#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>//
#define  Bmp_FileHeader_Size    14  // sizeof(Bmp_FileHeader)的值不一定准确
typedef struct{uint8_t bfType[2];    //文件类型: "BM"/bmp, "BA"/.. , ...uint32_t bfSize;      //整个文件的大小uint16_t bfReserved1; //保留: 0uint16_t bfReserved2; //保留: 0uint32_t bfOffbits;   //文件数据从第几个字节开始
}Bmp_FileHeader;
//
#define  Bmp_Info_Size    40
typedef struct{uint32_t biSize;    //该段占用字节数uint32_t biWidth;   //图像宽度, 单位像素int32_t biHeight;   //图像高度, 单位像素(数据为正时为倒向)uint16_t biPlanes;  //平面数, 总是为1uint16_t biBitCount;    //单位像素占用比特数: 1, 4, 8, 16, 24, 42uint32_t biCompression; //图像压缩方式: 0/BI_BGB 不压缩, //  1/BI_RLE8 8比特游程压缩, 只用于8位位图//  2/BI_RLE4 4比特游程压缩, 只用于4位位图//  3/BI_BITFIELDS 比特域, 用于16/32位位图//  4/BI_JPEG 位图含有jpeg图像, 用于打印机//  5/BI_PWG 位图含有pwg图像, 用于打印机uint32_t biSizeImage;   //说明图像大小, 为BI_BGB时可能为0int32_t biXPelsPerMeter;//水平分辨率, 像素/米, 有符号整数int32_t biYPelsPerMeter;//垂直分辨率, 像素/米, 有符号整数uint32_t biClrUsed;     //位图实际使用彩色表中的颜色索引数(为0表示使用所有)uint32_t biClrImportant;//图像显示有重要影响的颜色索引数
}Bmp_Info;//功能: 读取bmp格式图片
//参数: filePath: 传入, 文件地址
//     picMaxSize: 传出, 用以返回读取到的图片矩阵的总字节数
//      width: 传出, 用以返回图片横向的像素个数
//     height: 传出, 用以返回图片纵向的像素个数
//       per: 传出, 用以返回图片每像素占用字节数
//返回: 图片矩阵数据的指针(注意指针是函数内分配的内存, 用完需释放)
unsigned char *bmp_get(char *filePath, int *picMaxSize, int *width, int *height, int *per)
{FILE *fp;Bmp_FileHeader bf;Bmp_Info bi;int perW, perWCount;int ret;int i, j, picCount, totalSize;int overLineBytesNum;unsigned int overLineBytesSum;    // overLineBytesNum : 行结尾补0字节数  //每行字节数规定为4的倍数, 不足将补0, 所以读行的时候注意跳过unsigned char buffHeader[512], *data, *pic;//if(filePath == NULL)return NULL;//if((fp = fopen(filePath, "rb")) < 0){   printf("bmp_get : open file %s failed\r\n", filePath);return NULL;}//Bmp_FileHeaderif(fread(buffHeader, 1, Bmp_FileHeader_Size, fp) <= 0){printf("bmp_get : read Bmp_FileHeader failed\r\n");fclose(fp);return NULL;}bf.bfType[0] = buffHeader[0]; bf.bfType[1] = buffHeader[1];bf.bfSize = buffHeader[2] + ((buffHeader[3]&0xFF)<<8) + ((buffHeader[4]&0xFF)<<16) + ((buffHeader[5]&0xFF)<<24);bf.bfOffbits = buffHeader[10] + ((buffHeader[11]&0xFF)<<8) + ((buffHeader[12]&0xFF)<<16) + ((buffHeader[13]&0xFF)<<24);//printf("bmp_get : bfType/%s, bfSize/%d, bfOffbits/%d\r\n", bf.bfType, bf.bfSize, bf.bfOffbits);if(bf.bfType[0] != 'B' || bf.bfType[1] != 'M'){printf("bmp_get : bmp type err, bfType must be \"BM\"\r\n");fclose(fp);return NULL;}//Bmp_Infoif(bf.bfOffbits - Bmp_FileHeader_Size < Bmp_Info_Size || fread(buffHeader, 1, Bmp_Info_Size, fp) <= 0){printf("bmp_get : read Bmp_Info failed\r\n");fclose(fp);return NULL;}bi.biSize = buffHeader[0] + ((buffHeader[1]&0xFF)<<8) + ((buffHeader[2]&0xFF)<<16) + ((buffHeader[3]&0xFF)<<24);bi.biWidth = buffHeader[4] + ((buffHeader[5]&0xFF)<<8) + ((buffHeader[6]&0xFF)<<16) + ((buffHeader[7]&0xFF)<<24);bi.biHeight = buffHeader[8] | ((buffHeader[9]&0xFF)<<8) | ((buffHeader[10]&0xFF)<<16) | ((buffHeader[11]&0xFF)<<24);bi.biPlanes = buffHeader[12] + ((buffHeader[13]&0xFF)<<8);bi.biBitCount = buffHeader[14] + ((buffHeader[15]&0xFF)<<8);bi.biCompression = buffHeader[16] + ((buffHeader[17]&0xFF)<<8) + ((buffHeader[18]&0xFF)<<16) + ((buffHeader[19]&0xFF)<<24);bi.biSizeImage = buffHeader[20] + ((buffHeader[21]&0xFF)<<8) + ((buffHeader[22]&0xFF)<<16) + ((buffHeader[23]&0xFF)<<24);bi.biXPelsPerMeter = buffHeader[24] | ((buffHeader[25]&0xFF)<<8) | ((buffHeader[26]&0xFF)<<16) | ((buffHeader[27]&0xFF)<<24);bi.biYPelsPerMeter = buffHeader[28] | ((buffHeader[29]&0xFF)<<8) | ((buffHeader[30]&0xFF)<<16) | ((buffHeader[31]&0xFF)<<24);bi.biClrUsed = buffHeader[32] + ((buffHeader[33]&0xFF)<<8) + ((buffHeader[34]&0xFF)<<16) + ((buffHeader[35]&0xFF)<<24);bi.biClrImportant = buffHeader[36] + ((buffHeader[37]&0xFF)<<8) + ((buffHeader[38]&0xFF)<<16) + ((buffHeader[39]&0xFF)<<24);//perW 每像素字节数if(bi.biBitCount >= 8)perW = bi.biBitCount/8;elseperW = 1;//计算总字节数//totalSize = bf.bfSize - bf.bfOffbits;//计算总字节数overLineBytesNum = 4- bi.biWidth*(bi.biBitCount/8)%4;if(overLineBytesNum == 4)overLineBytesNum = 0;if(bi.biHeight < 0){totalSize = bi.biWidth*(-bi.biHeight)*(bi.biBitCount/8);overLineBytesSum = overLineBytesNum*(-bi.biHeight);}else{totalSize = bi.biWidth*bi.biHeight*(bi.biBitCount/8);overLineBytesSum = overLineBytesNum*bi.biHeight;}//printf("bmp_get : biSize/%d, biWidth/%d, biHeight/%d, biPlanes/%d, biBitCount/%d, biCompression/%d, biSizeImage/%d, biXPelsPerMeter/%d, biYPelsPerMeter/%d, biClrUsed/%d, biClrImportant/%d, overLineBytesNum/%d, overLineBytesSum/%d, totalSize/%d\r\n", bi.biSize, bi.biWidth, bi.biHeight, bi.biPlanes, bi.biBitCount, bi.biCompression, bi.biSizeImage, bi.biXPelsPerMeter, bi.biYPelsPerMeter, bi.biClrUsed, bi.biClrImportant, overLineBytesNum, overLineBytesSum, totalSize);//指针移动到数据起始if(fseek(fp, bf.bfOffbits, 0) < 0){printf("bmp_get : lseek failed\r\n");fclose(fp);return NULL;}//分配内存一次读入整张图片data = (unsigned char *)calloc(1, totalSize + overLineBytesSum + perW);    //多1像素的字节, 防止操作不当溢出if((ret = fread(data, 1, totalSize + overLineBytesSum, fp)) != (totalSize + overLineBytesSum)){if(ret <= 0){printf("bmp_get : read data failed\r\n");free(data);fclose(fp);return NULL;}}//closefclose(fp);//pic = (unsigned char *)calloc(1, totalSize);memset(pic, 0, totalSize);//根据图片方向拷贝数据if(bi.biHeight > 0)     //倒向        //上下翻转 + 左右翻转 + 像素字节顺序调整{for(i = 0, picCount = totalSize; i < totalSize + overLineBytesSum && picCount >= 0; ){picCount -= bi.biWidth*perW;for(j = 0, perWCount = perW - 1; j < bi.biWidth*perW && i < totalSize + overLineBytesSum && picCount >= 0; j++){pic[picCount + perWCount] = data[i++];if(--perWCount < 0)perWCount = perW - 1;if(perWCount == perW - 1)picCount += perW;}picCount -= bi.biWidth*perW;i += overLineBytesNum;}}else    // 正向        //像素字节顺序调整{for(i = 0, j = 0, picCount = 0, perWCount = perW - 1; i < totalSize + overLineBytesSum && picCount < totalSize; ){   pic[picCount + perWCount] = data[i++];if(--perWCount < 0)perWCount = perW - 1;if(perWCount == perW - 1)picCount += perW;if(++j == bi.biWidth*perW){j = 0;i += overLineBytesNum;}}}//freefree(data);//返回 宽, 高, 像素字节if(picMaxSize)*picMaxSize = totalSize;if(width)*width = bi.biWidth;if(height){if(bi.biHeight > 0)*height = bi.biHeight;else*height = -bi.biHeight;}if(per)*per = perW;return pic;
}//功能: 创建bmp格式图片
//参数: filePath: 传入, 文件地址
//      data: 传入, 图片矩阵数据的指针
//     width: 传入, 图片横向的像素个数
//     height: 传入, 图片纵向的像素个数
//       per: 传入, 图片每像素占用字节数
//返回: 创建的bmp图片文件的大小, -1表示创建失败
int bmp_create(char *filePath, unsigned char *data, int width, int height, int per)
{FILE *fp;int fileSize, fileSize2, count, headSize;unsigned char *bmpData, *p;int perWCount;int i, j, picCount;int overLineBytesNum;unsigned int overLineBytesSum = 0;// overLineBytesNum : 行结尾补0字节数  //每行字节数规定为4的倍数, 不足将补0, 所以读行的时候注意跳过//if(width < 0){printf("bmp_create : width < 0 , err !!\r\n");return -1;}//if((fp = fopen(filePath, "wb+")) < 0){printf("bmp_create : create %s err\r\n", filePath);return -1;}//overLineBytesNum = width*per%4;if(overLineBytesNum == 4)overLineBytesNum = 0;headSize = Bmp_FileHeader_Size + Bmp_Info_Size;if(height < 0){overLineBytesNum = overLineBytesNum*(-height);fileSize2 =  width*(-height)*per;}else{overLineBytesNum = overLineBytesNum*height;fileSize2 =  width*height*per;}fileSize = headSize + fileSize2;bmpData = (unsigned char *)calloc(1, fileSize + overLineBytesNum);//count = 0;//bmpData[count++] = 'B';      //bfTypebmpData[count++] = 'M';bmpData[count++] = (unsigned char)((fileSize>>0)&0xFF);    //bfSize     低位在前bmpData[count++] = (unsigned char)((fileSize>>8)&0xFF);bmpData[count++] = (unsigned char)((fileSize>>16)&0xFF);bmpData[count++] = (unsigned char)((fileSize>>24)&0xFF);count++;    //保留count++;count++;count++;bmpData[count++] = (unsigned char)((headSize>>0)&0xFF);    //bfOffbits     低位在前bmpData[count++] = (unsigned char)((headSize>>8)&0xFF);bmpData[count++] = (unsigned char)((headSize>>16)&0xFF);bmpData[count++] = (unsigned char)((headSize>>24)&0xFF);bmpData[count++] = (unsigned char)((Bmp_Info_Size>>0)&0xFF);    //biSizebmpData[count++] = (unsigned char)((Bmp_Info_Size>>8)&0xFF);bmpData[count++] = (unsigned char)((Bmp_Info_Size>>16)&0xFF);bmpData[count++] = (unsigned char)((Bmp_Info_Size>>24)&0xFF);bmpData[count++] = (unsigned char)((width>>0)&0xFF);    //biWidthbmpData[count++] = (unsigned char)((width>>8)&0xFF);bmpData[count++] = (unsigned char)((width>>16)&0xFF);bmpData[count++] = (unsigned char)((width>>24)&0xFF);bmpData[count++] = (unsigned char)((height>>0)&0xFF);    //biHeightbmpData[count++] = (unsigned char)((height>>8)&0xFF);bmpData[count++] = (unsigned char)((height>>16)&0xFF);bmpData[count++] = (unsigned char)((height>>24)&0xFF);bmpData[count++] = 0x01;    //biPlanesbmpData[count++] = 0x00;bmpData[count++] = 24;    //biBitCountbmpData[count++] = 0;bmpData[count++] = 0;    //biCompressionbmpData[count++] = 0;bmpData[count++] = 0;bmpData[count++] = 0;bmpData[count++] = (unsigned char)((fileSize2>>0)&0xFF);    //biSizeImagebmpData[count++] = (unsigned char)((fileSize2>>8)&0xFF);bmpData[count++] = (unsigned char)((fileSize2>>16)&0xFF);bmpData[count++] = (unsigned char)((fileSize2>>24)&0xFF);bmpData[count++] = 0;    //biXPelsPerMeterbmpData[count++] = 0;bmpData[count++] = 0;bmpData[count++] = 0;bmpData[count++] = 0;    //biYPelsPerMeterbmpData[count++] = 0;bmpData[count++] = 0;bmpData[count++] = 0;bmpData[count++] = 0;    //biClrUsedbmpData[count++] = 0;bmpData[count++] = 0;bmpData[count++] = 0;bmpData[count++] = 0;    //biClrImportantbmpData[count++] = 0;bmpData[count++] = 0;bmpData[count++] = 0;//p = &bmpData[count];if(height >= 0)     //倒向        //上下翻转 + 左右翻转 + 像素字节顺序调整{for(i = 0, picCount = fileSize2; i < fileSize2 + overLineBytesSum && picCount >= 0; ){picCount -= width*per;for(j = 0, perWCount = per - 1; j < width*per && i < fileSize2 + overLineBytesSum && picCount >= 0; j++){p[i++] = data[picCount + perWCount];if(--perWCount < 0)perWCount = per - 1;if(perWCount == per - 1)picCount += per;}picCount -= width*per;i += overLineBytesNum;}}else    // 正向        //像素字节顺序调整{for(i = 0, j = 0, picCount = 0, perWCount = per - 1; i < fileSize2 + overLineBytesSum && picCount < fileSize2; ){   p[i++] = data[picCount + perWCount];if(--perWCount < 0)perWCount = per - 1;if(perWCount == per - 1)picCount += per;if(++j == width*per){j = 0;i += overLineBytesNum;}}}//fileSize = fwrite(bmpData, 1, fileSize, fp);free(bmpData);fclose(fp);//sync();return fileSize;
}
//main.c#include <stdio.h>
#include <stdlib.h> //malloc free#include "bmp.h"//一张 宽100*高50*像素3字节 的RGB图片
int BMP_WIDTH = 0;
int BMP_HEIGHT = 0;
#define BMP_PERW 3
//读取图片用
int width, height, perW, picSize;int main(int argc, char *argv[])
{int x,y,ch=0;scanf("%d\n[%*d,%*d]\n[%*d,%*d]\n",&BMP_WIDTH);//去头BMP_HEIGHT = BMP_WIDTH;unsigned char buff[BMP_HEIGHT][BMP_WIDTH][BMP_PERW];//---------- 创建一张图片 ----------ch=getchar();while(ch!='$'){scanf("%d,%d]\n",&y,&x);//blockbuff[y][x][0] = 0xb0;buff[y][x][1] = 0xb0;buff[y][x][2] = 0xf0;ch=getchar();}getchar();//pathch=getchar();while(ch!='$'){scanf("%d,%d]\n",&y,&x);buff[y][x][0] = 0;buff[y][x][1] = 0;buff[y][x][2] = 0;ch=getchar();}getchar();ch=getchar();//spacewhile(ch!=EOF){scanf("%d,%d]\n",&y,&x);buff[y][x][0] = 0xff;buff[y][x][1] = 0xff;buff[y][x][2] = 0xff;ch=getchar();}//输出图片bmp_create("MAZE.bmp", (unsigned char *)buff, BMP_WIDTH, BMP_HEIGHT, BMP_PERW);return 0;
}

编译

gcc -Wall -o creatBMP main.c bmp.c

/************************************************************************************/
/************************************************************************************/
生成迷宫

//maze.c/*
This programme creat a random square maze of the given size.
And store the info of the maze into maze.txt.
In the format of:
1: The first line is one int number indicates the height and width of the maze.
2: The second and third line contains one [x,y], indicates the start and the end
point of the maze.
3: The rest of the line indicates the location of blocks in the maze
4: The last line of the file is a '$' symbol which indicates the end of the
block data, and for further data appending.
*/#include<stdio.h>
#include<stdlib.h>
#include <time.h>
#define DEFAULT_END_X L-2
#define DEFAULT_END_Y L-1
int L=0, DEFAULT_START_POINT = 1;
int SEE_MAP=0;
static const int ROUTE=0;
static const int WALL=1;void CreateMaze(int **maze,int x1,int y1,int x2,int y2){//判断是否还能继续分割if(x2-x1<2||y2-y1<2){return ;}//随机取点int x=x1+1+rand()%(x2-x1-1);int y=y1+1+rand()%(y2-y1-1);//画墙for(int i=x1;i<=x2;i++) maze[i][y]=WALL;for(int i=y1;i<=y2;i++) maze[x][i]=WALL;//递归分割,继续划分区域CreateMaze(maze,x1,y1,x-1,y-1);CreateMaze(maze, x+1, y+1, x2, y2);CreateMaze(maze,x+1,y1,x2,y-1);CreateMaze(maze, x1, y+1, x-1, y2);//随机取其中的三面墙int r[4]={0};r[rand()%4]=1;//在墙上随机取点开孔for(int i=0;i<4;i++){if(r[i]==0){int rx=x;int ry=y;switch (i) {case 0://判断该位置是否能确保打通相邻两块区域,判断依据,上下左右位置最多只有两面墙,下面一样do{rx=x1+rand()%(x-x1);}while(maze[rx-1][ry]+maze[rx+1][ry]+maze[rx][ry-1]+maze[rx][ry+1]>2*WALL);break;case 1:do{ry=y+1+rand()%(y2-y);}while(maze[rx-1][ry]+maze[rx+1][ry]+maze[rx][ry-1]+maze[rx][ry+1]>2*WALL);break;case 2:do{rx=x+1+rand()%(x2-x);}while(maze[rx-1][ry]+maze[rx+1][ry]+maze[rx][ry-1]+maze[rx][ry+1]>2*WALL);break;case 3:do{ry=y1+rand()%(y-y1);}while(maze[rx-1][ry]+maze[rx+1][ry]+maze[rx][ry-1]+maze[rx][ry+1]>2*WALL);break;default:break;}maze[rx][ry]=ROUTE;}}
}int main(int argc, const char * argv[]) {int ed_x = 0, ed_y = 0;printf("PLEASE ENTER THE MAZE SIZE:\n");scanf("%d",&L);if (L<=50) {SEE_MAP=1;}srand((unsigned)time(NULL));int **Maze=(int**)malloc(L*sizeof(int*));for(int i=0;i<L;i++){Maze[i]=(int*)calloc(L,sizeof(int));}//外侧一圈为墙for(int i=0;i<L;i++){Maze[0][i]=WALL;Maze[i][0]=WALL;Maze[L-1][i]=WALL;Maze[i][L-1]=WALL;}//生成迷宫CreateMaze(Maze, 1,1, L-2, L-2);//设置出口Maze[1][0]=ROUTE;Maze[L-2][L-1]=ROUTE;//画迷宫FILE *fpWrite=fopen("maze.txt","w");int BMPSIZE = 0;BMPSIZE = L;while(BMPSIZE%4) {BMPSIZE++;}//Write size and startpointfprintf(fpWrite,"%d\n",BMPSIZE);fprintf(fpWrite,"[1,0]\n");//print blocksint i = 0, j = 0;int ruler[] = {0,1,2,3,4,5,6,7,8,9};int len = 0, count = 0;if(SEE_MAP){printf("      ");for (count=0;count<L;count++) {printf("%2d",ruler[len++]);if (len==10) {len=0;}}printf("\n");len=0;for(i=0;i<L;i++){printf("   %2d ",ruler[len++]);if (len==10) {len=0;}for(j=0;j<L;j++){if(Maze[i][j]==WALL){if(SEE_MAP) {printf("##");}}else{if(SEE_MAP) {printf("  ");}}}if(SEE_MAP) {printf("\n");}}}printf("KEEP DEFAULT ENDPOINT?(0:n/1:y)?:\n");scanf("%d",&DEFAULT_START_POINT);//Write endpointif (!DEFAULT_START_POINT){printf("PLEASE ENTER THE END POINT [X,Y]\n");while (1) {scanf("%d,%d",&ed_x, &ed_y);if ((ed_x>=0)&&(ed_y>=0)&&(ed_x<L)&&(ed_y<L)&&(Maze[ed_x][ed_y]!=WALL)){fprintf(fpWrite,"[%d,%d]\n",ed_x, ed_y);printf("\nDone!\n");break;}else{printf("INVALID VALUE, ENTER AGAIN.\n");}}}else {//default endpointfprintf(fpWrite,"[%d,%d]\n", DEFAULT_END_X, DEFAULT_END_Y);}//Write block locationfor(int i=0;i<L;i++){for(int j=0;j<L;j++){if(Maze[i][j]==WALL){fprintf(fpWrite,"[%d,%d]\n",i,j);}}}fprintf(fpWrite,"$");fclose(fpWrite);for(int i=0;i<L;i++) free(Maze[i]);free(Maze);return 0;
}
gcc -Wall -o maze.exe maze.c

编译上面的

//maze_solver.c
/*
The input of this maze solver program is a txt file named maze.txt, which should
be created by maze.exe.
In a format of
1: The first line is one int number indicates the height and width of the maze.
2: The second and third line contains one [x,y], indicates the start and the end
point of the maze.
3: The rest of the line indicates the location of blocks in the maze
4: The last line of the file is a '$' symbol which indicates the end of the
block data, and for further data appending.This program use BFS to find the route of any given sized square maze.
And append route and space [x,y] coordinates to maze.txt which seperated by
a '$' symbol. Then the maze.txt file is ready to be read into bmp.exe to creat
the bmp image of the whole maze and its route.
*/#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>#define TOTAL_TIME 3000 //mili seconds to print the map
#define SPACE_CODE 0
#define BLOCK_CODE -1
#define LENC sizeof(struct coordinate)
#define LENQ sizeof(struct queue)
#define BLOCKSYMBOL "█"
#define ARROWSYMBOL "人"
#define ROUTESYMBOL "卐"
struct coordinate {int x;int y;struct coordinate * next;
};struct queue {int x, y;int pre_x, pre_y;struct queue * next;
};int SEE_REPAIRED_MAP = 1;
int ROUTE_CODE = 1;
int size = 0;
int count_blocks = 0, count_routes = 0;
int start_x = 0, start_y = 0, end_x = 0, end_y = 0;void do_head(void);
void hidden(void);              //To hide the cursor
void gotoxy(int x, int y);  //Move the coordinate to print the route
void data2txt(int ** grid); //Write data into a txt file for creating the bmp image
void print_maze(int ** grid);   //Show the maze only, with no route
int ** grid_initializer(int size);//Initialize the maze 2D grid
void grid_check(int ** grid);   //Validate some critical points before BFS
//Store coordinate [x, y] only
struct coordinate * creat(void);
//Store coordinate with previous value, bring out BFS
struct queue * creat_queue(struct coordinate * block);
//Linkedlist reversing function
struct queue * ReverseLink(struct queue * allqueue);
struct coordinate * ReverseLink_C(struct coordinate*repaired_route);
//Append items to a linkedlist
struct coordinate * append(struct coordinate * repaired_route,int x, int y);
int valid_queue(struct queue * list, int x, int y, int count, struct coordinate * block);
/******************************************************************************/void do_head(void) {float rate = 0, x, y;x = size * size;y = count_blocks;rate = y / x;printf("================================================\n""The grid has %d rows and %d columns.\n""The grid has %d block(s). (block rate:%4.2f%%)\n""The initial cell in the grid is [%d,%d].\n""The goal cell in the grid is [%d,%d].\n""================================================\n\n",size, size, count_blocks, rate, start_x, start_y, end_x, end_y);if (size>140){SEE_REPAIRED_MAP = 0;printf("THE MAP IS TOO LARGE TO SHOW\nPLEASE WAIT A FEW SECONDS\n");printf("loading the route......\n\n");}
}//To hide the cursor
void hidden(void) {HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO cci;GetConsoleCursorInfo(hOut, &cci);cci.bVisible = 0; /*1 show cursor, 0 hide cursor*/SetConsoleCursorInfo(hOut, &cci);
}//Move the coordinate to print the route
void gotoxy(int x, int y) {COORD pos = { x, y };HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOut, pos);/* which console and its position*/
}//Write data into a txt file for creating the bmp image
void data2txt(int **grid) {int i = 0, j = 0;FILE *fpWrite1 = fopen("maze.txt","a");fprintf(fpWrite1,"\n");//Store routefor (i=0;i<size;i++) {for (j=0;j<size;j++) {if ((end_x == i)&&(end_y == j)) {fprintf(fpWrite1,"[%d,%d]\n",i,j);}else if ((start_x == i)&&(start_y == j)) {fprintf(fpWrite1,"[%d,%d]\n",i,j);}else if (grid[i][j] > 0) {fprintf(fpWrite1,"[%d,%d]\n",i,j);}}}//Store spacefprintf(fpWrite1,"$\n");for (i=0;i<size;i++) {for (j=0;j<size;j++) {if (grid[i][j] == SPACE_CODE) {fprintf(fpWrite1,"[%d,%d]\n",i,j);}}}fclose(fpWrite1);
}void print_maze(int ** grid) {int i = 0, j = 0;int ruler[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};int len = 0, count = 0;printf("      ");for (count=0;count<size;count++) {printf("%2d", ruler[len++]);if (len == 10) {len = 0;}}printf("\n");len = 0;for (i=0;i<size;i++){printf("   %2d ",ruler[len++]);if (len == 10) {len = 0;}for (j=0;j<size;j++) {if (grid[i][j] == BLOCK_CODE) {printf("%s", BLOCKSYMBOL);}else{printf("  ");}}printf("\n");}
}int ** grid_initializer(int size){int i,j;                    int ** grid = (int **) malloc(sizeof(int *) * size);for (i = 0; i < size; i ++) {grid[i] = (int *) malloc(sizeof(int) * size);for (j = 0; j < size; j ++) {grid[i][j] = SPACE_CODE;}}return grid;
}struct coordinate * creat(void) {int n = 0, ch = 0;struct coordinate * head = NULL;struct coordinate * p1 = NULL;struct coordinate * p2 = NULL;p1 = p2 = (struct coordinate *)malloc(LENC);scanf("[%d,%d]\n", &p1->x, &p1->y);ch = getchar();while (ch != '$') {n += 1;if (n == 1) {head = p1;}else {p2->next = p1;}p2 = p1;p1 = (struct coordinate *)malloc(LENC);scanf("%d,%d]\n", &p1->x, &p1->y);ch = getchar();}p2->next = p1;p1->next = NULL;return head;
}struct queue * creat_queue(struct coordinate*block) {struct queue * list = NULL;struct queue * head = NULL;struct queue * current = NULL;struct queue * ptr = NULL;current = (struct queue *)malloc(LENQ);int i = 0, total = 0;list = current;head = current;current->x = start_x; current->y = start_y;current->pre_x = -1; current->pre_y = -1;ptr = (struct queue *)malloc(LENQ);head->next = ptr;head = ptr;total++;while((current->x!=end_x) || (current->y!=end_y)) {for (i=0;i<4;i++) {//4 directionsif (i == 0 && valid_queue(list, current->x-1, current->y, total, block)){ptr->x = current->x-1;ptr->y = current->y;}else if (i == 1 && valid_queue(list, current->x+1, current->y, total, block)){ptr->x = current->x+1;ptr->y = current->y;}else if (i == 2 && valid_queue(list, current->x, current->y-1, total, block)){ptr->x = current->x;ptr->y = current->y-1;}else if (i == 3 && valid_queue(list, current->x, current->y+1, total, block)){ptr->x = current->x;ptr->y = current->y+1;}else {continue;}ptr->pre_x = current->x;ptr->pre_y = current->y;ptr = (struct queue *)malloc(LENQ);head->next = ptr;head = ptr;total++;}current = current->next;}current->next = NULL;return list;
}struct queue * ReverseLink(struct queue * allqueue) {struct queue * next;struct queue * prev = NULL;while(allqueue != NULL) {next = allqueue->next;allqueue->next = prev;prev = allqueue;allqueue = next;}return prev;
}struct coordinate * ReverseLink_C(struct coordinate * repaired_route) {struct coordinate * next;struct coordinate * prev = NULL;while(repaired_route != NULL) {next = repaired_route->next;repaired_route->next = prev;prev = repaired_route;repaired_route = next;}return prev;
}struct coordinate * append(struct coordinate * repaired_route,int x, int y) {count_routes++;struct coordinate * ptr = NULL;struct coordinate * p1 = NULL;p1 = ptr = repaired_route;if (repaired_route==NULL) {repaired_route = (struct coordinate *)malloc(LENC);repaired_route->x = x; repaired_route->y = y;repaired_route->next = NULL;}else{while(p1->next != NULL) {p1 = p1->next;}ptr = p1;p1 = (struct coordinate *)malloc(LENC);p1->x = x; p1->y = y;ptr->next = p1;p1->next = NULL;}return repaired_route;
}int valid_queue(struct queue * list, int x, int y, int count, struct coordinate*block) {struct queue * ptr = NULL;struct coordinate*ptr_b = NULL;ptr = list;ptr_b = block;while (count!=0) {count--;if ((x==ptr->x)&&(y==ptr->y)) {return 0;}ptr = ptr->next;}if (!((0<=x)&&(x<size)&&(0<=y)&&(y<size))) {return 0;}while (ptr_b!=NULL) {if ((x==ptr_b->x)&&(y==ptr_b->y)){return 0;}ptr_b = ptr_b->next;}return 1;
}void grid_check(int **grid) {if (grid[start_x][start_y]||grid[end_x][end_y]||start_x<0 \||start_x>=size||start_y<0||start_y>=size|| \end_x<0||end_x>=size||end_y<0||end_y>=size){printf("START OR END POINT IS INVALID!\nMAZE SOLVER FAILED!");exit(0);}
}int main(int argc, char *argv[])
{   system("COLOR 00");scanf("%d\n", &size);    //read in datascanf("[%d,%d]\n", &start_x, &start_y);scanf("[%d,%d]\n", &end_x, &end_y);int ** grid = grid_initializer(size);struct coordinate*block = NULL;struct coordinate*tmp_b = NULL;block = creat();tmp_b = block;while (block != NULL) {count_blocks++;grid[block->x][block->y] = BLOCK_CODE;block = block->next;}block = tmp_b;grid_check(grid);do_head();int pre_x = 0, pre_y = 0;struct queue*allqueue = NULL;struct coordinate*repaired_route = NULL;allqueue = creat_queue(block);allqueue = ReverseLink(allqueue);//The first route coordgrid[allqueue->pre_x][allqueue->pre_y] = ROUTE_CODE;ROUTE_CODE++;repaired_route=append(repaired_route, allqueue->pre_x,allqueue->pre_y);pre_x = allqueue->pre_x; pre_y = allqueue->pre_y;for(;;) {if ((allqueue->x==pre_x)&&(allqueue->y==pre_y)) {repaired_route=append(repaired_route, allqueue->pre_x, allqueue->pre_y);//The second and moregrid[allqueue->pre_x][allqueue->pre_y] = ROUTE_CODE;ROUTE_CODE++;pre_x = allqueue->pre_x; pre_y = allqueue->pre_y;if ((pre_x == start_x)&&(pre_y == start_y)) {break;}}allqueue = allqueue->next;}int refresh = 0;refresh = TOTAL_TIME / count_routes;repaired_route=ReverseLink_C(repaired_route);if(SEE_REPAIRED_MAP){system("COLOR 70");int prex = 8, prey = 1, first = 0;hidden();system("cls");print_maze(grid);while (repaired_route != NULL) {if(first){gotoxy(prex,prey);printf("%s", ROUTESYMBOL);}//The routefirst=1;gotoxy(6+((repaired_route->y)*2), (repaired_route->x)+1);prex=6+((repaired_route->y))*2;prey=(repaired_route->x)+1;printf("%s", ARROWSYMBOL);   //DirectionSleep(refresh);repaired_route = repaired_route->next;}gotoxy(prex+2, prey);printf("☆");   //Reach the end of the mazegotoxy(6+((size)*2), (size)+1);printf("\n");}data2txt(grid);printf("\n");for (unsigned int i = 0; i < size; i ++) {free(grid[i]);}free(grid);return 0;
}

编译gcc -Wall -O3 -o maze_solver.exe maze_solver.c
/************************************************************************************/
/************************************************************************************/

主文件夹中的copy.bat是自动运行源代码文件夹中编译的批处理文件并且把exe复制过来的,我已经弄好了,所以不需要点它。

点击[RUN].bat运行!
谢谢大噶!!!!!!

https://pan.baidu.com/s/1ql-fy9V_vmhQp2huFWhshw
迷宫游戏百度网盘在此

任意大小迷宫自动生成+BFS寻路+生成无损迷宫bitmap(.BMP)图片相关推荐

  1. 如何下载高清卫星地图/历史影像(任意大小、自动拼接、高清晰)

    如何下载高清卫星地图/历史影像(任意大小.自动拼接.高清晰) 同步视频教程:如何下载卫星图像 矢量道路路网.水系如何下载? 如何下载使用等高线地形图? 1.BIGEMAP地图下载器提供了全世界主流地图 ...

  2. js迷宫自动走html,JavaScript简单实现迷宫问题求解

    前言 想起大学时老师让用Java GUI解决迷宫问题,当时还真给做出来了,可惜代码不见了 预览 介绍 使用JavaScript解决迷宫问题(使用vue-cli@3搭建环境),使用深度优先搜索算法计算所 ...

  3. 利用libqrencode生成二维码并保持成bmp图片

    点击打开原文链接 QR code二维码简介及Qrencode库的移植与使用 //QRGenerator.h #pragma once#include <string>using std:: ...

  4. 在Word中调整图片大小会自动改变怎么办?

    在Word中调整图片大小会自动改变怎么办? 在Word中有多个图片,需要调整到大小一致,可是拉动.或者设置图片大小后,图片会自动改变,始终无法将所有图片调到大小一致. 别担心 鼠标右键点击图片 选择大 ...

  5. java动画迷宫寻路_[人工智能] 迷宫生成、寻路及可视化动画

    前言 数据结构准备 迷宫生成算法 迷宫寻路算法 前言 本次带来迷宫相关的算法,迷宫的算法涉及到不少经典的图论算法,在游戏中NPC这些算法被大量的运用,深入了解和学习这些算法是为开发游戏打下坚实的基础. ...

  6. unity3d 自动变化大小_自动做游戏(1),自动生成人物侧面图

    文 @罗培羽 效果 游戏美术成本很高,如果能够应用一些深度学习的方法,让机器自动生成美术资源,那么游戏开发将会变得简单.尝试制作一个应用,根据人物正面图自动生成侧面图.效果如下图,对于像素类图片,效果 ...

  7. 基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(v6.9.0版)

    TableGo_20200520 v6.9.0 正式版发布,此次版本更新如下:           1.新增对JDK9及以上版本Java环境的支持           2.生成JavaBean更名为生 ...

  8. mysql javabean 工具_基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(v6.9.0版)...

    TableGo_20200520 v6.9.0 正式版发布,此次版本更新如下: 1.新增对JDK9及以上版本Java环境的支持 2.生成JavaBean更名为生成数据模型并且提供了C#.C++.Gol ...

  9. c语言随机prim算法的迷宫生成,Prim算法生成迷宫

    初始化地图 function initMaze(r,c){ let row = new Array(2 * r + 1) for(let i = 0; i < row.length; i++){ ...

最新文章

  1. tensorflow tf.Variable 的用法
  2. 三个python文件怎么关联___name__= __main__怎么解释 怎么用 另外两个py文件之间的互动关联...
  3. UVA208Firetruck 消防车(图的路径搜索)
  4. mysql explain的使用
  5. NLP复习资料(2)-三~五章:形式语言、语料库、语言模型
  6. 在Visual C++中用ADO进行数据库编程(中)
  7. 崩坏3服务器维护2月8号,《崩坏3》8月29日版本更新,全服维护通知
  8. antd upload手动上传_基于MVVCTP5的文件上传
  9. python中open打开路径问题_Python学习笔记之open()函数打开文件路径报错问题
  10. PDF在线预览 (flexpaper+swftools+saveaspdfandxps)
  11. 计算机必须设置默认打印机,win10系统禁止更改默认打印机设置的还原技巧
  12. 十二星座、超完美解析!
  13. 公寓宽带服务器无响应,利用RLDP协议解决网络环路故障
  14. Android 实现自定义宽高比的ImageView
  15. 控件的颜色设置(本景色,文本色,文本背景色)
  16. 安卓基础学习 Day 6|常用控件---列表视图+古诗查看
  17. 线性回归—求解介绍及回归扩展
  18. 水墨风格化matlab,调色进阶篇:如何调出浓水墨风格?
  19. Windows 8系统中LOL登陆错误出现的服务器未响应怎么处理?
  20. javase 双色球选7球 红球在【1-36】之间,选出6个,且不能重复 篮球在【1-16】之间,选出1个

热门文章

  1. pytorch的代码 CPU改为GPU
  2. nodejs+vue+elementui婚纱影楼摄影拍照网站python java
  3. Docker-compose与consul
  4. 线段树简单入门 (含普通线段树, zkw线段树, 主席树)
  5. 35岁程序员转行,跟老婆一起做外贸,半年净利润70多万
  6. winds开放指定端口
  7. 华为手机备份app从内部恢复
  8. c 语言整人代码大全,C 语言整人代码大全.doc
  9. Error 1935 错误!
  10. 番外篇:因为一个固态导致的——系统重装与JAVA软件环境下载安装配置