[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());
    }
}

 

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