简体   繁体   English

在2D网格上找到8个邻居的节点

[英]Find a nodes 8 neighbors on a 2D grid

I need to find the cardinal and diagonal neighbors of any node in a two dimensional array. 我需要找到二维数组中任何节点的基数和对角线邻居。 Take the below array. 采取以下数组。 I'm searching from the 1 which is [1, 1] on the array. 我正在从数组中[1,1]的1中搜索。 It should return the surrounding 0's. 它应该返回周围的0。 I can find the neighbors just find as shown in some of the below code but they're too slow. 我可以找到邻居,就像下面的一些代码所示,但是它们太慢了。

[[0, 0, 0]
 [0, 1, 0]
 [0, 0, 0]]

I can brute force it like this to return the coordinates of all 8 surrounding nodes. 我可以像这样蛮力返回周围所有8个节点的坐标。

def ReturnNeighbors(x, y):
    numpy.array([(x-1, y), (x, y-1), (x+1, y), (x, y+1),
               (x-1, y-1), (x+1, y+1), (x-1, y+1), (x+1, y-1)])

def ReturnNeighbors_4(x, y):
    for i in xrange(x - 1, x + 2):
        for j in xrange(y - 1, y + 2):
            if (i, j) != (x, y):
                yield (i, j)

Or by calculating the distance to all nodes and returning those with a distance < 2 but these and the other solutions I've figured out are slow. 或者通过计算到所有节点的距离并返回距离<2的节点,但是我发现的这些和其他解决方案都很慢。 The whole reason I'm learning to numpy is for the speed. 我要学习麻木的全部原因是为了提高速度。 I think I need to use scipy convolve2d or a cKDtree but they're too complicated for me. 我想我需要使用scipy convolve2d或cKDtree,但是它们对我来说太复杂了。

The way I handled this before switching to numpy is my array was full of actual node objects as the values. 我切换到numpy之前的处理方式是我的数组充满了实际的节点对象作为值。 Each object stored its x and y coordinates in the grid and a set of its neighbors. 每个对象将其x和y坐标存储在网格中以及一组相邻对象。 Like this. 像这样。 I can't use this method anymore as filling a gigantic array full of nodes takes ages. 我不能再使用此方法了,因为要填充一个巨大的充满节点的数组需要很长时间。 Even in a small 100x100 map that's 10000 node objects! 即使在100x100的小型地图中,也可以包含10000个节点对象! I plan to later not only have much larger maps but multiple maps active at any given time. 我计划以后不仅要拥有更大的地图,而且要在任何给定时间激活多个地图。 I've actually ran out of memory trying to create bigger maps due to the nodes imprint. 由于节点的印记,我实际上已经用尽了内存来尝试创建更大的地图。 It works for little dungeons but not worlds with multiple maps being simulated. 它适用于小型地牢,但不适用于模拟了多个地图的世界。

ExampleNode(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.neighbors = set()

        # The neighbors are found and added to the above set later.

node = Example(0, 0)

for neighbor in node.neighbors:
    do thing with each neighbor

I need a nodes neighbors for a variety of reasons. 由于多种原因,我需要一个节点邻居。 Smoothing a map using cellular automata, splattering blood nearby in combat, pathfinding with breadth first search and more. 使用细胞自动机对地图进行平滑处理,在战斗中向附近溅血,使用广度优先搜索进行寻路等等。 This is for a roguelike I'm creating. 这是针对我正在创建的流氓对象。 The brute force method works fine for small 60x60 dungeons but now I'm expanding the scope and generating a world map. 蛮力方法适用于60x60小型地牢,但现在我正在扩大范围并生成世界地图。 It's only 200x200 and irritatingly slow. 它只有200x200,而且非常慢。

Let's assume that the input array is named A that holds all the integers and we are working on just the elements that are 1s in it and would try to get their neighbours. 假设输入数组的名称为A ,其中包含所有整数,并且我们仅处理其中的1s并尝试获取其邻居。 Here's one approach to do so - 这是这样做的一种方法-

# Get offsets for row and column
R_offset,C_offset = np.meshgrid(np.arange(-1,2),np.arange(-1,2))

# Get row and column indices for places where elements are 1s
R_match,C_match = np.nonzero(A==1)

# Store number of matches as it would be frequently used
N = R_match.size

# Get offsetted row, col indices for all matches
R_idx = (R_match[:,None,None] + R_offset).reshape(N,-1)
C_idx = (C_match[:,None,None] + C_offset).reshape(N,-1)

# Based on boundary conditions set invalid ones to zeros
valid_mask = (R_idx>=0) & (C_idx>=0) & (R_idx<A.shape[0]) & (C_idx<A.shape[1])
valid_mask[:,4] = 0 # Set the pivot(self/center) ones to invalid

# Using valid mask, "cut off" elements from each group of 9 elems
cut_idx = valid_mask.sum(1).cumsum()

# Finally form groups
grps_R = np.split(R_idx[valid_mask],cut_idx)[:-1]
grps_C = np.split(C_idx[valid_mask],cut_idx)[:-1]

Sample run and explanation on how to interpret and use the outputs - 样本运行以及有关如何解释和使用输出的解释-

In [256]: A
Out[256]: 
array([[1, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0],
       [0, 0, 0, 0, 1]])

In [257]: grps_R
Out[257]: [array([1, 0, 1]), array([1, 2, 3, 1, 3, 1, 2, 3]), array([2, 3, 2])]

In [258]: grps_C
Out[258]: [array([0, 1, 1]), array([1, 1, 1, 2, 2, 3, 3, 3]), array([3, 3, 4])]

Thus, we have three groups based on the three 1s in A . 因此,基于A的三个1s ,我们有三个组。

The first one is at the top left corner - 第一个在左上角-

In [259]: np.column_stack((R_match[0],C_match[0]))  # First point
Out[259]: array([[0, 0]])

In [260]: np.column_stack((grps_R[0],grps_C[0]))    # Its three neighbors
Out[260]: 
array([[1, 0],
       [0, 1],
       [1, 1]])

The second one is at (2,2) - 第二个是(2,2) -

In [263]: np.column_stack((R_match[1],C_match[1]))  # Second point 
Out[263]: array([[2, 2]])

In [264]: np.column_stack((grps_R[1],grps_C[1]))    # Its eight neighbors
Out[264]: 
array([[1, 1],
       [2, 1],
       [3, 1],
       [1, 2],
       [3, 2],
       [1, 3],
       [2, 3],
       [3, 3]])

Finally the third one is at (4,5) - 最后第三个是(4,5) -

In [265]: np.column_stack((R_match[2],C_match[2]))  # Third point 
Out[265]: array([[3, 4]])

In [266]: np.column_stack((grps_R[2],grps_C[2]))    # Its three neighbors
Out[266]: 
array([[2, 3],
       [3, 3],
       [2, 4]])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM