博客园 首页 私信博主 回到顶部 联系博主
(仅pc端)
管理 换背景图

Bug迷宫(栈、回溯、DFS)

编制一个求解迷宫通路的图形界面演示程序。
问题描述:
1) 输入一个任意大小的迷宫,任设起点、终点、障碍,用栈求出一条走出迷宫的路径,并显示在屏幕上。
2) 根据用户界面提示,用键盘输入。Home 键设置迷宫起点,End 键设终点,上下左右箭头键移动,Enter 键添加墙,Del 键删除墙,完成后按 F9键演示,Esc 键退出。
3)橙色的实心小圆圈表示起点,绿色实心圆圈表示终点,空心圆圈表示足迹,红色方块表示墙。
4)本程序只求出一条成功的通路,但若对求解函数 MazePath 稍加更改即可求得全部路径。此外,因受图形界面限制,不能保存或载入测试文件(此功能可在 Maze_text 中实现)。
5)当未输入起点时,消息显示“Error: You must set Startplace.”;
未输入终点时,显示“Error: You must set Endplace.” 找到路径时,
屏幕显示足迹,并在消息框出现 Path found,否则消去足迹,显示 Path not found.

#include<stdio.h>
#include<malloc.h>
#include <conio.h>
#include<time.h>
#include<Windows.h>
#include <graphics.h>
#define size 15

typedef struct {
	int i;
	int j;
	int di;
}Box;

void mazepath();
void drawload(Box* st,int top);
void mademap();
void create();
void keyboard();
void draw_s();
void del();
void enter();
void home();
void end();
void f9();
void init_map();
void close();
void error();
void help();
void P(int* n);

int w, h, x, y, homenum, endnum,flag_x=0;
int** map;

int main(){
	mademap();

	while (1) {
		keyboard();
		if (homenum == 1 && endnum == 1)
			mazepath();
		if (homenum == 0) {
			MessageBoxA(GetForegroundWindow(), TEXT("Error: You must set Startplace."), TEXT("错误!"), MB_OK);
		}
		if(endnum==0)
			MessageBoxA(GetForegroundWindow(), TEXT("Error: You must set Endplace."), TEXT("错误!"), MB_OK);
		for (size_t i = 0; i < h; i++)
			for (size_t j = 0; j < w; j++)
				if (map[i][j] == -1)
					map[i][j] = 0;
	}
}

void keyboard() {
	static char ch = 0;

	while (1)
	{
		draw_s();
		while (!kbhit());
		ch = _getch();
		if (ch == -32) {
			ch = _getch();
			switch (ch)
			{
			case 77:ch = 'd'; break;
			case 75:ch = 'a'; break;
			case 80:ch = 's'; break;
			case 72:ch = 'w'; break;
			default:
				break;
			}
		}
		if (ch == 'd' || ch == 'D') {
			if (x + 3 > w) {
				x = 1;
				continue;
			}
			x += 1;
		}
		if (ch == 'a' || ch == 'A') {
			if (x - 2 <= -1) {
				x = w - 2;
				continue;
			}
			x -= 1;
		}
		if (ch == 's' || ch == 'S') {
			if (y + 3 > h) {
				y = 1;
				continue;
			}
			y += 1;
		}
		if (ch == 'w' || ch == 'W') {
			if (y - 2 <= -1) {
				y = h - 2;
				continue;
			}
			y -= 1;
		}
		if (ch == 'x' || ch == 'X') {
			flag_x = (flag_x + 1) % 2;
			MessageBoxA(GetForegroundWindow(), TEXT("模式已更改"), TEXT("提示"), MB_OK);
		}
		if (ch == 'H' || ch == 'h')
			help();
		if (ch == 71)
			home();
		if (ch == 79)
			end();
		if (ch == 13)
			enter();
		if (ch == 8)
			del();
		if (ch == 59)
			init_map();
		if (ch == 'u' || ch == 'U')
			create();
		if (ch == 67) {
			f9();
			return;
		}
		if (ch == VK_ESCAPE)
			exit(0);
	}
}

void mademap() {
	double n;

	system("mode con cols=25 lines=5");
	help();
	printf("请输入你要生成的迷宫大小\n(需要算上迷宫周围墙体)\n");
	while (1) {
		printf("宽:");
		scanf("%lf", &n);
		w = (int)n;
		if (w > 4 && w == n)
		{
			break;
		}
		error();
	}
	while (1) {
		printf("高:");
		scanf("%lf", &n);
		h = (int)n;
		if (h > 4 && h == n)
		{
			break;
		}
		error();
	}
	map = (int**)malloc(sizeof(int*) * h);
	if (map == NULL) {
		MessageBoxA(GetForegroundWindow(), TEXT("内存不足!"), TEXT("错误!"), MB_OK);
		exit(0);
	}
	for (size_t i = 0; i < h; i++) {
		map[i] = (int*)malloc(sizeof(int) * w);
		if (map[i] == NULL) {
			MessageBoxA(GetForegroundWindow(), TEXT("内存不足!"), TEXT("错误!"), MB_OK);
			exit(0);
		}
	}

	init_map();
	x = y = 1;
}

