[Qt] 迷宫随机生成和寻路算法 - Qt实现的迷宫小游戏

这是大二上学期做的一个小玩意儿,上传上来凑个数哈哈哈。

首先贴出下载链接:

1. 完整Qt源码:http://download.csdn.net/detail/mahabharata_/9824044

2. 发布的可执行程序:http://download.csdn.net/detail/mahabharata_/9824066

 

程序截图:

1. 动画演示自动寻路的过程(使用QSequentialAnimation)

2. 生成的一个较大迷宫和打印路径。

 

 

      最近,我陆续地把以前做的一些Qt或OpenGL的小程序、游戏等整理出来。其中的这个迷宫游戏,是我在大二时期为《数据结构综合实习》所做的程序。

      当时倒是觉得写完这个程序对我的Qt技巧的提升还挺大的。虽然现在时隔了将近2年,回头重新审视这段代码,发现不管是以前的代码结构,还是Qt的熟练程度还是差了一些火候。

      不过这里还是整理分享出来,希望能给那些希望学好Qt的同学一些帮助。顺带着,也可以通过这个程序,了解一下迷宫的随机生成算法、DFS的寻路算法。

 

说明:

1. 这个程序的灵感来自于最近流行的平面像素风格RPG游戏。

2. 当进入程序时,先点击“生成迷宫”,程序会自动生成一个给定宽度、高度的随机迷宫。

3. 点击“玩家模式”按钮,可以像普通RPG游戏那样,WASD操纵小人的移动,中间使用的插值会使小人的运动显得比较连贯。

4. 点击“圆形按钮”,小人将会动画演示自动寻路的过程

5. 点击“绘制路径”按钮,将会在地图上打印小人的路径。

 

核心算法:

0. 基本的数据结构

 

class point
{
public:
    int i;
    int j;
    int state;

    point();
    point(int i,int j, int state);

    bool operator==(const point& maze);
};
class Maze
{
private:
    point **recordMatrix;
    QStack<point> *MazeStack;
    point move[4]; //人移动的四个方向
public:
    point **matrix;

    int height;//迷宫矩阵的行
    int width;//迷宫矩阵的列

    int X;//人的位置
    int Y;
    QList<point> pathStack;  // 存储动画演示的中间过程。
    QList<point> autoPath;   //存放最终的路径。

    Maze();

    void initMaze(int h,int w);
    void createMaze();
    void autoFindPath();

private:
    void setDirFalse(bool& up,bool& down,bool& right,bool& left);
};

 

1. 迷宫的随机生成:

  在随机生成的迷宫中要求任意两点,都可以找到一条路径相通,所以在图论中可以认为迷宫就是一个连通图。产生连通图的常见方法有kruskal和prim算法,一般来讲使用prim算法产生的迷宫比较自然和随机。其实本质是,一个有约束条件的深搜。

 

void Maze::createMaze()
{
    int i=3,j=3;
    matrix[i][j].state=1;

    point temp;
    temp.i=i;
    temp.j=j;
    temp.state=1;
    bool up=false, down=false, right=false, left=false;

    while(true)
    {
        temp.i=i;
        temp.j=j;
        int randNum=qrand()%4;
        switch(randNum)
        {
        case 0://上
            if(!up&&i>2&&matrix[i-2][j].state==0)
            {
                MazeStack->push(temp);
                matrix[i-2][j].state=1;
                matrix[i-1][j].state=1;
                i=i-2;
                setDirFalse(up, down, right, left);
            }
            else
                up=true;
            break;
        case 1://下
            if(!down&&i<height-3&&matrix[i+2][j].state==0)
            {
                MazeStack->push(temp);
                matrix[i+2][j].state=1;
                matrix[i+1][j].state=1;
                i=i+2;
                setDirFalse(up, down, right, left);
            }
            else
                down=true;
            break;
        case 2://左
            if(!left&&j>2&&matrix[i][j-2].state==0)
            {
                MazeStack->push(temp);
                matrix[i][j-2].state=1;
                matrix[i][j-1].state=1;
                j=j-2;
                setDirFalse(up, down, right, left);
            }
            else
                left=true;
            break;
        case 3://右
            if(!right&&j<width-3&&matrix[i][j+2].state==0)
            {
                MazeStack->push(temp);
                matrix[i][j+2].state=1;
                matrix[i][j+1].state=1;
                j=j+2;
                setDirFalse(up, down, right, left);
            }
            else
                right=true;
            break;
        }
        if(up&&down&&right&&left)//如果当前访问节点四个方向都没有可拆的节点,回溯
        {
            if(!MazeStack->empty())
            {
                i=MazeStack->top().i;
                j=MazeStack->top().j;
                MazeStack->pop();
                setDirFalse(up, down, right, left);
            }
            else//如果栈为空的话就返回,此时迷宫矩阵已经创建完毕
            {
                return;
            }
        }
    }
}

2. 迷宫的自动寻路:

 

 

void Maze::autoFindPath()
{
    pathStack.clear();
    recordMatrix[X][Y].state = 0;  //出口位置标记为已经访问过,0为墙
    point temp(X,Y,0);
    pathStack.push_back(temp);

    int i , j , d ;
    while(!pathStack.isEmpty())
    {
        point top = pathStack.back();
        pathStack.pop_back();

        if(!autoPath.isEmpty()&& !(top==autoPath.back()))
            autoPath.push_back(top);
        if(autoPath.isEmpty())
            autoPath.push_back(top);

        i = top.i;j=top.j;d=top.state;

        while(d < 4)
        {
            temp.i = i+move[d].i;
            temp.j = j+move[d].j;

            if(temp.i == height-2 &&temp.j ==width-2)
            {
                pathStack.push_back(top);
                pathStack.push_back(temp);
                autoPath.push_back(temp);

                for(int i=0 ; i<pathStack.size();i++)
                {
                    qDebug()<<"("<<pathStack[i].i<<","<<pathStack[i].j<<")";
                }
                return;
            }

            if(matrix[temp.i][temp.j].state == 1 && recordMatrix[temp.i][temp.j].state == 1)
            {

                recordMatrix[temp.i][temp.j].state = 0;
                top.state=d;
                pathStack.push_back(top);
                temp.state=0;
                pathStack.push_back(temp);
                autoPath.push_back(temp);
                break;
            }
            d++;
        }
        if(d==4)
            autoPath.push_back(pathStack.back());
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章