迷宫求解
0 项目介绍
此算法适用C++,使用栈求解迷宫。比较 参考文章,本文采用系统栈函数,迷宫为n行m列,并进行了大量优化。本文介绍部分函数,资源如下*(审核中)* 。其余函数可依据参考文章,进行些许改动即可实现。
测试程序(免费)
完整资源
参考文章
1 子函数
1.1 栈相关
1.1.1 stack.h
#include <iostream>
#include <stack>
using namespace std;
struct PosType {
int x; //横坐标
int y; //纵坐标
PosType() {
x = y = 0;
}
void NextPos(int di);
};
class SElemType {
private:
int ord; //通道块在路径上的“序号”
PosType seat; //通道块在迷宫中的“坐标位置”
int di; //从此通道块走向下一通道块的方向
public:
SElemType() {
ord = di = 0;
}
SElemType(int o, PosType se, int d) {
ord = o;
seat.x = se.x;
seat.y = se.y;
di = d;
}
PosType Seat();
void Print(stack<SElemType>& S);
bool NoPass(stack<SElemType>& S);
void NextPos(stack<SElemType>& S, PosType& se);
};//栈的元素类型
1.1.2 函数功能
class SElemType:
//返回该点坐标seat
PosType Seat();
//打印路线,并清空栈
void Print(stack<SElemType>& S);
//若此点的四个方向不通,且栈不空,返回true
//否则,返回false
bool NoPass(stack<SElemType>& S);
//若此点下一个方向未走过,修改该点方向,更新当前坐标,将该点入栈
//右di=1,下di=2,左di=3,上di=4
void NextPos(stack<SElemType>& S, PosType& se);
class PosType:
//更新当前坐标
void NextPos(int di);
1.1.3 stack.cpp
部分函数
#include "stack.h"
PosType SElemType::Seat() {
return seat;
}
void SElemType::Print(stack<SElemType>& S) {
int i = 0;
while (!S.empty()) {
*this = S.top();
switch (di) {
case 1:cout << "从西来"; break;
case 2:cout << "从东来"; break;
case 3:cout << "从北来"; break;
case 4:cout << "从南来"; break;
}
cout << ord << ":(" << seat.x << ',' << seat.y << ')';
i++; S.pop();
if (!(i % 4)) cout << endl;
}
if (i % 4) cout << endl;
}
bool SElemType::NoPass(stack<SElemType>& S) {
if (di == 4)
if (!S.empty())
return true;
return false;
}
路线打印void SElemType::Print(stack& S),为反向打印,即从终点到起点(栈顶到栈底)。
1.2 迷宫相关
1.2.1 maze.h
#include "stack.h"
#include <time.h>
struct MazeType {
int t;
MazeType() {//构造函数,用于初始化
t = 0;
}
};
class Maze {
private:
MazeType** maze;
int m, n;//迷宫长m宽n
public:
Maze(int mu,int nu) {
m = mu;
n = nu;
maze = new MazeType*[nu];
for (int i = 0; i < n; i++)
maze[i] = new MazeType[mu]();
}
~Maze() {//析构函数,程序结束时自动调用
for (int i = 0; i < n; i++)
delete[] maze[i];
m = n = 0;
delete[] maze;
}
void Create();
void Print();
bool Pass(PosType p);
void FootPrint(PosType p);
void MarkPrint(SElemType e);
bool MazePath(stack<SElemType>& S, PosType start, PosType end);
};
1.2.2 函数功能
class Maze:
//构造迷宫,创造路
void Create();
//打印迷宫
void Print();
//若当前位置p合法,可以通过且未走过,maze[p.y][p.x]=1,返回true
bool Pass(PosType p);
//留下足迹,当前位置p已经走过,maze[p.y][p.x]=2
void FootPrint(PosType p);
//留下足迹,不能通过,maze[p.y][p.x]=3
void MarkPrint(SElemType e);
//若找到通路,存放在栈中,并返回true;否则,返回false
bool MazePath(stack<SElemType>& S, PosType start, PosType end);
1.2.3 maze.cpp
部分函数
#include "maze.h"
void Maze::Create() {
srand((unsigned int)time(0));
int i, j;
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
maze[i][j].t = rand() % 2;
}
void Maze::Print() {
int i, j;
cout << "\033[41m红墙\033[42m绿路\033[43m黄通路\033[44m蓝足迹\033[0m" << endl;
cout << 'n' << endl;
for (i = n - 1; i >= 0; i--) {
printf_s("%-2d", i);
for (j = 0; j < m; j++) {
switch (maze[i][j].t){
case 0:cout << "\033[41m×"; break;
case 1:cout << "\033[42m√"; break;
case 2:cout << "\033[43m○"; break;
case 3:cout << "\033[44m○"; break;
}
}
cout << "\033[0m" << endl;
}
cout << " ";
for (j = 0; j < m; j++)
printf_s("%-2d", j);
cout << 'm' << endl;
}
bool Maze::MazePath(stack<SElemType>& S, PosType start, PosType end) {
SElemType e;
int curstep = 1; //探索第一步
PosType curpos = start; //设定当前位置为入口位置
while (!S.empty()) S.pop();
do {
if (Pass(curpos)) {//当前点可以走通
FootPrint(curpos);//留下标记,此点已经走过
e = SElemType(curstep, curpos, 1);//得到此点的下一步,尝试向右
S.push(e);
if (curpos.x == end.x)
if (curpos.y == end.y)
return true;
curpos.NextPos(1);//修改当前坐标
curstep++;//步数加1
}
else {
if (!S.empty()) {
e = S.top(); S.pop();
while (e.NoPass(S)) {//此路不通,留下足迹,回到上一步
MarkPrint(e);
e = S.top(); S.pop();
}
e.NextPos(S, curpos);//e点的下一步,顺序为:先右,后下,再左,最后上
}
}
} while (!S.empty());
return false;
}
对于void Maze::Create(),可进行优化,生成一个更好的迷宫。
2 主函数
2.1 main.cpp
#include "maze.h"
int main() {
int m, n; SElemType e;
stack<SElemType> S;
PosType start, end;
cout << "迷宫求解" << endl;
cout << " 输入m n,迷宫长m宽n:" << endl;
cin >> m >> n;
Maze maze = Maze(m, n);
while (1) {
maze.Create();
cout << "迷宫长" << m << "宽" << n << endl;
maze.Print();
cout << "输入入口坐标m n和出口坐标m n" << endl;
cin >> start.x >> start.y >> end.x >> end.y;
if (!maze.MazePath(S, start, end))
cout << "\033[31m迷宫不能通过,重新生成迷宫.\033[0m" << endl;
else break;
}
cout << "\033[32m成功通过迷宫 ^-^\033[0m" << endl;
cout << "\033[32m走过的路线\033[0m" << endl;
e.Print(S);
cout << "\033[32m走过的迷宫\033[0m" << endl;
maze.Print();
return 0;
}
2.2测试截图
3 总结
3.1 不足之处
- 本文只是找到了一条通路,并未实现最短路径,如测试的图1
- 迷宫生成随意,可能会出现类似下图的情况
- 存在空间浪费
对于MazeType** maze,其中maze = new MazeType*[nu];
多出了nu个maze[i].t
3.2 改进
问题3(未验证)
struct MazeType {
int m;//迷宫长m
int* e;
MazeType(int mu) {//构造函数,用于初始化
m = mu;
e = new int[mu]();
}
~MazeType() {
delete[] e;
e = NULL;
m = 0;
}
};
class Maze {
private:
MazeType* maze;
int n;//迷宫宽n
public:
Maze(int mu,int nu) {
n = nu;
maze = new MazeType[nu](mu);
}
~Maze() {//析构函数,程序结束时自动调用
for (int i = 0; i < n; i++)
delete maze[i];
n = 0;
delete[] maze;
maze = NULL;
}
void Create();
void Print();
bool Pass(PosType p);
void FootPrint(PosType p);
void MarkPrint(SElemType e);
bool MazePath(stack<SElemType>& S, PosType start, PosType end);
};
正向打印
可采用文章中的自定义栈函数进行实现
思路如下
void Print(Stack s){
SElemType e;
while(S.base != S.top){
e = *S.base;
cout << e;
S.base++;
}
}
针对本课题些许改动,即可成功实现