我正在尝试分析StarCraft 2 bot API给出的地图地形。
此分析的初学者任务是找到收割者的悬崖,这是SC2中的特殊单元,可以在悬崖上上下跳跃。
为解决此问题,我分析了点本身不可路径(= cliff)且南北两个点可路径的点。数组中可路径化的点被标记为1,而不可路径化的为0。
地形图以2D numpy数组形式存在。以下是从较大的200x200阵列中摘录的一部分:
import numpy as np
example = np.array([[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 0, 0, 0]])
在这里,点[2,1]和[2,2]将符合以下标准:点本身不可移动(= 0),且点上方和下方的点可移动(= 1)。
这可以通过以下代码实现:
above = np.roll(example, 1, axis=0) # Shift rows downwards
below = np.roll(example, -1, axis=0) # Shift rows upwards
result = np.zeros_like(example) # Create array with zeros
result[(example == 0) & (above == 1) & (below == 1)] = 1 # Set cells to 1 that match condition
print(repr(result))
# array([[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]])
现在我的问题是,是否可以用更少的代码实现相同的目标?
np.roll函数每次都会创建一个新的np.array对象,因此分析数百个附近的点可能会导致100行不必要的代码并占用大量内存。
我正试图找到类似的东西
result = np.zeros_like(example)
result[(example == 0) & (example[-1, 0] == 1) & (example[1, 0 == 1)] = 1
# or
result[(example == 0) & ((example[-1:2, 0].sum() == 2)] = 1
括号中的数字显示了相对于当前分析点的相对位置,但我不知道是否有办法使它与numpy一起使用。
在检查第零行时,第零行的结果也不清楚:它可以访问最后一行,导致错误或返回默认值(0或1)。
编辑: 我找到了this post,它向我指出了可以在此处应用的scipy convolve2d函数,这可能是我正在寻找的东西:
import numpy as np
from scipy import signal
example = np.array([[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 0, 0, 0]])
kernel = np.zeros((3, 3), dtype=int)
kernel[::2, 1] = 1
print(repr(kernel))
# array([[0, 1, 0],
# [0, 0, 0],
# [0, 1, 0]])
result2 = signal.convolve2d(example, kernel, mode="same")
print(repr(result2))
# array([[0, 1, 1, 0],
# [0, 0, 0, 0],
# [0, 2, 2, 0],
# [0, 0, 0, 0],
# [0, 1, 1, 0]])
result2[result2 < 2] = 0
result2[result2 == 2] = 1
print(repr(result2))
# array([[0, 0, 0, 0],
# [0, 0, 0, 0],
# [0, 1, 1, 0],
# [0, 0, 0, 0],
# [0, 0, 0, 0]])
Edit2: 另一个解决方案可能是scipy.ndimage.minimum_filter,它的工作方式似乎与此类似:
import numpy as np
from scipy import ndimage
example = np.array([[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 0, 0, 0]])
kernel = np.zeros((3, 3), dtype=int)
kernel[::2, 1] = 1
print(repr(kernel))
# array([[0, 1, 0],
# [0, 0, 0],
# [0, 1, 0]])
result3 = ndimage.minimum_filter(example, footprint=kernel_vertical, mode="constant")
print(repr(result3))
# array([[0, 0, 0, 0],
# [0, 0, 0, 0],
# [0, 1, 1, 0],
# [0, 0, 0, 0],
# [0, 0, 0, 0]])