widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPainter>
#include <QDebug>
#include <QStack>
#include <QMessagebox>
#include <QKeyEvent>
#include <QEvent>
#include <QTime>
#include <QProcess>
//方块大小
#define xsize 20
#define ysize 20
//行列
#define H 29
#define W 29
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void paintEvent(QPaintEvent *event);
void keyPressEvent(QKeyEvent *event);
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::Widget *ui;
//起点位置
int x=xsize*2,y=ysize*2;
//当前坐标
int row=1,col=1;
public:
QPainter painter;
QPen pen;
void initmaze();
void Astart(int r,int c);
};
#endif // WIDGET_H
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <iostream>
#include <QHash>
#include <QList>
#include <QQueue>
using namespace std;
Widget::Widget(QWidget *parent):QWidget(parent),ui(new Ui::Widget)
{
ui->setupUi(this);
this->setFixedSize(this->size());
qDebug()<<this->size();
}
Widget::~Widget()
{
delete ui;
}
//1,2代表墙,0代表类似树的节点。破墙赋4,访问过赋4
int MAP[H][W];
int isFind[H+2][W+2];
struct Point {
int row;
int col;
};
QStack<Point> load;
void Widget::initmaze()
{
Point curP = { 2,2 };//辅组地图上的起始点
QStack<Point> ms;
ms.push(curP);//压入栈顶
int direction = 0;
srand(QTime::currentTime().msec());//设置随机数生成器的种子。使用当前时间的毫秒部分作为随机数生成器的种子,使得每次运行程序时生成的随机数序列都不同。
while (1) {
//结束循环条件:遍历完了
int n = 0;
for (int i = 0; i < H+2; i++) {
for (int j = 0; j < W+2; j++) {
if (isFind[i][j] == 0)n++;//如果等于,有格子是空的
}
}
if (n == 0)break;//所有格子都已经被访问过了
direction = rand()%4;//随机生成方向2
//退栈条件是走到死胡同
//死胡同是上下左右都走过了
if (isFind[curP.row - 2][curP.col] == 1 && isFind[curP.row][curP.col - 2] == 1 &&
isFind[curP.row + 2][curP.col] == 1 && isFind[curP.row][curP.col + 2] == 1)
{
if(!ms.empty())ms.pop();
if(ms.empty()){
qDebug()<<"生成失败";
}
curP = ms.top();
}
//如果方向为0,向上,并且当前位置的前两个位置为0,将上一个位置打破
if (direction == 0 && isFind[curP.row - 2][curP.col] == 0) {
MAP[curP.row - 1 - 1][curP.col - 1] = 0;//打破墙,原地图比isfind地图小1
isFind[curP.row - 2][curP.col] = 1;//当前已经被访问过
curP.row -= 2;//移动两个位置
ms.push(curP);//添加到ms数组中,跟踪当前位置
}
else if (direction == 1 && isFind[curP.row][curP.col - 2] == 0) {
MAP[curP.row - 1][curP.col - 1 - 1] = 0;
isFind[curP.row][curP.col - 2] = 1;
curP.col -= 2;
ms.push(curP);
}
else if (direction == 2 && isFind[curP.row + 2][curP.col] == 0) {
MAP[curP.row + 1 - 1][curP.col - 1] = 0;
isFind[curP.row + 2][curP.col] = 1;
curP.row += 2;
ms.push(curP);
}
else if (direction == 3 && isFind[curP.row][curP.col + 2] == 0) {
MAP[curP.row - 1][curP.col + 1 - 1] = 0;
isFind[curP.row][curP.col + 2] = 1;
curP.col += 2;
ms.push(curP);
}
}
}
void Widget::paintEvent(QPaintEvent *event)
{
painter.begin(this);
//设置间距
pen.setWidth(xsize);
for(int i=0;i<H;i++)
{
for(int j=0;j<W;j++)
{
if(MAP[i][j]==1)
{
pen.setColor(Qt::black);
painter.setPen(pen);
painter.drawPoint((j+1)*xsize,(i+1)*ysize);
}
//类似节点
if(MAP[i][j]==0)
{
pen.setColor(Qt::white);
painter.setPen(pen);
painter.drawPoint((j+1)*xsize,(i+1)*ysize);
}
}
}
pen.setColor(Qt::blue);
painter.setPen(pen);
painter.drawPoint((col+1)*xsize,(row+1)*ysize);
pen.setColor(Qt::red);
painter.setPen(pen);
painter.drawPoint((H-1)*xsize,(W-1)*ysize);
//画自动走的路径
while(!load.empty())//当优先队列不为空时
{
Point temp = load.top();
qDebug() << "row = " << temp.row << " col = " << temp.col;//qDebug来打印这个对象的行和列
pen.setColor(Qt::green);
painter.setPen(pen);
painter.drawPoint((temp.col+1)*xsize,(temp.row+1)*ysize);//在图像上绘制一个点
load.pop();
}
painter.end();
}
void Widget::keyPressEvent(QKeyEvent *event)
{
//点击按键会给direction赋值,但如果是向上走就不能往下 上下左右0123
switch (event->key())
{
case Qt::Key_W:
if(row*ysize>0&&MAP[row-1][col]==0)
{
row--;
}
break;
case Qt::Key_S:
if((row+2)*ysize<=ysize*H&&MAP[row+1][col]==0)
{
row++;
}
break;
case Qt::Key_A:
if(col*xsize>0&&MAP[row][col-1]==0)
{
col--;
}
break;
case Qt::Key_D://x=(col+1)*xsize
if((col+2)*xsize<=ysize*W&&MAP[row][col+1]==0)
{
col++;
}
break;
default:
break;
}
update();
//走到终点
if(row==H-2&&col==W-2)
{
//创建 QMessageBox 类对象
QMessageBox MyBox(QMessageBox::Question,"提示","你已走出迷宫,是否重新开始?",QMessageBox::Yes|QMessageBox::No);
//使 MyBox 对话框显示
int rec=MyBox.exec();
if (rec==QMessageBox::Yes) {
QProcess::startDetached(qApp->applicationFilePath(), QStringList());
}
else if (rec==QMessageBox::No) {
this->close();
}
}
}
void Widget::on_pushButton_clicked()
{
row=1;
col=1;
//初始化MAP迷宫
for (int i=0;i<H;i++)
{
for(int j=0;j<W;j++)
{
//如果i和j都是奇数的元素设为0
if(i%2==1&&j%2==1)
{
MAP[i][j]=0;
continue;
}
MAP[i][j]=1;
}
}
//设计边界
for (int i=0;i<H+2;i++)
{
for(int j=0;j<W+2;j++)
{
isFind[i][j]=1;
}
}
for (int i=0;i<H;i++)
{
for(int j=0;j<W;j++)
{
isFind[i+1][j+1]=MAP[i][j];
}
}
initmaze();
update();
}
void Widget::Astart(int r,int c)
{
while(!load.empty())load.pop();
//初始化数组
int arr[H][W];
for (int i=0;i<H;i++)
{
for(int j=0;j<W;j++)
{
arr[i][j]=0;
}
}
Point beginPoint = { r,c };//自定义起点
Point endPoint = { H-2,W-2 };//自定义终点
load.push(beginPoint);
Point currentPoint = beginPoint;//当前走到的位置
arr[currentPoint.row][currentPoint.col] = 1;//arr记录已经走过的路径,arr标记数组
while (1)//while循环一直走下去,一直走到终点栈来存储路径上的点,从起点开始尝试
//基于栈的深度优先算法,代码中的while循环会一直执行,直到找到终点,如果有可行的方向,就更新当前位置并将其压入栈中,否则就弹出栈顶元素回退到上一个位置
{
//下
if (MAP[currentPoint.row + 1][currentPoint.col] == 0 &&
arr[currentPoint.row + 1][currentPoint.col] == 0)//可以向下走的条件
{
arr[currentPoint.row + 1][currentPoint.col] = 1;
currentPoint.row = currentPoint.row + 1;
load.push(currentPoint);
}
//右
else if (MAP[currentPoint.row][currentPoint.col+1] == 0 &&
arr[currentPoint.row][currentPoint.col+1] == 0)//可以向右走的条件
{
arr[currentPoint.row][currentPoint.col + 1] = 1;
currentPoint.col = currentPoint.col + 1;
load.push(currentPoint);
}
//上
else if (MAP[currentPoint.row - 1][currentPoint.col] == 0 &&
arr[currentPoint.row - 1][currentPoint.col] == 0)//可以向上走的条件
{
arr[currentPoint.row - 1][currentPoint.col] = 1;
currentPoint.row = currentPoint.row - 1;
load.push(currentPoint);
}
//左
else if (MAP[currentPoint.row][currentPoint.col-1] == 0 &&
arr[currentPoint.row][currentPoint.col-1] == 0)//可以向左走的条件
{
arr[currentPoint.row][currentPoint.col - 1] = 1;
currentPoint.col = currentPoint.col - 1;
load.push(currentPoint);
}
else//死胡同,即上下左右都无法走
{
load.pop();
currentPoint = load.top();
}
if (currentPoint.row == endPoint.row && currentPoint.col == endPoint.col)
{
qDebug() << "找到终点!路径回退:" ;
break;
}
if (load.empty())
{
qDebug() << "找不到路!";
break;
}
}
}
void Widget::on_pushButton_2_clicked()
{
Astart(row,col);
update();
}