mazewidget.h

#ifndef MAZEWIDGET_H
#define MAZEWIDGET_H
#include <QMessageBox>      //Qt信息窗口头文件
#include <QPainter>         //Qt绘图头文件
#include <QDebug>           //QtDebug头文件
#include <QKeyEvent>        //Qt按键事件头文件
#include <QTimer>           //Qt计时器头文件
#include <QInputDialog>     //Qt输入对话框头文件
#include<widget.h>           //迷宫类头文件
#include <QWidget>
#include<QList>
#include<vector>
#include<QMediaPlayer>
#include<QMediaPlaylist>
#include<QtConcurrent/QtConcurrent>
namespace Ui {
class mazewidget;
}

class mazewidget : public QWidget
{
    Q_OBJECT
protected:
    void paintEvent(QPaintEvent*);        //绘图事件
    void keyPressEvent(QKeyEvent*);       //按键按下事件
private slots:
    void on_start_btn_clicked();    //|
    void on_stop_btn_clicked();     //|
    void on_end_btn_clicked();      //|
    void on_rule_btn_clicked();     //|各按钮点击槽函数
    void on_setting_btn_clicked();  //|
    void on_battle_btn_clicked();   //|
    void on_about_btn_clicked();    //|
    void on_roadfind_btn_clicked();
    void DFS(int x, int y, bool& find);
    void time_update();
    void setStartEndPos(QPoint start, QPoint end);//时间更新槽函数
    QList<QPoint> aStarPath(QPoint start, QPoint end);
    void A_star();

public:
    explicit mazewidget(QWidget *parent = nullptr);
    ~mazewidget();
    QPushButton *start_btn; //开始游戏
       QPushButton * stop_ptn;// 暂停
         QPushButton *end_btn ;//终止游戏
           QPushButton * setting_btn ;
           QPushButton * roadfind_btn ;//设置QLabel:
          QLabel* plaque ;//迷宫游戏
          QLabel*  plaque_time ;//时间:
          QMediaPlayer *player;
           QMediaPlaylist* playerList;

           QLabel* plaque_grade ;//分数:
        QList<int>open_list;
         QList<int>close_list;
         QPoint startPos;
         QPoint endPos;
        int row = 2 * level + 1;
           int  column = 2 * level + 1;

private:
    Ui::mazewidget *ui;
       //ui对象指针
    Widget* map;                  //迷宫对象指针
private: struct point {
        int x = -1;
        int y = -1;
        int cost = 0;
        int fvalue = 0;
        point* parent = nullptr;
        bool operator<(const point& other)
        const { return fvalue > other.fvalue; }
    };
    QVector<QPoint> path; // 用于存储搜索路径上的点的坐标

   QVector<point*>open_set;
    QVector<point*>close_set;
    void A_star(int, int, int, int);
    QVector<point*> get_surround_points(int, int, point*);
    bool is_point_valid(int, int, point*); point* get_point_with_min_fvalue();
    bool painting_switch;       //绘图开关
    bool timing_switch;         //计时开关
    bool keybord_switch;        //键盘响应开关
    bool stop_switch;          //暂停按钮状态
    bool find_switch;
int level;
    int grade;                  //分数
    int time;                  //时间
     int p_x, p_y;
     int end_x, end_y;
int  next_x;
int  next_y;
int  current_x;
int  current_y;

    QTimer* timer;				//计时器对象指针
};


#endif // MAZEWIDGET_H

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT
private:
    int level;  //迷宫阶数
    int** mapArray;  //地图存储空间
    int start_x, start_y;   //起点
    //生成基础地图(单元格)
    void base();
    //使点的周围设为待定(2)
    void arround(int i, int j);
    //设定迷宫开始延伸的起点
    void start() ;
    //循环停止判定(是否存在未判定的区域)
    bool judge();
    //操作(如果相邻空单元(1)则打通(变为4),如果不相邻空单元则为墙壁(0))
    void op(int i, int j);
    //随机选择一个待定墙壁判断并操作
    void random2();
     void DFS();
