在 WinForms.NET 中渲染随机生成的迷宫

发布于 2024-08-28 06:14:03 字数 4326 浏览 8 评论 0原文

我正在尝试创建一个迷宫生成器,为此我在 C# 中实现了随机 Prim 算法。

但生成的结果是无效的。我无法弄清楚是我的渲染无效还是实现无效。因此,对于初学者来说,我想让某人看一下实现:

迷宫是一个细胞矩阵。

var cell = maze[0, 0];
cell.Connected = true;

var walls = new HashSet<MazeWall>(cell.Walls);

while (walls.Count > 0)
{
    var randomWall = walls.GetRandom();
    var randomCell = randomWall.A.Connected ? randomWall.B : randomWall.A;

    if (!randomCell.Connected)
    {
        randomWall.IsPassage = true;
        randomCell.Connected = true;

        foreach (var wall in randomCell.Walls)
            walls.Add(wall);
    }

    walls.Remove(randomWall);
}

以下是渲染结果的示例:

渲染迷宫 http://dl.dropbox。 com/u/1744224/Upload/primrecur.png

编辑 好的,让我们看一下渲染部分:

private void MazePanel_Paint(object sender, PaintEventArgs e)
{
    int size = 20;
    int cellSize = 10;

    MazeCell[,] maze = RandomizedPrimsGenerator.Generate(size);

    mazePanel.Size = new Size(
        size * cellSize + 1, 
        size * cellSize + 1
    );

    e.Graphics.DrawRectangle(Pens.Blue, 0, 0, 
        size * cellSize, 
        size * cellSize
    );

    for (int y = 0; y < size; y++)
    for (int x = 0; x < size; x++)
    {
        foreach(var wall in maze[x, y].Walls.Where(w => !w.IsPassage))
        {
            if (wall.Direction == MazeWallOrientation.Horisontal)
            {
                e.Graphics.DrawLine(Pens.Blue, 
                    x * cellSize, y * cellSize, 
                    x * cellSize + cellSize, 
                    y * cellSize
                );
            }    
            else
            {
                e.Graphics.DrawLine(Pens.Blue,
                    x * cellSize,
                    y * cellSize, x * cellSize,
                    y * cellSize + cellSize
                );
            }
        }
    }
}

我想,要理解这一点,我们需要看到 MazeCell 和 MazeWall班级:

namespace MazeGenerator.Maze
{
    class MazeCell
    {
        public int Column 
        {
            get;
            set; 
        }

        public int Row 
        { 
            get; 
            set; 
        }

        public bool Connected 
        { 
            get; 
            set; 
        }

        private List<MazeWall> walls = new List<MazeWall>();

        public List<MazeWall> Walls
        {
            get { return walls;  }
            set { walls = value; }
        }

        public MazeCell()
        {
            this.Connected = false;
        }

        public void AddWall(MazeCell b)
        {
            walls.Add(new MazeWall(this, b));
        }
    }

    enum MazeWallOrientation
    {
        Horisontal,
        Vertical,
        Undefined
    }

    class MazeWall : IEquatable<MazeWall>
    {
        public IEnumerable<MazeCell> Cells 
        { 
            get
            {
                yield return CellA;
                yield return CellB;
            }            
        }

        public MazeCell CellA
        {
            get; 
            set;
        }

        public MazeCell CellB
        {
            get;
            set;
        }

        public bool IsPassage 
        { 
            get; 
            set; 
        }

        public MazeWallOrientation Direction
        {
            get
            {
                if (CellA.Column == CellB.Column)
                {
                    return MazeWallOrientation.Horisontal;
                }
                else if (CellA.Row == CellB.Row) 
                {
                    return MazeWallOrientation.Vertical;
                }
                else
                {
                    return MazeWallOrientation.Undefined;
                }
            }
        }

        public MazeWall(MazeCell a, MazeCell b)
        {
            this.CellA = a;
            this.CellB = b;

            a.Walls.Add(this);
            b.Walls.Add(this);

            IsPassage = false;
        }

        #region IEquatable<MazeWall> Members

        public bool Equals(MazeWall other)
        {
            return (this.CellA == other.CellA) && (this.CellB == other.CellB);
        }

        #endregion
    }
}

I'm trying to create a maze-generator, and for this I have implemented the Randomized Prim's Algorithm in C#.

However, the result of the generation is invalid. I can't figure out if it's my rendering, or the implementation that's invalid. So for starters, I'd like to have someone take a look at the implementation:

maze is a matrix of cells.

var cell = maze[0, 0];
cell.Connected = true;

var walls = new HashSet<MazeWall>(cell.Walls);

while (walls.Count > 0)
{
    var randomWall = walls.GetRandom();
    var randomCell = randomWall.A.Connected ? randomWall.B : randomWall.A;

    if (!randomCell.Connected)
    {
        randomWall.IsPassage = true;
        randomCell.Connected = true;

        foreach (var wall in randomCell.Walls)
            walls.Add(wall);
    }

    walls.Remove(randomWall);
}

Here's a example on the rendered result:

Rendered Maze http://dl.dropbox.com/u/1744224/Upload/primrecur.png

Edit Ok, lets have a look at the rendering part then:

private void MazePanel_Paint(object sender, PaintEventArgs e)
{
    int size = 20;
    int cellSize = 10;

    MazeCell[,] maze = RandomizedPrimsGenerator.Generate(size);

    mazePanel.Size = new Size(
        size * cellSize + 1, 
        size * cellSize + 1
    );

    e.Graphics.DrawRectangle(Pens.Blue, 0, 0, 
        size * cellSize, 
        size * cellSize
    );

    for (int y = 0; y < size; y++)
    for (int x = 0; x < size; x++)
    {
        foreach(var wall in maze[x, y].Walls.Where(w => !w.IsPassage))
        {
            if (wall.Direction == MazeWallOrientation.Horisontal)
            {
                e.Graphics.DrawLine(Pens.Blue, 
                    x * cellSize, y * cellSize, 
                    x * cellSize + cellSize, 
                    y * cellSize
                );
            }    
            else
            {
                e.Graphics.DrawLine(Pens.Blue,
                    x * cellSize,
                    y * cellSize, x * cellSize,
                    y * cellSize + cellSize
                );
            }
        }
    }
}

And I guess, to understand this we need to see the MazeCell and MazeWall class:

namespace MazeGenerator.Maze
{
    class MazeCell
    {
        public int Column 
        {
            get;
            set; 
        }

        public int Row 
        { 
            get; 
            set; 
        }

        public bool Connected 
        { 
            get; 
            set; 
        }

        private List<MazeWall> walls = new List<MazeWall>();

        public List<MazeWall> Walls
        {
            get { return walls;  }
            set { walls = value; }
        }

        public MazeCell()
        {
            this.Connected = false;
        }

        public void AddWall(MazeCell b)
        {
            walls.Add(new MazeWall(this, b));
        }
    }

    enum MazeWallOrientation
    {
        Horisontal,
        Vertical,
        Undefined
    }

    class MazeWall : IEquatable<MazeWall>
    {
        public IEnumerable<MazeCell> Cells 
        { 
            get
            {
                yield return CellA;
                yield return CellB;
            }            
        }

        public MazeCell CellA
        {
            get; 
            set;
        }

        public MazeCell CellB
        {
            get;
            set;
        }

        public bool IsPassage 
        { 
            get; 
            set; 
        }

        public MazeWallOrientation Direction
        {
            get
            {
                if (CellA.Column == CellB.Column)
                {
                    return MazeWallOrientation.Horisontal;
                }
                else if (CellA.Row == CellB.Row) 
                {
                    return MazeWallOrientation.Vertical;
                }
                else
                {
                    return MazeWallOrientation.Undefined;
                }
            }
        }

        public MazeWall(MazeCell a, MazeCell b)
        {
            this.CellA = a;
            this.CellB = b;

            a.Walls.Add(this);
            b.Walls.Add(this);

            IsPassage = false;
        }

        #region IEquatable<MazeWall> Members

        public bool Equals(MazeWall other)
        {
            return (this.CellA == other.CellA) && (this.CellB == other.CellB);
        }

        #endregion
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

断桥再见 2024-09-04 06:14:03

这只是一个想法:

即使您没有发布向单元格添加墙壁的代码,我相信这是逻辑错误。单个牢房有 4 个壁,但两个相邻的牢房只有 7 个壁。不是 8.

移除 randomWall 时,您还需要从其他单元移除相应的墙。

更详细地阐述一下:
如果您的 AddWallsToMaze 算法向每个单元添加 4 面墙,则存在重复的墙。

例如:
CellA 与 CellB 有一面墙。我们称之为 Wall1。
CellB 与 CellA 有一面墙。这是墙 2,不是墙 1。
应该是Wall1。

This is just a thought:

Even though you have not posted the code where you add walls to a cell, I believe that is the logical error. A single cell has 4 walls but two adjoining cells have only 7 walls. Not 8.

You need to remove the corresponding wall from the other cell aswell when removing the randomWall.

To elaborate in a bit more detail:
If your AddWallsToMaze algorithm adds 4 walls to each cell then there are duplicate walls.

Ex:
CellA has a wall with CellB. Let's call it Wall1.
CellB has a wall with CellA. This is Wall2 NOT Wall1.
It should be Wall1.

圈圈圆圆圈圈 2024-09-04 06:14:03

解决方案是纠正单元格绘制方式中的渲染错误。我正在做右墙和底墙,并渲染左墙和顶墙。

private static void RenderCell(PaintEventArgs e, int cellSize, int y, int x, MazeWall wall, Pen pen)
{
    if (wall.Direction == MazeWallOrientation.Horisontal)
    {
        e.Graphics.DrawLine(pen,
            x * cellSize,
            y * cellSize + cellSize,
            x * cellSize + cellSize,
            y * cellSize + cellSize
        );
    }
    else
    {
        e.Graphics.DrawLine(pen,
            x * cellSize + cellSize,
            y * cellSize,
            x * cellSize + cellSize,
            y * cellSize + cellSize
        );
    }
}

我对结果并不完全满意。我想我会尝试另一种算法,这似乎没有我希望的那么好。

The solution was to correct the rendering mistake in how the cells were drawn. I were doing right&bottom walls, and rendering left&top walls.

private static void RenderCell(PaintEventArgs e, int cellSize, int y, int x, MazeWall wall, Pen pen)
{
    if (wall.Direction == MazeWallOrientation.Horisontal)
    {
        e.Graphics.DrawLine(pen,
            x * cellSize,
            y * cellSize + cellSize,
            x * cellSize + cellSize,
            y * cellSize + cellSize
        );
    }
    else
    {
        e.Graphics.DrawLine(pen,
            x * cellSize + cellSize,
            y * cellSize,
            x * cellSize + cellSize,
            y * cellSize + cellSize
        );
    }
}

I'm not perfectly happy with the result. I think I'll try another algorihm, this doesn't seem as wellformed as I'd hoped.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文