在二维数组中查找相邻单元格的有效方法

3
我有一个Tiles类的二维数组。在创建游戏场地时,我需要生成所有直接相邻的单元格(水平、垂直、对角线)。我从生成填充每个单元格的新瓷砖开始,然后(当完成时)通过以下循环遍历2d数组以计算邻居:
int dnDistance= 1; //Direct Neighbor Distance.

for (int iMapY = 0; iMapY < playfieldHeight; iMapY++)
{
    for (int iMapX = 0; iMapX < playfieldWidth; iMapX++)
    {
        for (int yOffset = -dnDistance; yOffset <= dnDistance; yOffset++)
        {
            for (int xOffset = -dnDistance; xOffset <= dnDistance; xOffset++)
            {
                if ((iMapX + xOffset >= 0 && iMapX + xOffset < playfieldWidth) && (iMapY + yOffset >= 0 && iMapY + yOffset < playfieldHeight))
                { 
                    if (!(yOffset == 0 && xOffset == 0))
                    { 
                            playfieldTiles[iMapX, iMapY].dnTiles.Add(playfieldTiles[iMapX + xOffset, iMapY + yOffset]);
                    }
                }
            }
        }
    }
}

使用这种方法,我必须再次循环遍历整个二维数组,创建一个for循环,在一个for循环中,在一个for循环中,在一个for循环中,有时候不是很清楚。肯定有更好的方法,对吧?
我找到了一个帖子,看起来有些相似但不完全一样,或者我没有正确理解它:

你正在实现你链接的帖子中相同的想法,对我来说这似乎是正确的方法。 - NiVeR
一般来说,如果你最终得到了两三个以上嵌套的for循环,那么除非你正在处理一个四维数组或类似问题,否则就说明你有些做法上的问题。@Aybe 展示了如何只用两个for循环来完成相同的任务。 - AustinWBryan
1个回答

1

只要它正常工作,那就没问题!

这里有一个小优化,可以使调试更容易:

var playfieldHeight = 5;
var playfieldWidth = 5;
var playfieldTiles = new byte[playfieldWidth + dnDistance * 2, playfieldHeight + dnDistance * 2];
var len1 = playfieldWidth * playfieldHeight;
var len2 = dnDistance * 2 + 1;

for (var i = 0; i < len1; i++)
{
    var ix = i % playfieldWidth;
    var iy = i / playfieldWidth;
    for (var j = 0; j < len2 * len2; j++)
    {
        var jx = j % len2 - dnDistance;
        var jy = j / len2 - dnDistance;
        Console.WriteLine($"x1: {ix}, y1: {iy}, x2: {jx}, y2: {jy}");
    }
}

你现在只有两个循环,一个是字段循环,另一个是邻居循环。
你可以通过单个for进一步优化,但我认为可读性会降低(在循环内部)。

我想第二次看这个的时候我已经有点理解了。使用第一个for循环和玩家界面中总方块数(在本例中为25),将两个for循环组合成一个大循环。ix和iy是iMapX和iMapY。同样的事情也适用于计算邻居的2个循环。如果我没错的话,这不会对性能产生任何影响,但确实使代码更易读。我会把它标记为答案(因为我认为不会在性能方面得到改进)并深入研究。谢谢 :) - Sander Koldenhof
不客气,我只是像以前一样绘制像素:在偏移量和X/Y之间进行转换。这真的简化了调试过程,就像我说的那样,它本来可以是一个循环,但边界会很奇怪,而这里很简单,性能也不应该成为问题,除非你循环遍历了大量的项目。 - aybe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接