C语言 迷宫问题 (广度优先算法)

运行结果
本来是想用esayx写的 发现好像用不着,直接改的窗口背景颜色做的,后来还改进了鼠标绘制地图 ,地图大小可以设置,寻路的过程也可以设置放慢的速度,作为大一的一个实践小项目,第一次发csdn,和大家一起分享。

#include<cstdio>
#include<stdlib.h>
#include<windows.h> 
#include<conio.h>

#define RED 	1
#define YELLOW 	21
#define HYELLOW 22
#define GREEN 	3
#define HGREEN  32
#define BLUE 	4
#define PURPLE	5
#define GRAY	6
#define BLACK	7
#define WHITE	8

#define START	1
#define END		-2
#define	WALL	-1
#define WAY		0 

#define YES		1
#define NO		0
#define SLEEPTIME 0
struct Size{//尺寸 
	int width;
	int height;	
};
struct MazeMap{//地图 
	Size size;
	short** EachLine;//该数组存放每一行的头指针 
}; 
struct NodeIndex{//作为坐标标记出入队列 
	int X;
	int Y;
	NodeIndex* nextnode;
};
struct Queue{//链队列 
	NodeIndex* head;
	NodeIndex* tail;
	int num;
};
void InitDataQueue(Queue &indexqueue){//初始化队列 
	indexqueue.head = NULL;
	indexqueue.tail = NULL;
	indexqueue.num = 0;
} 
NodeIndex OutputData(Queue &indexqueue){
	NodeIndex nodeindex;
	NodeIndex* p;
	nodeindex.nextnode = NULL;
	nodeindex.X = -1;
	nodeindex.Y = -1;
	if(indexqueue.num == 0){
		return nodeindex;
	}
	nodeindex = *indexqueue.head;
	p = indexqueue.head->nextnode;
	free(indexqueue.head);
	indexqueue.head = p;
	indexqueue.num--;
	return nodeindex;
}
void InputData(Queue &indexqueue,NodeIndex nodeindex){//尾插法直接数据入队 
	NodeIndex* p;
	p = (NodeIndex*)malloc(sizeof(NodeIndex));
	if(p == NULL){
		printf("系统忙,无法运行\n"); 
		exit(-1);
	}
	*p = nodeindex;
	p->nextnode = NULL;
	if(indexqueue.num == 0){
		indexqueue.tail = p;
		indexqueue.head = indexqueue.tail;
	}else{
		indexqueue.tail->nextnode = p;
		indexqueue.tail = p;
	}
	indexqueue.num++;
}
void InitMazeMap(MazeMap &mazemap,Size size){//初始化地图数据 
	mazemap.size = size;
	mazemap.EachLine = (short**)malloc(sizeof(short*)*size.height);
	if(mazemap.EachLine == NULL){
		printf("系统忙,无法运行\n"); 
		exit(-1);
	}
	short** p,start;
	p = mazemap.EachLine; 
	for(int i=0;i<size.height;i++){
		*p = (short*)malloc(sizeof(short)*size.width);
		if(p == NULL){
			printf("系统忙,无法运行\n"); 
			exit(-1);
		}
		p++;
	}
	short* to_p;
	p = mazemap.EachLine;
	to_p = *p;
	for(int i=0;i<size.height;i++){
		for(int j=0;j<size.width;j++){
			if(i==0 || i==size.height-1 ||j==0 || j==size.width-1){
				*to_p = WALL;
			}else{
				*to_p = WAY;	
			}
			//printf("%d ",*to_p);//调试用于查看数据和数据内存地址 
			to_p++;
		}
		//printf("\n");
		p++;
		to_p = *p;
	}
} 
void GoTo_XY(int x,int y){//移动光标的函数 
	HANDLE handle_out;
	handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = {x*2,y};
	SetConsoleCursorPosition(handle_out,pos);
}
void Color(int color,HANDLE handle_out){//切换颜色函数 
	switch (color){
		case RED:{
			SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_INTENSITY ); 
			break;
		}
		case GREEN:{
			SetConsoleTextAttribute(handle_out,BACKGROUND_GREEN); 
			break;
		}
		case HGREEN:{
			SetConsoleTextAttribute(handle_out,BACKGROUND_GREEN|BACKGROUND_INTENSITY); 
			break;
		}
		case BLUE:{
			SetConsoleTextAttribute(handle_out,BACKGROUND_BLUE); 
			break;
		}
		case GRAY:{
			SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE);
			break;
		}
		case PURPLE:{
			SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_BLUE);
			break;
		}
		case YELLOW:{
			SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_GREEN);
			break;
		}
		case HYELLOW:{
			SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_INTENSITY);
			break;
		}
		case BLACK:{
			SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|COMMON_LVB_REVERSE_VIDEO);
			break;
		}
		case WHITE:{
			SetConsoleTextAttribute(handle_out,BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY);
			break;
		}
	}
}
POINT GetPosition(){//获取鼠标位置函数 
	POINT pxy ={0,0};
	LPPOINT pxyf = &pxy;
	GetCursorPos(pxyf);
	return pxy;
}
void SetTheWall(MazeMap &mazemap,Size size,HANDLE handle_out,POINT &start,POINT &end){
	int key = 0,Sset = 0,Eset = 0,statue = 1;
	int Rx = 0,Ry = 0;
		GoTo_XY(0,size.height+2);
		Color(WHITE,handle_out);
		printf("操作说明:                       \n");
		printf("1.按下空格的同时移动鼠标绘制地图 \n");
		printf("2.按下P键可以重新定位画笔位置    \n");
		printf("3.按下Enter键结束当前地图绘制    \n");
		printf("4.按下S键设置鼠标当前位置为起点  \n"); 
		printf("5.按下E键设置鼠标当前位置为终点  \n"); 
	POINT pxy ={0,0};
	GoTo_XY(0,0);
	Color(WHITE,handle_out);
	printf("[]<——将鼠标放到框内,双击键盘P键定位鼠标"); 
	fflush(stdin);
	while(_getch() != 112){
		GoTo_XY(0,0);
		printf("[]<——放到这里哦,双击P键定位鼠标				"); 
	}
	while(statue){
		key = _getch();
		pxy = GetPosition();
		switch (key){
			case 32:{//绘制墙体
				pxy.x = (pxy.x-Rx)/16;
				pxy.y = (pxy.y-Ry)/16;
				if(pxy.x<size.width && pxy.y<size.height){
					GoTo_XY(pxy.x,pxy.y);
					mazemap.EachLine[pxy.y][pxy.x] = -1;
					printf("  ");
				}
				break;
			}
			case 114:{//擦除
				pxy.x = (pxy.x-Rx)/16;
				pxy.y = (pxy.y-Ry)/16;
				if(pxy.x>0 && pxy.x<size.width && pxy.y<size.height && pxy.y>0){
					if(mazemap.EachLine[pxy.y][pxy.x] == START){
						Sset = 0;
					}else if(mazemap.EachLine[pxy.y][pxy.x] == END){
						Eset = 0;
					}
					mazemap.EachLine[pxy.y][pxy.x] = 0;
					GoTo_XY(pxy.x,pxy.y);
					Color(GRAY,handle_out);
					printf("  ");
					Color(WHITE,handle_out);
				}
				break;
			}
			case 112:{//鼠标定位 
				Rx = pxy.x;
				Ry = pxy.y;
				break;
			}
			case 115:{//起点绘制 
				if(Sset == 1){
					break;
				}
				pxy.x = (pxy.x-Rx)/16;
				pxy.y = (pxy.y-Ry)/16;
				if(pxy.x<size.width && pxy.y<size.height){
					start.x = pxy.x;
					start.y = pxy.y;
					mazemap.EachLine[pxy.y][pxy.x] = START;
					Color(BLUE,handle_out);
					GoTo_XY(pxy.x,pxy.y);
					printf(" S");
					Color(WHITE,handle_out);
					Sset = 1;
				}
				break;
			}
			case 101:{//终点绘制 
				if(Eset == 1){
					break;
				}
				pxy.x = (pxy.x-Rx)/16;
				pxy.y = (pxy.y-Ry)/16;
				if(pxy.x<size.width && pxy.y<size.height){
					end.x = pxy.x;
					end.y = pxy.y;
					mazemap.EachLine[pxy.y][pxy.x] = END;
					Color(YELLOW,handle_out);
					GoTo_XY(pxy.x,pxy.y);
					printf(" E");
					Color(WHITE,handle_out);
					Eset = 1;
				}
				break;
			}
			case 13:{
				if(Sset && Eset){
					statue = 0;
				}else{
					Color(WHITE,handle_out);
					GoTo_XY(0,0);
					printf("请设置起点终点!");
					Color(WHITE,handle_out);
					_getch(); 
				}
				break;
			}
		} 
		GoTo_XY(0,0);
		printf("[]当前位置:X:%d Y:%d key:%d(画笔不准可放到左边方框重定位)			",pxy.x,pxy.y,key);
	}
}