void del() {
	map[y][x] = 0;
}

void enter() {
	map[y][x] = 1;
}

void home() {
	for (size_t i = 0; i < h; i++)
		for (size_t j = 0; j < w; j++)
			if (map[i][j] == 8)
				map[i][j] = 0;

	map[y][x] = 8;
}

void end() {
	for (size_t i = 0; i < h; i++)
		for (size_t j = 0; j < w; j++)
			if (map[i][j] == -8)
				map[i][j] = 0;

	map[y][x] = -8;
}

void f9(){
	homenum = endnum = 0;
	for (size_t i = 0; i < h; i++)
		for (size_t j = 0; j < w; j++) {
			if (map[i][j] == 8)
				homenum++;
			if (map[i][j] == -8)
				endnum++;
		}
}

void draw_s() {
	static int flag = 0;

	if (flag == 0) {
		initgraph(w * size + 1, h * size + 1 + 30);
		settextcolor(WHITE);
		settextstyle(13, 0, _T("宋体"));
		outtextxy(0, h * size + 3, "找到路径(条):");
		flag = 1;
	}

	for (size_t i = 0; i < h; i++)
		for (size_t j = 0; j < w; j++)
		{
			if (x == j && y == i) {
				setfillcolor(YELLOW);
				fillrectangle(j * size, i * size, (j + 1) * size, (i + 1) * size);
				continue;
			}
			if (map[i][j] == 0) {
				clearrectangle(j * size, i * size, (j + 1) * size, (i + 1) * size);
			}
			if (map[i][j] == 1) {
				setfillcolor(RED);
				fillrectangle(j * size, i * size, (j + 1) * size, (i + 1) * size);
			}
			if (map[i][j] == 8) {
				setfillcolor(0x0099FF);
				fillcircle(j * size + (size / 2), i * size + (size / 2), size / 2);
			}
			if (map[i][j] == -8) {
				setfillcolor(GREEN);
				fillcircle(j * size + (size / 2), i * size + (size / 2), size / 2);
			}
		}
}

void init_map() {
	for (size_t i = 0; i < h; i++)
		for (size_t j = 0; j < w; j++) {
			map[i][j] = 0;
			if (i == 0 || j == 0||i==h-1||j==w-1) {
				map[i][j] = 1;
			}
		}
}

void close() {
	closegraph();
	for (size_t i = 0; i < h; i++)
		free(map[i]);
	free(map);
	exit(0);
}

void error() {
	MessageBoxA(GetForegroundWindow(), TEXT("请规范输入!"), TEXT("错误!"), MB_OK);
}

void help() {
	MessageBoxA(GetForegroundWindow(), TEXT("F1重置地图 F9开始寻路 ESC退出程序 Enter设置墙 Delete删除墙 P中止寻路\nX改变寻路模式 Home设置启点 End设置终点 U生成随机地图 H帮助 方向键控制移动"), TEXT("帮助"), MB_OK);
}