public:
    //构造函数申请内存空间
    Widget(int in_level);
    ~Widget();
    //获取地图
    int getlevel() ;
    int** getmap();
    int getside();
    //生成地图
    void makemap();
    int p_x, p_y; //当前位置
    int end_x, end_y;
    //重置地图
    void rebuildmap();
    int* operator[](int index);




private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

mazewidget.cpp

#include "mazewidget.h"
#include "ui_mazewidget.h"

#include <QDateTime>
#include <queue>
#include <iostream>




mazewidget::mazewidget(QWidget *parent) :
    QWidget(parent),ui(new Ui::mazewidget),map(new Widget(20)),painting_switch(false), timing_switch(false)
  , keybord_switch(false), grade(0), time(0)

{

    ui->setupUi(this);
       ui->progressBar->setVisible(false);                 //初始隐藏进度条
        ui->end_btn->setEnabled(false);                     //设置终止按钮禁用
       ui->stop_btn->setEnabled(false);                    //设置暂停按钮禁用
        ui->grade_value->setText("  ");                     //设置分数值显示为空\        ui->time_value->setText("  ");                      //设置时间值显示为空
        map->makemap();
        playerList = new QMediaPlaylist();
           player = new QMediaPlayer();
          playerList->addMedia(QMediaContent(QUrl("qrc:/C:/Users/MALING/Music/hmbb.mp3")));

           playerList->setPlaybackMode(QMediaPlaylist::Loop);

           player->setPlaylist(playerList);
           player->setVolume(100);
           player->play();
           this->setWindowTitle("海绵宝宝回家");
        //生成地图
        timer = new QTimer(this);                                           //初始化计时器
        connect(timer, &QTimer::timeout, this, &mazewidget::time_update);

        if (map == nullptr) {
                map = new Widget(20);
            }

}

mazewidget::~mazewidget()
{
    delete ui;
    delete map;		//1.
       delete timer;	//2.
}