void PrintMap(MazeMap mazemap,HANDLE handle_out){//显示地图函数 
	Size size = mazemap.size;
	short** p;
	short* to_p;
	p = mazemap.EachLine;
	to_p = *p;
	for(int i=0;i<size.height;i++){
		GoTo_XY(0,i);
		for(int j=0;j<size.width;j++){
			if(*to_p == WAY){
				Color(GRAY,handle_out); 
				printf("  ");
			}else{
				Color(WHITE,handle_out); 
				printf("  ");
			}
			to_p++;
		}
		p++;
		to_p = *p;
	}
} 
void HideCursor(){//隐藏光标 
	CONSOLE_CURSOR_INFO cursor_info = {1,0};//第二个值为零隐藏
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info); 
} 
void SetHandle(HANDLE &handle_out,HANDLE &handle_in,Size size){//获取并设置窗口句柄 
	handle_out = GetStdHandle(STD_OUTPUT_HANDLE);//获得标准输出设备句柄
	handle_in = GetStdHandle(STD_INPUT_HANDLE);
	SMALL_RECT rc = {1,1,size.width*2,size.height+5};//设置窗口位置和大小	
	SetConsoleWindowInfo(handle_out,true,&rc);	//设置窗口信息,第二个参数为设置参数是否执行
}
void SetStartEnd(MazeMap &mazemap,POINT start,POINT end,HANDLE &handle_out){//设置出发点和终点 
	mazemap.EachLine[start.y][start.x] = START;
	Color(BLUE,handle_out);
	GoTo_XY(start.x,start.y);
	printf("S ");
	mazemap.EachLine[end.y][end.x] = END;
	Color(YELLOW,handle_out);
	GoTo_XY(end.x,end.y);
	printf("E ");
} 
int SrcMethod(MazeMap &mazemap,NodeIndex nodeindex,Queue &indexqueue,int drie){//找路的方法 
	int nodevalue = 0;						//Bug(1) [&]
	NodeIndex fblr[4] = {{0,1},{-1,0},{1,0},{0,-1}}; //分别对应上下左右 
	if(mazemap.EachLine[nodeindex.Y+(fblr[drie].Y)][nodeindex.X+(fblr[drie].X)] == END){
		return YES; 
	}
	if(mazemap.EachLine[nodeindex.Y+(fblr[drie].Y)][nodeindex.X+(fblr[drie].X)] == WAY ){
		mazemap.EachLine[nodeindex.Y+(fblr[drie].Y)][nodeindex.X+(fblr[drie].X)] = mazemap.EachLine[nodeindex.Y][nodeindex.X]+1;
		nodeindex.X = nodeindex.X+(fblr[drie].X);
		nodeindex.Y = nodeindex.Y+(fblr[drie].Y);
		GoTo_XY(nodeindex.X,nodeindex.Y);
		printf("  ");
		InputData(indexqueue,nodeindex);
		Sleep(SLEEPTIME);
	}
	return NO;
}
int FindThePeth(MazeMap mazemap,NodeIndex &endindex,NodeIndex &startindex,HANDLE &handle_out){
	int value[4] = {0};
	int i ,min,mark = 0;
	while(true){
		i=0;//(bug_2)注意每次归零,否则有情况不可达 
		value[0] = mazemap.EachLine[endindex.Y][endindex.X+1];//R
		value[1] = mazemap.EachLine[endindex.Y][endindex.X-1];//L
		value[2] = mazemap.EachLine[endindex.Y+1][endindex.X];//F
		value[3] = mazemap.EachLine[endindex.Y-1][endindex.X];//B
		while(value[i]<=0){//既然能够到达,必然有一个可走的(值大于0的点) 
			i++;
		}
		mark = i;
		min = value[i];
		for(i=0;i<4;i++){
			if(value[i] >0 && value[i]<min){
				mark = i;
				min = value[i];
			}
		}
		switch(mark){
			case 0:{
				endindex.X = endindex.X+1;
				break;
			}
			case 1:{
				endindex.X = endindex.X-1;
				break;
			}
			case 2:{
				endindex.Y = endindex.Y+1;
				break;
			}
			case 3:{
				endindex.Y = endindex.Y-1;
				break;
			}
		}
		if(endindex.X == startindex.X && endindex.Y == startindex.Y){
			return YES;
		}
		GoTo_XY(endindex.X,endindex.Y);
		Color(RED,handle_out);
		printf("  ");
		Sleep(SLEEPTIME);
	}
}
void DrawMap(MazeMap &mazemap){//测试用地图绘制 
	 
}
int main(){
	HANDLE handle_out,handle_in;
	MazeMap mazemap;
	Queue indexqueue; 
	Size map_size; 
	
	printf("请输入要生成的地图尺寸:\n");
	printf("宽度(10--50较为适宜):");
	scanf("%d",&map_size.width); 
	while(map_size.width<10 || map_size.width>50){
		printf("输入数据超出限制,请重新输入");
		scanf("%d",&map_size.width); 
	} 
	printf("高度度(10--50较为适宜):");
	scanf("%d",&map_size.height ); 
	while(map_size.height<10 || map_size.height>50){
		printf("输入数据超出限制,请重新输入");
		scanf("%d",&map_size.height); 
	}
	POINT start = {0,0};
	POINT end = {0,0}; 
	int srcstatue = NO,nodevalue = 0;
	SetHandle(handle_out,handle_in,map_size);
	HideCursor();
	InitMazeMap(mazemap,map_size);//初始化操作 
	InitDataQueue(indexqueue);
	for(int i=0;i<map_size.height+2;i++){//输出字符固定布局位置,否则拖动窗口大小会被刷新排版 
		GoTo_XY(map_size.width,i);
		Color(BLACK,handle_out);
		printf("|");
	}
	PrintMap(mazemap,handle_out);
	SetTheWall(mazemap,map_size,handle_out,start,end);
	
	NodeIndex nodeindex,startindex,endindex;
	nodeindex.X = start.x;
	nodeindex.Y = start.y; 
	startindex.X = nodeindex.X;
	startindex.Y = nodeindex.Y;
	endindex.X = end.x;
	endindex.Y = end.y;
	InputData(indexqueue,nodeindex);
	while(indexqueue.num != 0){
		nodeindex = OutputData(indexqueue);
		if(nodeindex.X != start.x || nodeindex.Y != start.y){
			Color(HYELLOW,handle_out);
			GoTo_XY(nodeindex.X,nodeindex.Y);
			printf("  ");
			Color(HGREEN,handle_out);	
		}
		if(SrcMethod(mazemap,nodeindex,indexqueue,0) == YES ){
			srcstatue = YES;
			break;
		}
		if(SrcMethod(mazemap,nodeindex,indexqueue,3) == YES ){
			srcstatue = YES;
			break;
		}
		if(SrcMethod(mazemap,nodeindex,indexqueue,2) == YES ){
			srcstatue = YES;
			break;
		}
		if(SrcMethod(mazemap,nodeindex,indexqueue,1) == YES ){
			srcstatue = YES;
			break;
		}
		
		GoTo_XY(0,map_size.height);
		Color(GREEN,handle_out);
		printf("当前可走节点个数:%d		 ",indexqueue.num);
	}
	if(srcstatue==YES){
		FindThePeth(mazemap,endindex,startindex,handle_out);
		GoTo_XY(0,map_size.height+1);
		printf("路径已找到			 ");
	}else{
		GoTo_XY(0,map_size.height+1);
		printf("出口不可达			");
	} 
		
		/*for(int i=0;i<map_size.height;i++){
		for(int j=0;j<map_size.width;j++){
			printf("%2d ",mazemap.EachLine[i][j]);//调试用于查看数据和数据内存地址 
		}
		printf("\n");
		}*/
		
	GoTo_XY(0,map_size.height+5);//运行结束以后恢复位置以及背景 
	Color(BLACK,handle_out);
	CloseHandle(handle_in);
	CloseHandle(handle_out); 
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值