检查2D阵列中每个邻居的最快方法

时间:2018-02-19 18:29:29

标签: c# arrays performance neighbours

我正在开发一个随机的地牢生成器,只是为了好玩/作为一个侧面项目来学习一些新东西。我编写了一个函数,它返回任何给定单元格的整数哈希值,它为您提供有关它应该是什么类型的游戏对象的信息。即如果它是一面墙,面向什么方向,它是一个角落等等。这是目前的功能。

    private int CellHashValue(int xIndex, int yIndex, char centerTile)
    {
        int hashValue = 0;
        if (dungeon2DArray[xIndex - 1, yIndex + 1] == centerTile)
        {
            hashValue += 1;
        }
        if (dungeon2DArray[xIndex, yIndex + 1] == centerTile)
        {
            hashValue += 2;
        }
        if (dungeon2DArray[xIndex + 1, yIndex + 1] == centerTile)
        {
            hashValue += 4;
        }
        if (dungeon2DArray[xIndex - 1, yIndex] == centerTile)
        {
            hashValue += 8;
        }
        if (dungeon2DArray[xIndex + 1, yIndex] == centerTile)
        {
            hashValue += 16;
        }
        if (dungeon2DArray[xIndex - 1, yIndex - 1] == centerTile)
        {
            hashValue += 32;
        }
        if (dungeon2DArray[xIndex, yIndex - 1] == centerTile)
        {
            hashValue += 64;
        }
        if (dungeon2DArray[xIndex + 1, yIndex - 1] == centerTile)
        {
            hashValue += 128;
        }
        return hashValue;
    }

我的问题是,是否有一种更有效,更快捷的方法来进行这些检查,或许我没想到?地牢阵列的大小范围从100x100到1000x1000,但不会在每个单元格上调用该功能。我有一个单独的列表,其中包含房间以及我迭代以实例化对象的每个方向的开始和结束索引。

2 个答案:

答案 0 :(得分:1)

由于您使用数组来构建地图,因此访问时间因直接访问而不变。因此,检查每个数组索引的过程很快。

加快功能有几件小事。

  1. 在相应的if语句中返回hashValue。这将删除几行代码。
  2. 通过删除hashValue变量并返回硬编码值,将从进程中删除变量初始化。这比看起来更重要。创建和删除对象需要花费时间,大量时间
  3. xIndexyIndex可以对该对象设为全局。 小心实现这个想法。由于xIndex和yIndex在检查特定条件时没有变化,因此它们可以在对象中变为全局。这减少了传入的参数数量。由于Java不通过引用传递,因此创建了相同大小的对象并将其传递给函数。一个简单的int不会对速度产生太大影响,但如果你有一个包含许多变量的对象,则需要更多的时间来构建另一个具有相同价值的对象。
  4. 每个检查都可以移动到单独的功能。这主要有助于以后的可读性和调试。有一些速度优势但它们依赖于项目。通过观察对象如何被初始化/操纵,通常可以强制某些条件为真。当不需要检查逻辑并且可以在没有检查的情况下达成结论时,则需要更少的时间。
  5. 只是一些想法。如果你有时间研究,第2和第3点使用low latency/high frequency中的概念。另外,请注意,其中一些概念并未被视为最佳实践。

答案 1 :(得分:1)

您正在做的事情主要是应用一种卷积形式。如果没有关于如何调用方法或如何使用返回的哈希值的更多上下文,您正在做的事情似乎接近于迭代3x3网格的最有效方式。假设你的dungeon2dArray是一个char [] []并且是全局的,我认为这更清晰,更简洁(你必须根据迭代的顺序调整如何解释结果总和)。

private int CellHashValue(int x, int y) {
    int hashSum = 0;   // Hash sum to return
    int hashValue = 1; // Increases as power of 2 (1,2,4,8,...128)
    char centerTile = dungeon2DArray[x, y]; // Cache center tile

    for (int r = -1; r <= 1; r++) {
        for (int c = -1; c <= 1; c++) {
            if (r == 0 && c == 0) continue; // Skip center tile
            if (dungeon2DArray[x + c, y + r] == centerTile) {
                hashSum += hashValue;
            }
            hashValue *= 2; // Next power of two
            //could also bit shift here instead 
            // hashValue <<= 1
        }
    }
    return hashSum;
}

注意:此方法不进行任何边界检查,因此如果x或y索引沿着边缘,则索引将失败。

每个数组访问都是O(1)并且遍历整个地牢数组的迭代是O(n ^ 2),因此获得更高效率的唯一方法是组合每个单元格方法调用,但这仍然只是一个恒定的因素,所以效率并不高,但取决于计算可以提高性能。