void mazewidget::paintEvent(QPaintEvent*) {

    if(!painting_switch) return;
    QPainter painter(this);     //画笔对象
    //绘图逻辑:
    int perblock = (std::min(ui->frame->width(), ui->frame->height()) - 20) / (map->getside());
    int start_x = ui->frame->x() + (ui->frame->width() - (ui->frame->x() + (map->getside()) * perblock)) / 2;
    int strat_y = ui->frame->y() + (ui->frame->height() - (ui->frame->y() + (map->getside()) * perblock)) / 2;
    for(int i = 0; i < map->getlevel() * 2 + 1; i++) {
        for(int j = 0; j < map->getlevel() * 2 + 1; j++) {
            if(i == map->p_x && j == map->p_y) {
                QPixmap road;
                                   road.load("C:\\Users\\MALING\\Pictures\\Saved Pictures\\starthmbb.png");
                                   painter.drawPixmap(start_x + i * perblock, strat_y + j * perblock, perblock, perblock,road);
            } else if(map->getmap()[i][j] == 7) {
                QPixmap foot;
                                   foot.load("C:\\Users\\MALING\\Pictures\\Saved Pictures\\jiaoyin.jpg");
                                   painter.drawPixmap(start_x + i * perblock, strat_y + j * perblock, perblock, perblock,foot);
            } else if(map->getmap()[i][j] == 3 || map->getmap()[i][j] == 4) {
                painter.fillRect(start_x + i * perblock, strat_y + j * perblock, perblock, perblock, QBrush(Qt::white));
            } else if(map->getmap()[i][j] == 5) {
                QPixmap start;
                                   start.load("C:\\Users\\MALING\\Pictures\\Saved Pictures\\starthmbb.png");
                                   painter.drawPixmap(start_x + i * perblock, strat_y + j * perblock, perblock, perblock,start);
            } else if(map->getmap()[i][j] == 6) {
                QPixmap end;
                end.load("C:\\Users\\MALING\\Pictures\\Saved Pictures\\endhmbb.png");
                painter.drawPixmap(start_x + i * perblock, strat_y + j * perblock, perblock, perblock,end);
            }
            else if(map->getmap()[i][j]==0 || map->getmap()[i][j] == -1) {
                QPixmap wall;
                                    wall.load("C:\\Users\\MALING\\Pictures\\Saved Pictures\\paopao.png");
                                    painter.drawPixmap(start_x + i * perblock, strat_y + j * perblock, perblock, perblock,wall);
            }else{
                painter.fillRect(start_x + i * perblock, strat_y + j * perblock, perblock, perblock, QBrush(Qt::yellow));
            }
        }
    }
}
void mazewidget::keyPressEvent(QKeyEvent* event) {
    if(!keybord_switch) return;

    // 角色坐标
    int x = map->p_x;
    int y = map->p_y;

    //键盘移动逻辑:
    if(event->key() == Qt::Key_I || event->key() == Qt::Key_W) {
        if((*map)[x][y - 1] == 3 || (*map)[x][y - 1] == 4 || (*map)[x][y - 1] == 5 || (*map)[x][y - 1] == 6 || (*map)[x][y - 1] == 7) {
            map->p_y--;
        }
    } else if(event->key() == Qt::Key_K || event->key() == Qt::Key_S) {
        if((*map)[x][y + 1] == 3 || (*map)[x][y + 1] == 4 || (*map)[x][y + 1] == 5 || (*map)[x][y + 1] == 6 || (*map)[x][y + 1] == 7) {
            map->p_y++;
        }
    } else if(event->key() == Qt::Key_J || event->key() == Qt::Key_A) {
        if((*map)[x - 1][y] == 3 || (*map)[x - 1][y] == 4 || (*map)[x - 1][y] == 5 || (*map)[x - 1][y] == 6 || (*map)[x - 1][y] == 7) {
            map->p_x--;
        }
    } else if(event->key() == Qt::Key_L || event->key() == Qt::Key_D) {
        if((*map)[x + 1][y] == 3 || (*map)[x + 1][y] == 4 || (*map)[x + 1][y] == 5 || (*map)[x + 1][y] == 6 || (*map)[x + 1][y] == 7) {
            map->p_x++;
        }
    }
    //经过路径
    if((*map)[map->p_x][map->p_y] != 5 && (*map)[map->p_x][map->p_y] != 6)(*map)[map->p_x][map->p_y] = 7;
    repaint();
    //到达终点
    if((*map)[map->p_x][map->p_y] == 6) {
        map->makemap();
        repaint();
        grade += (map->getlevel(), 2);
        ui->grade_value->setText(QString::number(grade));
    }





           }


void mazewidget::time_update() {
    if(time != 0) {
        //计时中
        time--;
        ui->time_value->setText(QString::number(time));
        ui->progressBar->setValue(time / 2);
    } else {
        timer->stop();                          //停止计时器
        ui->progressBar->setVisible(false);     //隐藏进度条
        keybord_switch = false;                 //设置键盘响应、
        painting_switch = false;                //绘图响应、
        timing_switch = false;                  //计时响应为关闭状态
        repaint();                              //清除画布
        ui->start_btn->setEnabled(true);        //|
        ui->time_value->setText(" ");           //|
        ui->grade_value->setText(" ");          //|
        ui->stop_btn->setEnabled(false);        //|设置各按钮与标签状态
        ui->end_btn->setEnabled(false);         //|
        ui->setting_btn->setEnabled(true);      //|
        //提示
        QMessageBox outgrade(QMessageBox::NoIcon, "恭喜", "您得分:" + QString::number(grade), QMessageBox::Ok);
        outgrade.exec();
        //分数重置
        grade = 0;
    }
}
void mazewidget::on_start_btn_clicked() {
    painting_switch = true;
    timing_switch = true;
    keybord_switch = true;
    time = 200;
    timer->start(1000);
    ui->progressBar->setVisible(true);
    ui->progressBar->setValue(100);
    repaint();
    ui->time_value->setText(QString::number(time));
    ui->grade_value->setText(QString::number(grade));
    ui->start_btn->setEnabled(false);
    ui->stop_btn->setEnabled(true);
    ui->end_btn->setEnabled(true);
    ui->setting_btn->setEnabled(false);
}
void mazewidget::on_stop_btn_clicked() {
    if(stop_switch) {
        timing_switch = false;
        keybord_switch = false;
        timer->stop();
        ui->stop_btn->setText("继续");
        stop_switch = false;
    } else {
        timing_switch = true;
        keybord_switch = true;
        timer->start();
        ui->stop_btn->setText("暂停");
        stop_switch = true;
    }
}
void mazewidget::on_end_btn_clicked() {
    timing_switch = false;
    painting_switch = false;
    keybord_switch = false;
    stop_switch = false;
    timer->stop();
    time = 0;
    grade = 0;
    ui->progressBar->setVisible(false);
    ui->grade_value->setText(" ");
    ui->time_value->setText(" ");
    ui->stop_btn->setText("暂停");
    ui->stop_btn->setEnabled(false);
    ui->end_btn->setEnabled(false);
    ui->start_btn->setEnabled(true);
    ui->setting_btn->setEnabled(true);
    map->rebuildmap();
    repaint();

}

