[迷宮中的算法實踐]迷宮生成算法——遞歸分割算法

Recursive division method

       Mazes can be created with recursive division, an algorithm which works as follows: Begin with the maze's space with no walls. Call this a chamber. Divide the chamber with a randomly positioned wall (or multiple walls) where each wall contains a randomly positioned passage opening within it. Then recursively repeat the process on the subchambers until all chambers are minimum sized. This method results in mazes with long straight walls crossing their space, making it easier to see which areas to avoid.算法

       For example, in a rectangular maze, build at random points two walls that are perpendicular to each other. These two walls divide the large chamber into four smaller chambers separated by four walls. Choose three of the four walls at random, and open a one cell-wide hole at a random point in each of the three. Continue in this manner recursively, until every chamber has a width of one cell in either of the two directions.dom

Recursive Maze generationide

 

遞歸分割算法ui

        能夠用遞歸分割法建立迷宮,算法的工做原理以下:this

        1.開始建立迷宮,使整個空間沒有壁,咱們稱之爲「室」。spa

        2.在隨機位置生成壁將室分割爲兩個子室,並在壁上隨機開孔,使子室聯通。code

        3.重複步驟2,直到全部子室所有不可分割(即子室某一個維度等於1)。blog


        例如,在矩形迷宮中,在任意點創建彼此垂直的兩個壁。 這兩個壁將大腔室分紅由四個壁分開的四個較小腔室。 隨機選擇四個牆壁中的三個,並在三個牆壁的隨機點處打開一個單元格的孔。 繼續以這種方式遞歸,直到每一個室在兩個方向中的任一個方向上具備一個單元的寬度。遞歸

下面咱們來作C#的代碼實現:three

/// <summary>
/// 遞歸回溯法迷宮生成法
/// </summary>
/// <param name="startX"></param>
/// <param name="startY"></param>
/// <param name="widthLimit"></param>
/// <param name="heightLimit"></param>
private void RecursiveBacktrack(int startX, int startY, int widthLimit, int heightLimit)
{
    PathStack = new Stack<Point>();
    //周圍未連通格座標
    int[] blockPos = new int[4];
    //周圍未標記格的數量
    int blockNum = 0;

    //將起點做爲當前格
    int currentX = startX;
    int currentY = startY;

    //標記起點
    MazeMap[currentX, currentY] = UnBlock;
    CreateScript.Add(new ScriptPoint(new Point(currentX, currentY), false));
    do
    {
        //檢測周圍有沒有未連通的格子
        blockNum = 0;
        //檢查上方
        if (currentY > 1 && MazeMap[currentX, currentY - 2] == Block)
        {
            blockPos[blockNum] = 0;
            blockNum++;
        }
        //檢查右側
        if (currentX < widthLimit && MazeMap[currentX + 2, currentY] == Block)
        {
            blockPos[blockNum] = 1;
            blockNum++;
        }
        //檢查下方
        if (currentY < heightLimit && MazeMap[currentX, currentY + 2] == Block)
        {
            blockPos[blockNum] = 2;
            blockNum++;
        }
        //檢查左側
        if (currentX > 1 && MazeMap[currentX - 2, currentY] == Block)
        {
            blockPos[blockNum] = 3;
            blockNum++;
        }

        //選出下一個當前格
        if (blockNum > 0)
        {
            //隨機選擇一個鄰格
            blockNum = _r.Next(0, blockNum);
            //把當前格入棧
            PathStack.Push(new Point(currentX, currentY));
            //連通鄰格,並將鄰格指定爲當前格
            switch (blockPos[blockNum])
            {
                case 0:
                    MazeMap[currentX, currentY - 1] = UnBlock;
                    CreateScript.Add(new ScriptPoint(new Point(currentX, currentY - 1), false));
                    currentY -= 2;
                    break;
                case 1:
                    MazeMap[currentX + 1, currentY] = UnBlock;
                    CreateScript.Add(new ScriptPoint(new Point(currentX + 1, currentY), false));
                    currentX += 2;
                    break;
                case 2:
                    MazeMap[currentX, currentY + 1] = UnBlock;
                    CreateScript.Add(new ScriptPoint(new Point(currentX, currentY + 1), false));
                    currentY += 2;
                    break;
                case 3:
                    MazeMap[currentX - 1, currentY] = UnBlock;
                    CreateScript.Add(new ScriptPoint(new Point(currentX - 1, currentY), false));
                    currentX -= 2;
                    break;

            }
            //標記當前格
            MazeMap[currentX, currentY] = UnBlock;
            CreateScript.Add(new ScriptPoint(new Point(currentX, currentY), false));
        }
        else if (PathStack.Count > 0)
        {
            //將棧頂做爲當前格
            Point top = PathStack.Pop();
            currentY = top.Y;
            currentX = top.X;
        }
    } while (PathStack.Count > 0);
}
相關文章
相關標籤/搜索