void mazepath(){
	FILE* f = NULL;
	Box* st = NULL, * shortload = NULL;
	int i = 0, j = 0, di = 0, i1 = 0, j1 = 0, top = -1, xe = 0, ye = 0, shorttop = -1, flag_h = 0;
	long long int x = 0;
	bool find = 0;
	char s[10] = { NULL };
	st = (Box*)malloc(sizeof(Box) * w * h);
	if (st==NULL)
	{
		MessageBoxA(GetForegroundWindow(), TEXT("内存不足!"), TEXT("错误!"), MB_OK);
		close();
	}
	if (flag_x==1)
	{ 
		f = fopen("maze_text.txt","w");
		if (f == NULL) {
			MessageBoxA(GetForegroundWindow(), TEXT("创建文件失败!"), TEXT("错误!"), MB_OK);
			free(st);
			close();
		}
		shortload= (Box*)malloc(sizeof(Box) * w * h);
		if (shortload == NULL)
		{
			MessageBoxA(GetForegroundWindow(), TEXT("内存不足!"), TEXT("错误!"), MB_OK);
			free(st);
			fclose(f);
			close();
		}
	}

	for (size_t i2 = 0; i2 < h; i2++)
		for (size_t j2 = 0; j2 < w; j2++) {
			if (map[i2][j2] == 8) {
				top++;
				st[top].i = j2; st[top].j = i2; st[top].di = -1;
			}
			if (map[i2][j2] == -8) {
				xe = j2; ye = i2;
			}
		}
	
	HANDLE handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)P,&flag_h, 0, 0);flag_h = 1;

		while (top != -1) {
			i = st[top].i; j = st[top].j; di = st[top].di;
			if (i == xe && j == ye) {
				if (flag_x == 0) {
					x++;
					sprintf(s, "%d", x);
					outtextxy(83, h * size + 3, s);

					flag_h = 0;
					CloseHandle(handle);
					MessageBoxA(GetForegroundWindow(), TEXT("Path found"), TEXT("提示!"), MB_OK);
					drawload(st, top);
					free(st);
					return;
				}
				else {
					fprintf(f, "路径:");
					for (size_t n = 0; n <= top; n++)
						fprintf(f, "(%d,%d)", st[n].i, st[n].j);
					fprintf(f, "\n");

					if (x == 0)
						shorttop = top;

					x++;
					sprintf(s, "%d", x);
					outtextxy(83, h * size + 3, s);

					if (top <= shorttop) 
						for (size_t n = 0; n <= top; n++) {
							shortload[n].i = st[n].i; shortload[n].j = st[n].j; shortload[n].di = st[n].di;
							shorttop = top;
						}

					top--;
					map[st[top].j][st[top].i] = -1;
					i = st[top].i; j = st[top].j; di = st[top].di; i1 = j1 = 0;
					find = 0;
				}
			}
			else
				find = 0;
			while (di < 4 && !find) {
				di++;
				switch (di) {
				case 0:i1 = i - 1; j1 = j; break;
				case 1:i1 = i; j1 = j + 1; break;
				case 2:i1 = i + 1; j1 = j; break;
				case 3:i1 = i; j1 = j - 1; break;
				}
				if (map[j1][i1] == 0 || map[j1][i1] == -8)find = 1;
			}
			if (find) {
				st[top].di = di;
				top++;
				st[top].i = i1; st[top].j = j1; st[top].di = -1;
				if (map[st[top].j][st[top].i] != 8 && map[st[top].j][st[top].i] != -8)map[j1][i1] = -1;
			}
			else {
				if (map[st[top].j][st[top].i] == 8) top--;
				else {
					map[st[top].j][st[top].i] = 0;
					top--;
				}
			}
			if (flag_h == 0)
				break;
		}

		flag_h = 0;
		free(st);
		CloseHandle(handle);
		if (flag_x == 0)
			MessageBoxA(GetForegroundWindow(), TEXT("Path not found"), TEXT("提示!"), MB_OK);
		else {
			fprintf(f, "共%d条路",x);
			fclose(f);
			MessageBoxA(GetForegroundWindow(), TEXT("所有路径添加到maze_text"), TEXT("提示!"), MB_OK);
			MessageBoxA(GetForegroundWindow(), TEXT("即将输出已知最短路径,若无路径将不输出"), TEXT("提示!"), MB_OK);
			if (x > 0)
				drawload(shortload, shorttop);
			free(shortload);
		}
}

void create() {
	init_map();
	srand(time(NULL));
	for (size_t i = 1; i < h - 1; i++) 
		for (size_t j = 1; j < w - 1; j++) {
			map[i][j] = rand() % 2;
			if (rand() % 2 == 1)
				j++;
		}
}

void P(int *x) {
	int i = 4;
	char ch = 0;

	outtextxy(0, h * size + 17, "正在寻路");
	setfillcolor(BLUE);
	while (*x!=0) {
		if (kbhit()) {
			ch = getch();
			if (ch == 'p' || ch == 'P') {
				*x = 0;
				MessageBoxA(GetForegroundWindow(), TEXT("寻路中止"), TEXT("提示"), MB_OK);
			}
		}
		fillrectangle(i * size, h * size + 20, (i + 1) * size + 2, h * size + 25);
		Sleep(300);
		if (i > w - 3) {
			clearrectangle(4 * size - 1, h * size + 19, w * size , h * size + 26);
			i = 3;
		}
		i++;
	}
	clearrectangle(4 * size - 1, h * size + 19, w * size, h * size + 26);
	outtextxy(0, h * size + 17, "完成寻路");
}

void drawload(Box *st,int top) {
	clearrectangle(x * size, y * size, (x + 1) * size, (y + 1) * size);
	if (map[y][x]==1)
	{
		setfillcolor(RED);
		fillrectangle(x * size, y * size, (x + 1) * size, (y + 1) * size);
	}
	if (map[y][x] == 8) {
		setfillcolor(0x0099FF);
		fillcircle(x * size + (size / 2), y * size + (size / 2), size / 2);
	}
	if (map[y][x] == -8) {
		setfillcolor(GREEN);
		fillcircle(x * size + (size / 2), y * size + (size / 2), size / 2);
	}

	int i = 1;
	while (1) {
		circle(st[i].i * size + (size / 2), st[i].j * size + (size / 2), size / 2);
		if (i == top)
			break;
		i++;
		Sleep(100);
	}
	while (!kbhit());
	draw_s();
}

ps:画图机制可改进

posted @ 2020-12-28 15:15  温一壶白开  阅读(163)  评论(0编辑  收藏  举报