void mazewidget::on_setting_btn_clicked() {
    QStringList difficultys;
    difficultys << tr("启蒙难度(5阶迷宫)") << tr("简单难度(10阶迷宫)") << tr("普通难度(20阶迷宫)") << tr("困难难度(40阶迷宫)");
    QString difficulty = QInputDialog::getItem(this, tr("选择难度"),
                         tr("请选择一个条目"), difficultys, 0, false);
    if(difficulty == tr("启蒙难度(5阶迷宫)")) {
        delete map;
        map = new Widget(5);
        map->makemap();
    } else if(difficulty == tr("简单难度(10阶迷宫)")) {
        delete map;
        map = new Widget(10);
        map->makemap();
    } else if(difficulty == tr("普通难度(20阶迷宫)")) {
        delete map;
        map = new Widget(20);
        map->makemap();
    } else if(difficulty == tr("困难难度(40阶迷宫)")) {
        delete map;
        map = new Widget(40);
        map->makemap();
    }
    find_switch = false;
}


bool mazewidget::is_point_valid(int x, int y, point* parent) {
    // 如果是边界, 直接返回false
    if (x < 0 || x >= map->getlevel() * 2 + 1 || y < 0 || y >= map->getlevel() * 2 + 1)
        return false;

    // 类型1 2 3 4 7都为不可达
    if ((*map)[x][y] == 1 || (*map)[x][y] == 2 || (*map)[x][y] == 3 || (*map)[x][y] == 4 || (*map)[x][y] == 7)
        return false;

    // 如果在开放列表或者关闭列表中, 表示探索过
    for (point *p : open_set) {
        if (p->x == x && p->y == y)
            return false;
    }
    for (point *p : close_set) {
        if (p->x == x && p->y == y)
            return false;
    }


    if (parent && parent->x == x && parent->y == y)
        return false;
    return true;

}


QVector<mazewidget::point*> mazewidget::get_surround_points(int x, int y, point* parent) {
    // 相邻节点列表
    QVector<point*> surround_points;

    // 如果当前节点上面不是墙壁, 添加到相邻节点列表
    if (is_point_valid(x - 1, y, parent)) {
        point* p = new point;
        p->x = x - 1; p->y = y;
        p->cost = parent->cost + 1;
        p->fvalue = p->cost + abs(x - 1 - map->p_x) + abs(y - map->p_y);
        p->parent = parent; surround_points.push_back(p);
    }

    // 下面
    if (is_point_valid(x + 1, y, parent)) {
        point* p = new point;
        p->x = x + 1;
        p->y = y;
        p->cost = parent->cost + 1;
        p->fvalue = p->cost + abs(x + 1 - map->p_x) + abs(y - map->p_y);
        p->parent = parent; surround_points.push_back(p);
    }

    // 左边
    if (is_point_valid(x, y - 1, parent)) {
        point* p = new point;
        p->x = x; p->y = y - 1;
        p->cost = parent->cost + 1;
        p->fvalue = p->cost + abs(x - map->p_x) + abs(y - 1 - map->p_y);
        p->parent = parent; surround_points.push_back(p);
    }

    // 右边
    if (is_point_valid(x, y + 1, parent)) {
        point* p = new point; p->x = x;
        p->y = y + 1; p->cost = parent->cost + 1;
        p->fvalue = p->cost + abs(x - map->p_x) + abs(y + 1 - map->p_y);
        p->parent = parent;
        surround_points.push_back(p);
    }

    return surround_points;
}

