Lost Robot
Lost Robot

Reputation: 1321

Finding adjacent cells in a grid without exceptions

There are times when I have an area in a 2D array, and I need to check for adjacent cells. Normally I would do the following:

adjacentCells = (world[y+1][x]==1)+(world[y-1]==1)+(world[y][x+1]==1)+(world[y][x-1]==1)

This would calculate how many orthogonally adjacent cells to the point (x,y) are equal to 1. The issue is, doing things this way wraps around the matrix if my x or y coordinates are 0 (the top or left edge), and it causes an exception if the point (x,y) is on a different edge. This makes the code look like this:

def adjacentCells(x,y):
    total=0
    if x==0:
        total += 1
    else:
        total += world[y][x-1]
    if y==0:
        total += 1
    else:
        total += world[y-1][x]
    try:
        total += world[y][x+1]
    except:
        total += 1
    try:
        total += world[y+1][x]
    except:
        total += 1
    return total

Is there a way to fix this issue, in a way about as simple as the uppermost example?

Upvotes: 0

Views: 2280

Answers (2)

martineau
martineau

Reputation: 123473

For doing something as trivial as adding up the values of up to 4 cells, I'd just write the code for each case—it only requires one line per cell location. It may be longer than using a loop construct, but avoids looping overhead and it's all pretty much boilerplate.

It's also relatively easy to read and understand, and would make it easier to special-case one of the locations should doing that be needed for some reason.

Here's what I mean:

world = [[1, 1, 1, 1],
         [1, 1, 1, 1],
         [1, 1, 1, 1]]

MIN_X, MAX_X = 0, len(world[0])-1
MIN_Y, MAX_Y = 0, len(world)-1

def adjacentCells(x, y):
    return((world[  y][x-1] if MIN_Y <=   y <= MAX_Y and MIN_X <= x-1 <= MAX_X else 1)
         + (world[  y][x+1] if MIN_Y <=   y <= MAX_Y and MIN_X <= x+1 <= MAX_X else 1)
         + (world[y-1][  x] if MIN_Y <= y-1 <= MAX_Y and MIN_X <=   x <= MAX_X else 1)
         + (world[y+1][  x] if MIN_Y <= y+1 <= MAX_Y and MIN_X <=   x <= MAX_X else 1))

print(adjacentCells(0, 0))  # -> 4
print(adjacentCells(1, 1))  # -> 4

Upvotes: 1

Duncan
Duncan

Reputation: 95692

I would do it something like this:

def adjacentCells(x, y):
    neighbours = [(x-1, y), (x, y-1), (x+1, y), (x, y+1)]
    return sum(
        world[b][a] if 0 <= b < len(world) and 0 <= a < len(world[b])
        else 1
        for (a,b) in neighbours)

So get a list of potential neighbours but check each one is valid before you use it.

If the neighbours of border cells counted as 0 instead of 1 it would be simpler, then you would simply filter the list of neighbours before using it.

Upvotes: 1

Related Questions