#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "MAZE.h"
#include <QMainWindow>
#include <QWidget>
#include <iostream>
#include <QTime>
#include <QLineEdit>
#include <QPushButton>
#include <QPainter>
#include <QLabel>
#include <QMessageBox>
#include <QDebug>
#include <QKeyEvent>
#include <QPixmap>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void paintEvent(QPaintEvent *);//键盘监听
void keyPressEvent(QKeyEvent *e);//绘图重写
void PointMove();
private:
MAZE *m; ///<迷宫地图
///< 当前人物在迷宫的位置(X,Y)
int X = 1;
int Y = 0;
bool bfs_fg = false; ///< 最短路径绘制标志
private slots:
void on_queding_clicked();//创建迷宫
void on_zhaolu_clicked();//寻找路径
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
***********************************************
#ifndef MAZE_H
#define MAZE_H
static const int N = 650;
class MAZE
{
public:
///< 值为0:绘制迷宫过道
///< 值为1:绘制迷宫围墙
///< 值为2:绘制当前的位置
///< 值为3:绘制迷宫终点
///< 值为4:绘制你当前的位置
///< 值为6:绘制最短路径提示
int maze[N][N];
struct point//定义结构体point
{
int x, y, pre;
}q[N*N], path[N*N];//结构体数组
MAZE();
void set_n(int tn);
int get_n();
//int get_len_path(){return len_path;}
//void set_len_path(int tn){len_path = tn;}
void printPath()//打印通路
{
bfs();
for(int i = len_path-1; i >= 0; i--)
if(maze[path[i].x][path[i].y]==0)
maze[path[i].x][path[i].y] = 6;
}
void recoverPath()
{
for(int i = len_path-1; i >= 0; i--)
if(maze[path[i].x][path[i].y]==6)
maze[path[i].x][path[i].y] = 0;
}
void mazeInit();//迷宫信息
int searchPath(int x, int y);//搜索路径
void print();
~MAZE();
private:
int n, len_path, nn;
void bfs();
void getPath(int pos);
};
#endif // MAZE_H
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "MAZE.h"
#include <iostream>
//绘制迷宫最小单元的(矩形)的长和宽20,即正方形
#define size 20
using namespace std;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//调整窗口中其它控件的大小
int n = 31;
/*新建迷宫*/
m = new MAZE();
m->set_n(n);
//迷宫初始化
m->mazeInit();
//迷宫绘制
m->print();
//设置窗口标题
this->setWindowTitle("迷宫");
//设置窗口固定大小
this->setFixedSize(750,650);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::paintEvent(QPaintEvent *)//绘制迷宫
{
QPainter painter(this);
int n = m->get_n();
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
//绘制迷宫围墙,0为墙1为路
if(m->maze[i][j] ==1){
painter.setPen(Qt::black);
painter.setBrush(QBrush(Qt::black,Qt::SolidPattern));
painter.drawRect(QRect(j*size,i*size,size,size));
}
//绘制当前的位置(x,y)
else if(m->maze[i][j] == 2){
painter.setPen(Qt::red);
painter.setBrush(Qt::red);
painter.drawRect(j*20,i*20,20,20);
}
//绘制迷宫终点
else if(m->maze[i][j] == 3){
painter.setPen(Qt::red);
painter.setBrush(Qt::red);
painter.drawRect(j*20,i*20,20,20);
}
//绘制迷宫过道
else if(m->maze[i][j] == 0){
painter.setPen(Qt::white);
painter.setBrush(QBrush(Qt::white,Qt::SolidPattern));
painter.drawRect(QRect(j*size,i*size,size,size));
}
//绘制最短路径提示
else if(m->maze[i][j] == 6){
painter.setPen(Qt::white);
painter.setBrush(Qt::blue);
painter.drawRect(j*20+5,i*20+5,10,10);
}
}
}
}
void MainWindow::keyPressEvent(QKeyEvent *e)//键盘控制上下左右的移动
{
if(bfs_fg){ //变量 bfs_fg为真(表示通过广度优先算法找到了路径),则调用 m->recoverPath()函数还原路径
m->recoverPath();
bfs_fg = false; //变量bfs_fg设为假,更新界面
update();
}
int tx = X, ty = Y; //初始化变量 tx和 ty为当前位置的坐标,获取迷宫的大小 n
int n = m->get_n();
if(e->key()==Qt::Key_W)//上移
{
if(X>0 && m->maze[X-1][Y] != 1)//如果当前位置不在迷宫的最上方且上方的值不为1
{
X=X-1;
}
}
else if(e->key()==Qt::Key_S)//下移
{
if(X<n-1 && m->maze[X+1][Y] != 1)//如果当前位置不在迷宫的最下方且下方的值不为1(路)
{
X=X+1;
}
}
else if(e->key()==Qt::Key_A)//左移
{
if(Y>0 && m->maze[X][Y-1] != 1)//如果当前位置不在迷宫的最左方且左方的值不为1
{
Y=Y-1;
}
}
else if(e->key()==Qt::Key_D)//右移
{
if(Y<n-1 && m->maze[X][Y+1] != 1)//如果当前位置不在迷宫的最右方且右方的值不为1
{
Y=Y+1;
}
}
int tmp = m->maze[X][Y];//将新位置的值存储在临时变量 tmp中
if(tmp == 3){
QMessageBox::information(this,"提示","到达终点",QMessageBox::Yes);
}else{
m->maze[X][Y] = m->maze[tx][ty];
m->maze[tx][ty] = tmp;//如果 tmp的值为3(终点),则弹出提示窗口,否则将当前位置的值设为先前位置的值,将先前位置的值设为 tmp
}
update();
}
void MainWindow::on_queding_clicked()//重建迷宫
{
m->mazeInit();
X = 1, Y = 0;
update();
}
void MainWindow::on_zhaolu_clicked()//自动寻路
{
m->printPath();
bfs_fg = true;
update();
}
void MainWindow::on_pushButton_clicked()
{
m->mazeInit();
//初始化人物当前位置
X = 1, Y = 0;
//重绘地图,会调用void MainWindow::paintEvent(QPaintEvent *)
update();
}
void MainWindow::on_pushButton_2_clicked()
{
m->printPath();
bfs_fg = true;
update();
}
*************************************************************
#include "MAZE.h"
#include <iostream>
#include <windows.h>
#include <cstdio>
#include <cmath>
#include <time.h>
#include <cstring>
using namespace std;
int fa[N*N]; //fa 数组用来存储最短路径中每个位置的父节点
int dx[4] = {1, 0, -1, 0}; //dx 和 dy 数组表示四个方向的移动:右、下、左、上
int dy[4] = {0, 1, 0, -1};
MAZE::MAZE(){}
void MAZE::set_n(int tn)//设置迷宫大小
{
n = tn;
nn = n/2;//将传入的参数赋值给 n,并计算出迷宫地图大小的一半
}
int MAZE::get_n()//获取迷宫大小
{
return n;
}
void MAZE::print()//print 函数调用了 bfs 函数,即广度优先搜索算法,用于打印迷宫的路径
{
bfs();
}
void MAZE::mazeInit()//生成迷宫
{
//迷宫围墙,nn*2+2是规划的迷宫地图大小
for(int i=0; i<=nn*2+2; ++i)
for(int j=0; j<=nn*2+2; ++j)
maze[i][j] = 1;//初始化为1(墙)
//在迷宫之外的的轮廓默设置为0(路)
for(int i=0, j=2*nn+2; i<=2*nn+2; ++i)
{
maze[i][0] = 0;
maze[i][j] = 0;
}
for(int i=0, j=2*nn+2; i<=2*nn+2; ++i)
{
maze[0][i] = 0;
maze[j][i] = 0;
}
//默认迷宫坐标第三行第一列为起点
maze[2][1] = 2;
//默认2*nn 行 和 2*nn+1列为终点
maze[2*nn][2*nn+1] = 3;
//生成无符号随机数
srand((unsigned)time(NULL));//调用 searchPath函数,以在起点附近生成路径,并将其连接到迷宫中
//生成的随机数在 [0, nn+1]之间,生成路径
searchPath(rand()%nn+1, rand()%nn+1);
//将地图整体向左上方平移一个单位
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
maze[i][j] = maze[i+1][j+1];//将新生成的迷宫从索引为1开始的位置复制到索引为0开始的位置
}
}
len_path = 0;//路径的长度设置为0
}
int MAZE::searchPath(int x, int y)//prime算法随机生成迷宫
{
//定义静态数组dir表示上下左右四个方向
static int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int zx = x*2;
int zy = y*2;//通过将传入的坐标乘以2,并将结果存储在 zx和 zy变量中,来在迷宫地图中定位当前位置
int next, turn, i;
maze[zx][zy] = 0;//当前位置设置为起点
//设置turn为[0, 4]之间的任意一个奇数
turn = rand()%2 ? 1 : 3;//使用 rand() % 2获取一个随机数,如果结果为1,则将 turn设置为1(墙),否则设置为3(终点)
//next=rand()%4 取值范围[0, 4),
//next=(next+turn)%4 每个循环在奇数和偶数之间切换,[0, 4)遍历一遍
//在迷宫地图里,随机选一个地方,开始挖路,4次循环,往4个方向挖
for(i=0, next=rand()%4; i<4; ++i, next=(next+turn)%4)
//搜索当前位置的第二步,如果是1(墙),这将当前位置的沿着指定方向的下一步设置为0(路)
if(maze[zx+2*dir[next][0]][zy+2*dir[next][1]] == 1)
{ //判断上下左右四个方向隔一个位置是否为1(墙),是则变为0(路)
maze[zx+dir[next][0]][zy+dir[next][1]] = 0;
searchPath(x+dir[next][0], y+dir[next][1]);//递归调用 searchPath函数,传入下一个步骤的坐标,当前位置的下一步为节点开始搜索
}
return 0;
}
void MAZE::getPath(int pos)//深度优先算法搜索路径
{
while(pos != -1)//通过一个循环,不断将当前位置的坐标存入路径数组中,并将路径长度加一
{ //获取下一个位置的索引,即当前位置的前一个节点,在下一次循环中继续处理。直到遍历完整个路径,即找到起点为止。
path[len_path].x = q[pos].x;
path[len_path].y = q[pos].y;
len_path++;
pos = q[pos].pre;
}
}
void MAZE::bfs()//广度优先算法寻找路径
{
int front, tail, sx, sy;
for(int i = 0; i < n; i++)//循环遍历数组的每个元素,当找到值为2(当前位置)的元素时,将其坐标赋值给sx和sy,即起点的坐标
for(int j = 0; j < n; j++)
if(maze[i][j] == 2)
{
sx = i; sy = j;
}
front = tail = 0; //找到起点的位置,初始化头尾指针为0
q[tail].x = sx;
q[tail].y = sy;
q[tail].pre = -1;
tail++;
int x, y, nx, ny;
bool fg = false;
while(front < tail)
{
x = q[front].x;
y = q[front].y;
for(int i = 0; i < 4; i++)
{
nx = x+dx[i];
ny = y+dy[i];
if(nx>=0&&nx<n&&ny>=0&&ny<n&&maze[nx][ny]==0)//确保头结点在路上
{
maze[nx][ny] = 5;//把此节点设为通路
q[tail].x = nx;
q[tail].y = ny;
q[tail].pre = front;//加入到数组q中
tail++;
}
if(maze[nx][ny] == 3){//起点和终点重合
q[tail].x = nx;
q[tail].y = ny;
q[tail].pre = front;
tail++;
fg = true;//结束标志
len_path = 0;
path[len_path].x = nx;
path[len_path].y = ny;
len_path++;
getPath(front);
}
}
if(fg)break;//如果找到终点结束循环
front++;//否则头结点到上一个节点
}
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
if(maze[i][j] == 5)
maze[i][j] = 0;//循环处理队列中的节点,分别向上、下、左、右四个方向探索。如果下一个节点在迷宫范围内且可以通过(值为0),
//则将其加入队列并标记为通路。当遇到终点时(值为3),将终点加入队列并设置结束标志。最后,将标记为通路的节点恢复为原始值。
}