mazewidget::point* mazewidget::get_point_with_min_fvalue() {
    if (open_set.empty()) {
        qDebug() << "开放列表为空,没有节点可用";
            return nullptr; // 开放列表为空,没有节点可用
        }

    int index = 0;

    // 拿开放列表第一个的曼哈顿距离
    int min_fvalue = open_set[0]->fvalue;

    // 遍历整个开放列表, 判断是否有更小的距离, 如果有就更新最小距离
    for (int i = 1; i < open_set.size(); i++) {
        if (open_set[i]->fvalue < min_fvalue) {
            index = i;
            min_fvalue = open_set[i]->fvalue;
        }
    }

    // 返回的节点
    point* p = open_set[index];

    // 从开放列表移除距离终点最近的节点
    open_set.erase(open_set.begin() + index);

    return p;
}

void mazewidget::A_star(int sx, int sy, int ex, int ey) {
    qDebug() << "111";
    open_set.clear();  // 开放列表(待探索节点)
    close_set.clear();  // 闭合列表(探索过的节点)
    path.clear();

    // 每一个节点都有x,y坐标和相对于终点的曼哈顿距离
    point* start = new point;
    start->x = sx; start->y = sy;
    start->cost = 0;
    // 曼哈顿距离(这里是起点到终点的曼哈顿距离)
    start->fvalue = abs(sx - ex) + abs(sy - ey);
    // 将起点加入到开放列表
    open_set.push_back(start);

    // 终点
    point* end = new point;
    end->x = ex; end->y = ey;

    int t = 1;

    // 判断开放列表是否被探索完成
    while (!open_set.empty()) {
        // 获取距离最近的节点作为下一个节点(移动到下一个节点就变成了当前节点)
        point* current = get_point_with_min_fvalue();
        // qDebug() << "current:" << current;
        t++;
        qDebug() << "执行次数: " << t;

        // 向关闭列表添加当前节点, 因为已经被探索
        close_set.push_back(current);

        // 判断当前位置是否等于终点位置
        if (current->x == end->x && current->y == end->y) {

            // 从终点回到起点, 以获得路径
            while (current) {
                qDebug() << "探索到终点";

                // 将当前节点添加到路径的末尾
                path.prepend(QPoint(current->x, current->y));

                // ???
                // (*map)[current->x][current->y] = 7;

                // 得到当前节点的上一级节点
                point* prev = current;
                // 将当前节点设为上一级节点
                current = current->parent;
                // 删除上一级节点
                delete prev;
            }
            return;
        }

        // 获取当前节点的相邻节点
        // 需要在函数里面实现去除不可达节点(墙壁)
        QVector<point*> surround_points = get_surround_points(current->x, current->y, current);
        // 将相邻节点添加到开放列表(待探索节点)
        for (point* p : surround_points) {
            open_set.push_back(p);
            delete p; // 释放内存
        }

        delete current;
    }
}

widget.cpp

#include "widget.h"

