Search code examples
c#arraysperformanceneighbours

Fastest way to check each neighbor in 2D array


I am working on a random dungeon generator just for fun / as a side project to learn some new things. I have written a function that returns an integer hash value for any given cell, which gives you information about what type of gameobject it should be. i.e. if it is a wall, what direction to face, is it a corner, etc. Here is what the function currently looks like.

    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;
    }

My question is, is there a more efficient and faster way to do these checks that perhaps I am not thinking of? The dungeon array ranges in size from 100x100 to 1000x1000, though the function is not called on each cell. I have a separate List that contains rooms and there start and end indexes for each direction that I iterate over to instantiate objects.


Solution

  • What you're doing is essentially applying a form of convolution. Without more context as to how your method is being called or how you're using the returned hash value, what you're doing seems to be close to the most efficient way to iterate a 3x3 grid. Assuming your dungeon2dArray is a char[][] and is global, this is what I believe to be a bit clearer and more concise (you'll have to adjust how to interpret the resulting sum based on the order of iteration).

    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;
    }
    

    Note: This method doesn't do any boundary checking, so if x or y index is along edge, indices will fail.

    Each of the array accesses is O(1) and iterating over your entire dungeon array is O(n^2), so the only way to get better efficiency would be to combine per cell methods calls, but this is still only a constant factor, so not really more efficient, but depending on the calculation could boost performance a little bit.