可视化迷宫,适合课堂演示,纯c++

可视化迷宫,适合课堂演示(C++版)

完成时间:2018-11-12
编译器:Visual Studio 2017 或 Dev-cpp v5.11
运行环境:Windows系统


主要是锻炼一下自己写程序的能力,再配合老师在课堂上讲解,顺便装个13(逃) ,于是制作出了这个适合演示的程序,欢迎各位提建议
PS:我真的懒 ,就不写太多注释了……
PPS:迷宫是通过递归算法生成的,思路如下图(这张图是别人的博客上截下来的,非原创)所示,只不过我最后还随机挖掉了16%的墙,以便于产生不止一条通路…算法原链接:https://blog.csdn.net/juzihongle1/article/details/73135920/
PPPS:有想法欢迎讨论,我的QQ:1783952099,目前南航本科大二

可视化迷宫,适合课堂演示,纯c++_第1张图片

部分运行截图如下:
可视化迷宫,适合课堂演示,纯c++_第2张图片
可视化迷宫,适合课堂演示,纯c++_第3张图片
可视化迷宫,适合课堂演示,纯c++_第4张图片
可视化迷宫,适合课堂演示,纯c++_第5张图片


代码如下:

#include 
#include 
#include 
#include 
#include 
using namespace std;
#pragma warning(disable:4996) //这一行是为了能在 Visual Studio 2017内使用getch()函数

#define WALLSTR   "█"
#define UPSTR     "∧"
#define DOWNSTR   "∨"
#define LEFTSTR   "<"
#define RIGHTSTR  ">"
//以上特殊符号是在手心输入法的特殊符号表里面找到的,因为不会写真的图形界面……(菜哭)
#define BLANKSTR  "·"//就是个全角的点
#define DEADSTR   "X"//全角的大写的英文字母x
#define DEAD        -1
#define DELAY       50
#define UP          10
#define DOWN        20
#define LEFT        30
#define RIGHT       40
#define ORIGINAL    0
#define WALL        1
#define ROAD        2
//以上用来标记地图
struct POSITION
{
	int x, y;
};

struct QUEUE
{
	int x, y;
	int PreSub;
};

HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
int MaxLine = 38, MaxColume = 38;//不建议修改这个
int map[50][50] = { 0 };
POSITION Stack[2500] = { {0,0} };
QUEUE Queue[2500] = { {0,0,0} };
int head = -1, tail = -1, top = -1;

void SetPosition(int line, int col)//更改光标的位置
{
	static COORD coord;
	coord.X = col * 2;
	coord.Y = line;
	SetConsoleCursorPosition(hout, coord);
}

void MakeMap()//制作地图
{
	int i, j, top = 0, ttt;
	POSITION s[2500] = { {0,0} };
	POSITION sss[6] = { {0,0} };
	bool vis[50][50] = { false };

	memset(map, ORIGINAL, sizeof(map));
	for (i = 0; i <= MaxLine + 3; i++)
	{
		vis[i][0] = vis[i][MaxColume + 1] = vis[i][1] = vis[i][MaxColume + 2] = true;
		map[i][0] = map[i][MaxColume + 1] = map[i][1] = map[i][MaxColume + 2] = WALL;
	}
	for (i = 0; i <= MaxColume + 3; i++)
	{
		vis[0][i] = vis[MaxLine + 1][i] = vis[1][i] = vis[MaxLine + 2][i] = true;
		map[0][i] = map[MaxLine + 1][i] = map[1][i] = map[MaxLine + 2][i] = WALL;
	}
	map[2][1] = WALL;
	map[MaxLine][MaxColume + 1] = ROAD;
	s[0].x = s[0].y = 2;
	while (top >= 0)
	{
		vis[s[top].x][s[top].y] = true;
		map[s[top].x][s[top].y] = ROAD;
		for (i = s[top].x - 1; i <= s[top].x + 1; i++)
			for (j = s[top].y - 1; j <= s[top].y + 1; j++)
				if (map[i][j] == ORIGINAL)
				{
					vis[i][j] = true;
					map[i][j] = WALL;
				}
		i = s[top].x;
		j = s[top].y;
		if (!(vis[i - 2][j] && vis[i + 2][j] && vis[i][j - 2] && vis[i][j + 2]))
		{
			ttt = -1;
			if (!vis[i - 2][j])
			{
				ttt++;
				sss[ttt].x = i - 2;
				sss[ttt].y = j;
			}
			if (!vis[i + 2][j])
			{
				ttt++;
				sss[ttt].x = i + 2;
				sss[ttt].y = j;
			}
			if (!vis[i][j - 2])
			{
				ttt++;
				sss[ttt].x = i;
				sss[ttt].y = j - 2;
			}
			if (!vis[i][j + 2])
			{
				ttt++;
				sss[ttt].x = i;
				sss[ttt].y = j + 2;
			}
			ttt = rand() % (ttt + 1);

			top++;
			s[top].x = sss[ttt].x;
			s[top].y = sss[ttt].y;
			map[(i + s[top].x) / 2][(j + s[top].y) / 2] = ROAD;

		}
		else
		{
			top--;
		}
	}
	//下面开始随机……挖墙
	for (i = 2; i <= MaxLine; i++)
		for (j = 2; j <= MaxColume; j++)
			if (map[i][j] == WALL)
				if (rand() % 100 < 16)
					map[i][j] = ROAD;
}

