3

首先让我为尺寸道歉,我会尽量保持这个尺寸

在尝试完全按照维基百科上所说的方式构建 prim 算法之后,我发现它不会像我构建的迷宫那样工作。所以我试图做同样的想法来适应我的迷宫,但我看到了一个奇怪的错误,

当我的游戏开始时,它只是没有正确构建我的迷宫,我无法弄清楚为什么这是偶尔发生的事情

迷宫错误图片

其他时候它工作得很好,所以我有一个public Dictionary<int, Dictionary<int, MazeCellState>> maze这个迷宫,当它开始时,迷宫都是树篱,然后我继续像这样建造路径

private static void buildPath()
       {
           List<KeyValuePair<Misc.Cord, Misc.Cord>> ends = new List<KeyValuePair<Misc.Cord, Misc.Cord>>();
           ends.Add(new KeyValuePair<Misc.Cord, Misc.Cord>(new Misc.Cord() { X = 0, Y = 0 }, new Misc.Cord() { X = 0, Y = 0 }));
           Misc.Cord currentPos = null;

           while (ends.Count > 0)
           {
               int posKey = rand.Next(0, ends.Count);
               Misc.Cord lastPos = ends[posKey].Key;
               currentPos = ends[posKey].Value;
               maze[currentPos.X][currentPos.Y] = MazeCellState.Path;
               int currentCount = 0;

               MovingState moveTo1 = (MovingState)rand.Next(0, 4);
               MovingState moveTo2 = (MovingState)rand.Next(0, 4);
               while (moveTo1.Equals(moveTo2))
               {
                   moveTo1 = (MovingState)rand.Next(0, 4);
                   moveTo2 = (MovingState)rand.Next(0, 4);
               }

               // check left
               if (currentPos.X - 2 > 0 && maze[currentPos.X - 2][currentPos.Y] != MazeCellState.Path && currentCount < 2 && (moveTo1 == MovingState.Left || moveTo2 == MovingState.Left))
               {
                   if(!lastPos.Equals(new Misc.Cord() { X = currentPos.X - 2, Y = currentPos.Y }))
                   {
                       ends.Add(new KeyValuePair<Misc.Cord, Misc.Cord>(currentPos, new Misc.Cord() { X = currentPos.X - 2, Y = currentPos.Y }));
                       maze[currentPos.X - 1][currentPos.Y] = MazeCellState.Path;
                       currentCount++;
                   }
               }

               // check right
               if (currentPos.X + 2 < maze.Count && maze[currentPos.X + 2][currentPos.Y] != MazeCellState.Path && currentCount < 2 && (moveTo1 == MovingState.Right || moveTo2 == MovingState.Right))
               {
                   if (!lastPos.Equals(new Misc.Cord() { X = currentPos.X + 2, Y = currentPos.Y }))
                   {
                       ends.Add(new KeyValuePair<Misc.Cord, Misc.Cord>(currentPos, new Misc.Cord() { X = currentPos.X + 2, Y = currentPos.Y }));
                       maze[currentPos.X + 1][currentPos.Y] = MazeCellState.Path;
                       currentCount++;
                   }
               }

               // check Up
               if (currentPos.Y - 2 > 0 && maze[currentPos.X][currentPos.Y - 2] != MazeCellState.Path && currentCount < 2 && (moveTo1 == MovingState.Up || moveTo2 == MovingState.Up))
               {
                   if(!lastPos.Equals(new Misc.Cord() { X = currentPos.X, Y = currentPos.Y - 2}))
                   {
                       ends.Add(new KeyValuePair<Misc.Cord, Misc.Cord>(currentPos, new Misc.Cord() { X = currentPos.X, Y = currentPos.Y - 2 }));
                       maze[currentPos.X][currentPos.Y - 1] = MazeCellState.Path;
                       currentCount++;
                   }
               }

               // check Down
               if (currentPos.Y + 2 < maze[0].Count && maze[currentPos.X][currentPos.Y + 2] != MazeCellState.Path && currentCount < 2 && (moveTo1 == MovingState.Down || moveTo2 == MovingState.Down))
               {
                   if(!lastPos.Equals(new Misc.Cord() { X = currentPos.X, Y = currentPos.Y + 2}))
                   {
                       ends.Add(new KeyValuePair<Misc.Cord, Misc.Cord>(currentPos, new Misc.Cord() { X = currentPos.X, Y = currentPos.Y + 2 }));
                       maze[currentPos.X][currentPos.Y + 1] = MazeCellState.Path;
                       currentCount++;
                   }
               }
                ends.RemoveAt(posKey);
                ends = reorderList(ends);
           }

           maze[0][1] = MazeCellState.Path;
       }

我不知道为什么有时我会得到上面的图片,我的理论是它最终会恢复它的自我

一些快速说明,此时 MazeCellState 只能是 2 个选项之一,路径或对冲和 reorderList 将重新索引任何类型的列表,迷宫大小是从屏幕分辨率计算出来的,每个单元格是 64x64 PX,

            GraphicsDevice.Viewport.Width * 5 / 64,
            GraphicsDevice.Viewport.Height * 5 / 64
4

1 回答 1

2

当您的字段是网格时,这确实是一种很难实现算法的方法。Prim 的网格算法可以更容易地表达。与其研究你的代码做错了什么,我会告诉你一个简单的方法。

创建您的网格,并用从零开始的连续数字对所有单元格进行编号。每个单元都有两个可以破坏的边界墙;上下左右,或其他组合,只要选择(左/右)和(上/下)之一即可。

现在选择任何一个单元格,然后选择它的一堵墙。如果该墙另一侧的单元格具有不同的编号(一个高一个低一个),则打破该墙,然后在整个迷宫中,将所有出现的较大数字重新编号为较低的数字。如果您选择一个单元格和另一侧已经有相同编号的墙,不要尝试另一面墙,而是按顺序移动到下一个单元格,在每一行和向下重复(可能几乎一直循环) 直到你找到一个有墙的牢房,你可以打破它。

如果你有 N 个单元格,你必须准确地重复这个破墙练习 N-1 次,直到最后一次所有单元格都被编号为零(因为每次你打破,你从字段中删除更高的数字),你有一个完整的迷宫。

如果你想要一个迷宫,它的路径通常是左右而不是上下,然后偏向于你随机选择在那个方向打破哪堵墙。这也适用于 3D 迷宫,您可能不需要很多梯子;只是不要选择打破这么多的天花板/地板。

在我描述了这个算法之后,我 14 岁的儿子在 3D 中用 Turbo-Pascal 实现了它,所以我知道这个算法和这个描述确实有效。这实际上是 Prim 算法的一个版本,除了所有弧都具有相同的成本(或所有左右弧都如此,所有上下弧都如此,等等)。它的巧妙之处在于编号的工作方式,以确定哪些单元格已经可以从其他单元格到达。

于 2014-03-22T07:29:02.653 回答