C# 查找墙的最小数量

C# 查找墙的最小数量,c#,algorithm,optimization,C#,Algorithm,Optimization,我在做一个游戏,墙壁是用方块做的。墙放置在二维栅格上,如下所示: [X][X][X][X] [ ][X][ ][ ] [ ][X][ ][ ] [ ][X][ ][ ] 现在,当我优化碰撞检测时,它有助于将墙数减少到最小。在上述情况下,共有七个墙砌块,但如果这些砌块组合在一起,则只有两堵墙。我很难找到一个最佳的解决方案来找到这些组合墙,并根据搜索开始的块得到不同的结果(块存储在无序列表中,顺序来自它们在编辑器中的放置顺序)。如何解决这个问题有什么想法吗?这应该是相当基本的东西,但是,你知道,今

我在做一个游戏,墙壁是用方块做的。墙放置在二维栅格上,如下所示:

[X][X][X][X]
[ ][X][ ][ ]
[ ][X][ ][ ]
[ ][X][ ][ ]
现在,当我优化碰撞检测时,它有助于将墙数减少到最小。在上述情况下,共有七个墙砌块,但如果这些砌块组合在一起,则只有两堵墙。我很难找到一个最佳的解决方案来找到这些组合墙,并根据搜索开始的块得到不同的结果(块存储在无序列表中,顺序来自它们在编辑器中的放置顺序)。如何解决这个问题有什么想法吗?这应该是相当基本的东西,但是,你知道,今天是星期五,我不能正常工作

这是我目前的次优代码,它基本上做了两个检查,水平和垂直“连续性”,然后检查哪一个更好。它还存储“已经处理过”的墙块,这样它们就不会被识别两次,但这当然会让它在交叉点变得很时髦

public void CreateCollidersForExport()
{
    List<Wall> handledWalls = new List<Wall>();

    foreach (Wall w in walls)
    {
        if (handledWalls.Contains(w)) continue;
        handledWalls.Add(w);

        // Search how many walls there is horizontally
        Vector3 horizontalCenter = new Vector3(w.X, w.Y, w.Z);
        List<Wall> tmpWallsHorizontal = new List<Wall>();
        tmpWallsHorizontal.Add(w);
        foreach (Wall other in walls)
        {
            if (handledWalls.Contains(other) || tmpWallsHorizontal.Contains(other)) continue;
            bool canAdd = false;
            foreach (Wall _w in tmpWallsHorizontal)
            {
                if (other.X == _w.X + Wall.size && other.Y == _w.Y && other.Z == _w.Z)
                {
                    canAdd = true;
                    horizontalCenter.X += Wall.size / 2;
                    break;
                }
                else if (other.X == _w.X - Wall.size && other.Y == _w.Y && other.Z == _w.Z)
                {
                    canAdd = true;
                    horizontalCenter.X -= Wall.size / 2;
                    break;
                }
            }

            if (canAdd)
            {
                tmpWallsHorizontal.Add(other);
            }
        }

        // Search how many walls there is vertically
        Vector3 verticalCenter = new Vector3(w.X, w.Y, w.Z);
        List<Wall> tmpWallsVertical = new List<Wall>();
        tmpWallsVertical.Add(w);
        foreach (Wall other in walls)
        {
            if (handledWalls.Contains(other) || tmpWallsVertical.Contains(other)) continue;
            bool canAdd = false;
            foreach (Wall _w in tmpWallsVertical)
            {
                if (other.X == _w.X && other.Y == _w.Y && other.Z == _w.Z + Wall.size)
                {
                    canAdd = true;
                    verticalCenter.Z += Wall.size / 2;
                    break;
                }
                else if (other.X == _w.X && other.Y == _w.Y && other.Z == _w.Z - Wall.size)
                {
                    canAdd = true;
                    verticalCenter.Z -= Wall.size / 2;
                    break;
                }
            }

            if (canAdd)
            {
                tmpWallsVertical.Add(other);
            }
        }

        if (tmpWallsHorizontal.Count > tmpWallsVertical.Count)
        {
            // tmpWallsHorizontal has the longest "wall" now
        }
        else if (tmpWallsVertical.Count > tmpWallsHorizontal.Count)
        {
            // tmpWallsVertical has the longest "wall" now
        }
        else
        {
            // Both ways are the same length
        }
    }
}
public void CreateCollidersForExport()
{
List handledWalls=新列表();
foreach(墙中的墙w)
{
如果(handledWalls.Contains(w))继续;
扶手墙。添加(w);
//搜索水平方向上有多少面墙
矢量3水平中心=新矢量3(w.X,w.Y,w.Z);
List tmpWallsHorizontal=新列表();
tmpWallsHorizontal.Add(w);
foreach(墙中的其他墙)
{
如果(handledWalls.Contains(其他)| | tmpWallsHorizontal.Contains(其他))继续;
bool-canAdd=false;
foreach(tmpWallsHorizontal中的墙)
{
if(other.X==\u w.X+Wall.size&&other.Y==\u w.Y&&other.Z==\u w.Z)
{
canAdd=正确;
水平中心.X+=墙.size/2;
打破
}
else if(other.X==\u w.X-Wall.size&&other.Y==\u w.Y&&other.Z==\u w.Z)
{
canAdd=正确;
水平中心.X-=墙.size/2;
打破
}
}
如果(加拿大)
{
tmpWallsHorizontal.Add(其他);
}
}
//搜索垂直方向上有多少面墙
矢量3垂直中心=新矢量3(w.X,w.Y,w.Z);
List tmpWallsVertical=新列表();
tmpWallsVertical.Add(w);
foreach(墙中的其他墙)
{
如果(handledWalls.Contains(其他)| | tmpWallsVertical.Contains(其他))继续;
bool-canAdd=false;
foreach(tmpWallsVertical中的墙)
{
if(other.X===w.X&&other.Y===w.Y&&other.Z===w.Z+Wall.size)
{
canAdd=正确;
垂直中心Z+=墙尺寸/2;
打破
}
else if(other.X==\u w.X&&other.Y==\u w.Y&&other.Z==\u w.Z-Wall.size)
{
canAdd=正确;
垂直中心Z-=墙的尺寸/2;
打破
}
}
如果(加拿大)
{
tmpWallsVertical.Add(其他);
}
}
if(tmpWallsHorizontal.Count>tmpWallsVertical.Count)
{
//tmpWallsHorizontal现在拥有最长的“墙”
}
else if(tmpWallsVertical.Count>tmpWallsHorizontal.Count)
{
//tmpWallsVertical现在拥有最长的“墙”
}
其他的
{
//两条路的长度相同
}
}
}