void PrintMap()//输出迷宫
{
	SetConsoleTextAttribute(hout, 8);
	SetPosition(0, 0);
	int i, j;
	for (i = 0; i <= MaxLine + 2; i++)
	{
		for (j = 0; j <= MaxColume + 2; j++)
		{
			cout << (map[i][j] == WALL ? WALLSTR : BLANKSTR);
		}
		if (i < MaxLine + 2) cout << endl;
	}
	SetConsoleTextAttribute(hout, 14);
	SetPosition(2, 1);
	cout << "S";
	SetPosition(MaxLine, MaxColume + 1);
	cout << "E";
	SetConsoleTextAttribute(hout, 7);
}

void ChangeConsoleSize(int line, int col)//改变控制台窗口大小
{
	char LINE[10], COL[10], FINAL[50] = { '\0' };
	sprintf(LINE, "%d", line);
	sprintf(COL, "%d", col * 2);
	strcpy(FINAL, "mode con cols=");
	strcat(FINAL, COL);
	strcat(FINAL, " lines=");
	strcat(FINAL, LINE);
	system(FINAL);
	//函数最后的结果就相当于cmd命令:mode con lines=123 cols=123 
}

void ClearMap()//清除所有搜索时留下的标记,只留下墙和路
{
	int i, j;
	for (i = 0; i <= MaxLine + 2; i++)
		for (j = 0; j <= MaxColume + 2; j++)
			if (map[i][j] != WALL)
				map[i][j] = ROAD;
	map[2][1] = WALL;
	map[MaxLine][MaxColume + 1] = ROAD;
}

void ChangeCursor(int a)  // 设置光标是否可见  a=0不可见,a=1可见 
{
	CONSOLE_CURSOR_INFO cursor_info = { 1, a };
	SetConsoleCursorInfo(hout, &cursor_info);
}

void DepthFirstSearch(int x = 2, int y = 2, int dir = 0)
{
	memset(Stack, 0, sizeof(Stack));
	top = -1;
	while (top > -2 && (x != MaxLine || y != MaxColume + 1))
	{
		top++;
		Stack[top].x = x;
		Stack[top].y = y;
		SetConsoleTextAttribute(hout, 14);
		SetPosition(x, y);
		cout << RIGHTSTR;
		Sleep(DELAY);
		if (map[x][y + 1] == ROAD)
		{
			map[x][y] = RIGHT;
			y++;
		}
		else
		{
			SetPosition(x, y);
			cout << DOWNSTR;
			Sleep(DELAY);
			if (map[x + 1][y] == ROAD)
			{
				map[x][y] = DOWN;
				x++;
			}
			else
			{
				SetPosition(x, y);
				cout << LEFTSTR;
				Sleep(DELAY);
				if (map[x][y - 1] == ROAD)
				{
					map[x][y] = LEFT;
					y--;
				}
				else
				{
					SetPosition(x, y);
					cout << UPSTR;
					Sleep(DELAY);
					if (map[x - 1][y] == ROAD)
					{
						map[x][y] = UP;
						x--;
					}

					else
					{
						map[x][y] = DEAD;
						SetPosition(x, y);
						cout << DEADSTR;
						Sleep(DELAY / 2);
						top -= 2;
						x = Stack[top + 1].x;
						y = Stack[top + 1].y;
					}
				}
			}
		}
		if (kbhit())
			if (getch() == '3')
				return;//万一不想看了,直接停掉
	}
	ClearMap();
	PrintMap();
	SetConsoleTextAttribute(hout, 28);
	while (top >= 0)
	{
		SetPosition(Stack[top].x, Stack[top].y);
		cout << BLANKSTR;
		top--;
	}
	SetConsoleTextAttribute(hout, 7);
}

