Python numpy 替换特定模式中的值



我正在尝试使用A*星(A-Star)算法"避开墙壁"。 我的数组如下所示:

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

我只能在0(零)和1(一)上行走。 我希望我的人工智能走在路径的中心,假设有足够的空间走路。人工智能可以对角线行走。

例如,代替[1, 1, 1, 0, 0, 0, 1, 1, 1],(第一个数组),因为有足够的空间不阻塞路径,我怎么能用[1, 1, 1, 1, 0, 1, 1, 1, 1],替换它

事后:

如果我们走在中心,这里的最佳路径是[4 3 2 2 3 4].

另外,如果我们在这种情况下得到最短的路径怎么办 如果我们从 (3, 0) 到 (4, 5) 将是[3 3 3 3 4 4]的。如果我们 只是不希望墙壁在我们的道路上,就像以前有一个元素一样 墙[3 3 2 2 3 4],如果我们允许开始和 完成触摸墙壁?

编辑: Ali_Sh答案是我最初寻找的,也是公认的答案。

如果a是主数组,则每行中间 0 的索引可以通过以下方式实现:

cond = np.where(a == 0)
unique = np.unique(cond[0], return_index=True, return_counts=True)
ind = unique[1] + unique[2] // 2
cols = cond[1][ind]  # --> [4 3 2 2 3 4]

它可用于将ones数组中的1值替换为主数组形状:

one = np.ones(shape=a.shape)
one[np.arange(len(one)), cols] = 0

这将:

[[1. 1. 1. 1. 0. 1. 1. 1. 1.]
[1. 1. 1. 0. 1. 1. 1. 1. 1.]
[1. 1. 0. 1. 1. 1. 1. 1. 1.]
[1. 1. 0. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 0. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 0. 1. 1. 1. 1.]]

下面是一个示例,它只查找每行中为零的所有值,并将路径设置为中间参数。如果有一行有两个零补丁,这可能会遇到麻烦。在这种情况下,您需要确保零补丁上方和下方的参数也是零补丁。

我在这里使用了matplotlib来可视化路径:

import matplotlib.pyplot as plt
p = []
A = [[1, 1, 1, 0, 0, 0, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 1, 1, 1],
[1, 0, 0, 0, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 1, 1, 1, 1, 1],
[1, 1, 0, 0, 0, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 0, 1, 1, 1]]
for i in range(len(A)):
ptemp = []
for j in range(len(A[0])):
if A[i][j] == 0:
ptemp.append(j) # find all the zero values
p.append(ptemp[int(len(ptemp)/2)]) # set the path as the center zero value

print(p)
plt.imshow(A[::-1])
plt.plot(p[::-1],range(len(A)))
plt.show()

对于问题的更新部分,如果我们有列的另一种路径,而不是我之前答案中指定的最佳路径(例如[3 1 1 1 2 3]代替[4 3 2 2 3 4]),只需使用以下方法即可应用:

cols = np.array([3, 1, 1, 1, 2, 3])
one = np.ones(shape=a.shape)
one[np.arange(len(one)), cols] = 0
# [[1. 1. 1. 0. 1. 1. 1. 1. 1.]
#  [1. 0. 1. 1. 1. 1. 1. 1. 1.]
#  [1. 0. 1. 1. 1. 1. 1. 1. 1.]
#  [1. 0. 1. 1. 1. 1. 1. 1. 1.]
#  [1. 1. 0. 1. 1. 1. 1. 1. 1.]
#  [1. 1. 1. 0. 1. 1. 1. 1. 1.]]

如果我们想要边界以外的所有路径,我们可以将以下代码添加到以前的答案代码中:

如果我们没有完全走在中心,但只是避开"近墙"路径 甚至与墙壁偏移 1 个:

cols_min = cols - (unique[2] - 2) // 2
cols_max = cols + (unique[2] - 2) // 2
one[np.arange(len(one)), cols_min] = 0
one[np.arange(len(one)), cols_max] = 0
# [[1. 1. 1. 1. 0. 1. 1. 1. 1.]
#  [1. 1. 0. 0. 0. 1. 1. 1. 1.]
#  [1. 1. 0. 1. 1. 1. 1. 1. 1.]
#  [1. 1. 0. 1. 1. 1. 1. 1. 1.]
#  [1. 1. 1. 0. 1. 1. 1. 1. 1.]
#  [1. 1. 1. 1. 0. 1. 1. 1. 1.]]

当我们可以触摸第一行和最后一行的墙壁(这里是其中之一)时,我们可以将以下代码添加到之前的答案代码中:

col_min_first = cols[0] - unique[2][0] // 2
col_min_last = cols[-1] - unique[2][-1] // 2
one[0, col_min_first:cols[0]] = 0
one[-1, col_min_last:cols[-1]] = 0
# [[1. 1. 1. 0. 0. 1. 1. 1. 1.]
#  [1. 1. 1. 0. 1. 1. 1. 1. 1.]
#  [1. 1. 0. 1. 1. 1. 1. 1. 1.]
#  [1. 1. 0. 1. 1. 1. 1. 1. 1.]
#  [1. 1. 1. 0. 1. 1. 1. 1. 1.]
#  [1. 1. 1. 0. 0. 1. 1. 1. 1.]]

最后,如果我们想找到最短的路径,我们可以通过找到其中0数最多的列来实现目标,首先,然后找到离该列最近的列索引0,其中该列不包含0

ind_max = np.argmax(np.sum(a == 0, axis=0))
mask_rows = a[:, ind_max] != 0
mask_col_min = a[:, ind_max - 1] == 0
mask_col_max = a[:, ind_max + 1] == 0
ind_max = np.where(mask_rows & mask_col_min, ind_max - 1, ind_max)
ind_max = np.where(mask_rows & mask_col_max, ind_max + 1, ind_max)
one = np.ones(shape=a.shape)
one[np.arange(len(one)), ind_max] = 0
# [[1. 1. 1. 0. 1. 1. 1. 1. 1.]   | a = np.array([[1, 1, 1, 0, 0, 0, 1, 1, 1],        [[1. 1. 1. 0. 1. 1. 1. 1. 1.]
#  [1. 1. 1. 0. 1. 1. 1. 1. 1.]   |               [1, 0, 0, 0, 0, 0, 1, 1, 1],         [1. 1. 1. 0. 1. 1. 1. 1. 1.]
#  [1. 1. 1. 0. 1. 1. 1. 1. 1.]   |               [0, 0, 0, 1, 1, 1, 1, 1, 1],   -->   [1. 1. 0. 1. 1. 1. 1. 1. 1.]
#  [1. 1. 1. 0. 1. 1. 1. 1. 1.]   |               [1, 0, 0, 0, 1, 1, 1, 1, 1],         [1. 1. 1. 0. 1. 1. 1. 1. 1.] 
#  [1. 1. 1. 0. 1. 1. 1. 1. 1.]   |               [1, 1, 0, 0, 0, 1, 1, 1, 1],         [1. 1. 1. 0. 1. 1. 1. 1. 1.]
#  [1. 1. 1. 0. 1. 1. 1. 1. 1.]]  |               [1, 1, 1, 0, 0, 0, 1, 1, 1]])        [1. 1. 1. 0. 1. 1. 1. 1. 1.]]