目录
一、功能要求:
(1)创建迷宫:根据用户输入的行数n(3<=n<=100)和列数m(3<=m<=100),假定入口始终在(1,1)位置,出口始终在(n,m)位置,创建一个n*m个格子的迷宫,要求屏幕中能显示迷宫信息。
(2)创建障碍:用户输入障碍数k(1<k<n*m),在创建好的迷宫中,随机将k个格子设置为障碍,不能将入口和出口设置为障碍,要求能在迷宫中显示障碍信息。
(3)建立迷宫结构。
二、解决思路:
1、建立结点类、边类、迷宫类。
2、根据输入信息建立迷宫结构。
三、具体代码:
1、头文件及函数声明
#include <iostream>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <cstdlib> // 包含rand()函数的头文件
#include <ctime>
#include <algorithm>
#include <cmath>//pow()函数
using namespace std;
bool isValidInput(int n, int m, int k);//判断输入合法
int getrandom(int x);//获取随机值
void printblank(int n, int val);//调整迷宫格式
int getbit(int sum);//获取sum位数
2、类
class Node;
class Edge
{
public:
int x, y; // 水平和垂直方向
Node *from;
Node *to;
Edge(int x, int y, Node *from, Node *to) : x(x), y(y), from(from), to(to) {}
};
class Node
{
public:
int row; // 横坐标
int col; // 纵坐标
int value;
vector<Node *> nexts; // 所连接的点集
vector<Edge *> edges; // 从该点出发的边集
Node(int value, int row, int col) : value(value), row(row), col(col) {}
};
class maze
{
public:
unordered_map<int, Node *> nodes;
unordered_set<Edge *> edges;
maze(){};
void creatMaze(int n, int m, int k, vector<vector<int>> &myMaze);
maze creatGraph(vector<vector<int>> mitrix); // 建无向图
void print(vector<vector<int>> myMaze, maze graph, int n, int m);
};
3、主函数及验证数据有效函数
int main()
{
int n, m, k;
while (true)
{
cout << "please input the row and col" << endl;
cin >> n >> m;
cout << "please input the number of barriers" << endl;
cin >> k;
if (isValidInput(n, m, k))
{
break;
}
}
vector<vector<int>> myMaze(n + 2, vector<int>(m + 2, 0));
maze graphMaze;
vector<Node *> path;
graphMaze.creatMaze(n, m, k, myMaze);
graphMaze = graphMaze.creatGraph(myMaze);
graphMaze.print(myMaze,graphMaze,n,m);
return 0;
}
bool isValidInput(int n, int m, int k) // 验证n,m,k是否在范围中
{
if (n < 3 || m < 3)
{
cout << "too small" << endl;
return false;
}
else if (n > 100 || m > 100)
{
cout << "too big" << endl;
return false;
}
else if (k <= 1)
{
cout << "too few" << endl;
return false;
}
else if (k >= n * m)
{
cout << "to many" << endl;
return false;
}
return true;
}
4、建立迷宫结构
0代表路,1代表墙,根据行列数及障碍数,随机生成符合条件的迷宫
void maze::creatMaze(int n, int m, int k, vector<vector<int>> &myMaze){
srand(static_cast<unsigned int>(time(nullptr)));
for (int i = 0; i <= n + 1; i++)
{
myMaze[i][0] = 1;
myMaze[i][m + 1] = 1;
}
for (int i = 0; i <= m + 1; i++)
{
myMaze[0][i] = 1;
myMaze[n + 1][i] = 1;
}
myMaze[n][m] = 2;
myMaze[1][1] = 2;
for (int i = 0; i < k; i++)
{
int x = getrandom(n);
int y = getrandom(m);
while ((x == 1 && y == 1) || (x == n && y == m) || (myMaze[x][y] == 1))
{
x = getrandom(n);
y = getrandom(m);
}
myMaze[x][y] = 1;
}
}
int getrandom(int x)
{
int num = rand() % x + 1; // 1到n,1到m
return num;
}
现在的0,1图并无实际含义,需将其转化为图,为了后续搜索路径功能,用数字代表路径,故将n行m列的迷宫用数字表示,从1到n*m,障碍为0(这里改的有点乱,为了以后表示路径,此时大于1的数为路,0为障碍,注意区分)
maze maze::creatGraph(vector<vector<int>> mitrix)
{
maze graph;
int row = mitrix.size() - 2;
int col = mitrix[0].size() - 2;
for (int i = 1; i <= row; i++)
{
for (int j = 1; j <= col; j++)
{
int curValue = (i - 1) * col + j;
if (mitrix[i][j] != 1)
{
if (graph.nodes.find(curValue) == graph.nodes.end())
{
graph.nodes[curValue] = new Node(curValue, i, j);
}
vector<pair<int, int>> direction = {{i + 1, j}, {i - 1, j}, {i, j - 1}, {i, j + 1}}; // 其次代表右,左,上,右
for (auto dir : direction)
{
int curRow = dir.first;
int curCol = dir.second;
int dirValue = (curRow - 1) * col + curCol;
if (mitrix[curRow][curCol] != 1 && curCol > 0 && curRow > 0)
{
if (graph.nodes.find(dirValue) == graph.nodes.end())
{
graph.nodes[dirValue] = new Node(dirValue, curRow, curCol);
}
Node *fromNode = graph.nodes[curValue];
Node *toNode = graph.nodes[dirValue];
Edge *curEdge1 = new Edge(curRow - i, curCol - j, fromNode, toNode);
Edge *curEdge2 = new Edge(i - curRow, j - curCol, fromNode, toNode);
fromNode->nexts.push_back(toNode);
fromNode->edges.push_back(curEdge1);
toNode->edges.push_back(curEdge2);
graph.edges.insert(curEdge1);
graph.edges.insert(curEdge2);
}
}
}
}
}
return graph;
}
5、输出排版
由于结点value值是1到n*m,为了使其排版对齐,识别最大值的位数,并设置前后距离
void maze::print(vector<vector<int>> myMaze, maze graph, int n, int m)
{
int bit = getbit(n * m);
for (int row = 0; row < n + 2; row++)
{
for (int col = 0; col < m + 2; col++)
{
cout << myMaze[row][col] << " ";
}
if (row >= 1 && row <= n)
{
cout << " ";
for (int i = 1; i <= m; i++)
{
int val = (row - 1) * m + i;
if (graph.nodes.find(val) != graph.nodes.end())
{
cout << graph.nodes[val]->value;
switch (bit)
{
case 1:
cout << " ";
break;
default:
printblank(bit, val);
break;
}
}
else
{
cout << 0;
printblank(bit, 0);
}
}
}
cout << endl;
}
}
int getbit(int sum)
{
int bit = 0;
while (sum != 0)
{
bit++;
sum /= 10;
}
return bit;
}
void printblank(int bit, int val)
{ // 例如:对于两位数,val为1位就输出2个空格,为2位就输出一个空格
float x = pow(10, bit);
if (val == 0)
{
while (bit > 0)
{
cout << " ";
bit--;
}
}
else
{
while (x > 1)
{
if (x / val <= 10)
{
cout << " ";
break;
}
else
cout << " ";
x /= 10;
}
}
}
6、呈现效果
输入行列数及障碍数,左面含义是,外面一周是墙,左上角和右上角的2代表起点和终点,0代表路,1代表障碍。
右面的图含义是,实际有意义的地图(也就是墙里面的),从1往后排,此时0代表阻碍。
四、后续功能
1、用队列实现搜索迷宫的最优路径(bfs)。
https://blog.youkuaiyun.com/Lincooo/article/details/140187776?spm=1001.2014.3001.5501
2、用递归实现搜索迷宫的所有路径(dfs)。