我会尝试将此视为一种。我们的想法是,您可以在网格的任何一个单元上行走:每次碰到“墙”时,您都会开始泛洪填充,但泛洪填充仅在一个轴上工作(因此,您不是在所有四个方向上泛洪,而是只向上/下或左/右)

假设您拥有初始网格,并开始从左到右、从上到下迭代单元格:

[X][X][X][X]
[ ][X][ ][ ]
[ ][X][ ][ ]
[ ][X][ ][ ]
从左上角的单元格开始,注意它是一面墙,开始泛洪。由于只能向右泛洪,因此可以执行水平泛洪。您将覆盖标有“1”的区域,并在列表中记住该区域:

[1][1][1][1]                  0/0 -> 3/0
[ ][X][ ][ ]
[ ][X][ ][ ]
[ ][X][ ][ ]
你继续前进,最后撞到第二排的墙。不能向左洪水(无墙),不能向上洪水(已覆盖),不能向右洪水(无墙),但可以向下洪水-因此可以进行垂直洪水:

[1][1][1][1]                  1: 0/0 -> 3/0
[ ][2][ ][ ]                  2: 1/1 -> 1/3
[ ][2][ ][ ]
[ ][2][ ][ ]
现在你完成了。在此版本中,“X”始终只是一面墙的一部分。所以如果你有

[ ][X][ ][ ]
[X][X][X][X]
[ ][X][ ][ ]
[ ][X][ ][ ]
你会有三堵墙:

[ ][1][ ][ ]                  1: 1/0 -> 1/3
[2][1][3][3]                  2: 0/1 -> 0/1
[ ][1][ ][ ]                  3: 2/1 -> 3/1
[ ][1][ ][ ]
如果允许其他墙壁覆盖“X”单元,则可能只有两个:

[ ][1][ ][ ]                  1: 1/0 -> 1/3
[2][*][2][2]                  2: 0/1 -> 3/1
[ ][1][ ][ ]
[ ][1][ ][ ]

“*”表示被两堵墙覆盖的单元格。

请向我们展示您的非最佳代码。这是您想要的输出吗<代码>(0,0)-(0,3)和(0,1)-(3,1)?听起来您必须计算所有可能的组合才能找到最佳组合。如果你最后只有三面墙而不是两面墙,那会很糟糕吗?或者两个重叠的墙?如果墙交叉,那么如果水平墙在第二排呢?重叠不是问题,所以它们可以交叉和重叠。谢谢,这几乎是我已经做过的,我只需要在运行搜索之前对墙进行排序。