void WidthFirstSearch()
{
	int x, y, PreSub;
	tail = head = 0;
	memset(Queue, 0, sizeof(Queue));
	Queue[head].PreSub = -1;
	Queue[head].x = 2;
	Queue[head].y = 1;
	SetConsoleTextAttribute(hout, 14);
	while (tail <= head)
	{
		x = Queue[tail].x;
		y = Queue[tail].y;
		PreSub = Queue[tail].PreSub;

		if (map[x - 1][y] == ROAD)
		{
			map[x - 1][y] = UP;
			SetPosition(x - 1, y);
			cout << UPSTR;
			head++;
			Queue[head].x = x - 1;
			Queue[head].y = y;
			Queue[head].PreSub = tail;
			if (Queue[head].x == MaxLine && Queue[head].y == MaxColume + 1) break;
		}
		if (map[x + 1][y] == ROAD)
		{
			SetPosition(x + 1, y);
			cout << DOWNSTR;
			map[x + 1][y] = DOWN;
			head++;
			Queue[head].x = x + 1;
			Queue[head].y = y;
			Queue[head].PreSub = tail;
			if (Queue[head].x == MaxLine && Queue[head].y == MaxColume + 1) break;
		}
		if (map[x][y + 1] == ROAD)
		{
			SetPosition(x, y + 1);
			cout << RIGHTSTR;
			map[x][y + 1] = RIGHT;
			head++;
			Queue[head].x = x;
			Queue[head].y = y + 1;
			Queue[head].PreSub = tail;
			if (Queue[head].x == MaxLine && Queue[head].y == MaxColume + 1) break;
		}
		if (map[x][y - 1] == ROAD)
		{
			SetPosition(x, y - 1);
			cout << LEFTSTR;
			map[x][y - 1] = LEFT;
			head++;
			Queue[head].x = x;
			Queue[head].y = y - 1;
			Queue[head].PreSub = tail;
			if (Queue[head].x == MaxLine && Queue[head].y == MaxColume + 1) break;
		}
		Sleep(DELAY / 2);
		tail++;
		if (kbhit())
			if (getch() == '3')
				return;//万一不想看了,直接停掉
	}
	ClearMap();
	PrintMap();
	tail = Queue[head].PreSub;
	SetConsoleTextAttribute(hout, 28);
	if (Queue[head].x == MaxLine && Queue[head].y == MaxColume + 1)
		while (tail != -1)
		{
			SetPosition(Queue[tail].x, Queue[tail].y);
			cout << BLANKSTR;
			tail = Queue[tail].PreSub;
		}
	SetConsoleTextAttribute(hout, 14);
	SetPosition(MaxLine, MaxColume + 1);
	cout << "E";
	SetPosition(2, 1);
	cout << "S";
	SetConsoleTextAttribute(hout, 7);
}