void Widget::base() {
    for (int i = 0; i < level * 2 + 1; i++) {
        for (int j = 0; j < level * 2 + 1; j++) {
            if (i == 0 || j == 0 || i == level * 2 + 1 - 1 ||
                j == level * 2 + 1 - 1) {
                mapArray[i][j] = -1;
            } else if (i % 2 != 0 && j % 2 != 0) {
                mapArray[i][j] = 1;
            } else {
                mapArray[i][j] = 0;
            }
        }
    }
}
//使点的周围设为待定(2)
void Widget:: arround(int i, int j) {
    if (mapArray[i - 1][j] == 0) {
        mapArray[i - 1][j] = 2;
    }
    if (mapArray[i + 1][j] == 0) {
        mapArray[i + 1][j] = 2;
    }
    if (mapArray[i][j - 1] == 0) {
        mapArray[i][j - 1] = 2;
    }
    if (mapArray[i][j + 1] == 0) {
        mapArray[i][j + 1] = 2;
    }
}
//设定迷宫开始延伸的起点
void Widget:: start() {
    mapArray[start_x][start_y] = 5;
    arround(start_x, start_y);
}
//循环停止判定(是否存在未判定的区域)
bool Widget:: judge() {
    bool flag = 0;
    for (int i = 0; i < level * 2 + 1; i++) {
        for (int j = 0; j < level * 2 + 1; j++) {
            if (mapArray[i][j] == 2) {
                flag = 1;
                return flag;
            }
        }
    }
    return flag;
}
//操作(如果相邻空单元(1)则打通(变为4),如果不相邻空单元则为墙壁(0))
void Widget:: op(int i, int j) {
    if ((mapArray[i - 1][j] == 3 || mapArray[i - 1][j] == 5) && mapArray[i + 1][j] == 1) {
        mapArray[i][j] = 4;
        mapArray[i + 1][j] = 3;
        arround(i + 1, j);
        start_x = i + 1;
        start_y = j;
    } else if ((mapArray[i][j - 1] == 3 || mapArray[i][j - 1] == 5) &&
               mapArray[i][j + 1] == 1) {
        mapArray[i][j] = 4;
        mapArray[i][j + 1] = 3;
        arround(i, j + 1);
        start_x = i;
        start_y = j + 1;
    } else if ((mapArray[i + 1][j] == 3 || mapArray[i + 1][j] == 5) &&
               mapArray[i - 1][j] == 1) {
        mapArray[i][j] = 4;
        mapArray[i - 1][j] = 3;
        arround(i - 1, j);
        start_x = i - 1;
        start_y = j;
    } else if ((mapArray[i][j + 1] == 3 || mapArray[i][j + 1] == 5) &&
               mapArray[i][j - 1] == 1) {
        mapArray[i][j] = 4;
        mapArray[i][j - 1] = 3;
        arround(i, j - 1);
        start_x = i;
        start_y = j - 1;
    } else {
        mapArray[i][j] = 0;
    }
}

void Widget:: random2() {
    int t = 0;
    for (int i = 0; i < level * 2 + 1; i++) {
        for (int j = 0; j < level * 2 + 1; j++) {
            if (mapArray[i][j] == 2) {
                t++;
            }
        }
    }

    int k = rand() % t + 1;
    t = 0;
    for (int i = 0; i < level * 2 + 1; i++) {
        for (int j = 0; j < level * 2 + 1; j++) {
            if (mapArray[i][j] == 2) {
                t++;
                if (t == k) {
                    op(i, j);
                    goto loopout;
                }
            }
        }
    }
loopout:
    if (!judge()) {
        mapArray[start_x][start_y] = 6;
    }
}

//构造函数申请内存空间
Widget:: Widget(int in_level) : level(in_level) {
    mapArray = new int* [level * 2 + 1];
    for (int i = 0; i < level * 2 + 1; i++) {
        mapArray[i] = new int[level * 2 + 1];
    }
    start_x = 1, start_y = 1; //起点设置为(1,1)
}
Widget::~Widget() {
    for (int i = 0; i < level * 2 + 1; i++) {
        delete [] mapArray[i];
    }
    delete [] mapArray;
}
//获取地图
int Widget:: getlevel() {
    return Widget::level;
}
int** Widget::getmap() {
    return mapArray;
}
int Widget::getside() {
    return level * 2 + 1;
}
//生成地图
void Widget:: makemap() {
    p_x = start_x;
    p_y = start_y;
    base();
    start();
    int a = 0;
    while (judge()) {
        a++;
        random2();
        // if (a % 30 == 0) {
        //     printarr(map, level);
        //     system("PAUSE");
        // }
    }
}
int*    Widget::operator[](int index) {
    return mapArray[index];
}
//重置地图
void Widget::rebuildmap(){
    start_x=1;
    start_y=1;
    makemap();
}