void PrintMenu()
{
	SetConsoleTextAttribute(hout, 14);
	SetPosition(2, MaxColume + 5);
	cout << "按 1 进行深搜演示";
	SetPosition(4, MaxColume + 5);
	cout << "按 2 进行广搜演示";
	SetPosition(6, MaxColume + 5);
	cout << "按 3 去除所有路径";
	SetPosition(8, MaxColume + 5);
	cout << "按 4 重新生成迷宫";
	SetPosition(10, MaxColume + 5);
	cout << "按 5 开始编辑迷宫";
	SetPosition(12, MaxColume + 4);
	cout << "=====================";
	SetPosition(14, MaxColume + 5);
	cout << "在进行演示时按3";
	SetPosition(15, MaxColume + 5);
	cout << "可以立刻终止演示";
	SetPosition(17, MaxColume + 4);
	cout << "=====================";
	SetPosition(19, MaxColume + 5);
	cout << "编辑迷宫操作方法:";
	SetPosition(21, MaxColume + 5);
	cout << "·按方向键移动所选方块";
	SetPosition(22, MaxColume + 5);
	cout << "  所选方块以红色标记";
	SetPosition(23, MaxColume + 5);
	cout << "·按空格键切换路或墙";
	SetPosition(24, MaxColume + 5);
	cout << "·按回车键退出编辑";
	SetPosition(26, MaxColume + 4);
	cout << "=====================";
	SetPosition(28, MaxColume + 5);
	cout << "图标解释:";
	SetPosition(30, MaxColume + 5);
	cout << "S:起点";
	SetPosition(31, MaxColume + 5);
	cout << "E:终点";
	SetPosition(32, MaxColume + 5);
	cout << BLANKSTR << ":可行走的路";
	SetPosition(33, MaxColume + 5);
	cout << WALLSTR << ":墙壁";
	SetPosition(34, MaxColume + 5);
	cout << RIGHTSTR << ":向右行走";
	SetPosition(35, MaxColume + 5);
	cout << DOWNSTR << ":向下行走";
	SetPosition(36, MaxColume + 5);
	cout << LEFTSTR << ":向左行走";
	SetPosition(37, MaxColume + 5);
	cout << UPSTR << ":向上行走";
	SetConsoleTextAttribute(hout, 7);
}

void EditMap()
{
	int x = 19, y = 19;
	bool KeepWhile = true;
	SetPosition(x, y);
	SetConsoleTextAttribute(hout, 4);
	cout << (map[x][y] == WALL ? WALLSTR : BLANKSTR);
	while (KeepWhile)
	{
		switch (getch())
		{
		case 224: //0xE0 方向键
			SetPosition(x, y);
			SetConsoleTextAttribute(hout, 8);
			cout << (map[x][y] == WALL ? WALLSTR : BLANKSTR);
			switch (getch())
			{
			case 0x48: //↑ 
				if (x > 2) x--;
				break;
			case 0x50: //↓ 
				if (x < MaxLine) x++;
				break;
			case 0x4b: //← 
				if (y > 2) y--;
				break;
			case 0x4d: //→
				if (y < MaxColume) y++;
				break;
			}
			SetPosition(x, y);
			SetConsoleTextAttribute(hout, 4);
			cout << (map[x][y] == WALL ? WALLSTR : BLANKSTR);
			break;
		case ' ':
			if (map[x][y] == WALL)
				map[x][y] = ROAD;
			else
				map[x][y] = WALL;
			SetPosition(x, y);
			cout << (map[x][y] == WALL ? WALLSTR : BLANKSTR);
			break;
		case 13: //回车键
			SetPosition(x, y);
			SetConsoleTextAttribute(hout, 8);
			cout << (map[x][y] == WALL ? WALLSTR : BLANKSTR);
			KeepWhile = false;
			break;
		}
	}
}

int main()
{
	int i, j;
	ChangeConsoleSize(MaxLine + 3, MaxColume + 17);
	ChangeCursor(0);
	srand(time(0));
	MakeMap();
	PrintMap();
	PrintMenu();
	while (1)
	{
		switch (getch())
		{
		case '1':
			ClearMap();
			PrintMap();
			DepthFirstSearch();
			fflush(stdin);
			break;
		case '2':
			ClearMap();
			PrintMap();
			WidthFirstSearch();
			fflush(stdin);
			break;
		case '3':
			ClearMap();
			PrintMap();
			break;
		case '4':
			MakeMap();
			PrintMap();
			break;
		case '5':
			EditMap();
			break;
		}
	}
	return 0;
}

End Of File

你可能感兴趣的:(小进阶)