Python - 在“数组”中查找最低位置

4

我的目标是将一个“怪物”(mX,mY)在2D网格中向玩家(pX,pY)移动。怪物可以朝着8个不同的方向移动。

我已经有了这方面的工作代码,但我对Python非常陌生。我强烈感觉到我的代码很糟糕,并且有更快的方法可以做到这一点。

我通过在怪物位置周围创建一个3 x 3的数组(数组位置4),并将其填充为该数组位置到玩家的距离来完成此操作。然后,我检查是否有任何低于怪物当前距离的,如果是,则将怪物移动到该位置。

enter image description here

这是我当前的代码。如果让你感到恶心,请原谅,我还在学习中。

# get the distance between the monster and player
dist = math.hypot(pX - mX, pY - mY)

if dist > 1.5 and dist < 10:

    # make an 'array' grid to store updated distances in
    goto = np.full((3, 3), 10, dtype=float)

    # if each position in the array passes a
    # collision check, add each new distance

    if collisionCheck(mID, (mX-1), (mY-1), mMap) == 0:
        goto[0][0] = round(math.hypot(pX - (mX-1), pY - (mY-1)), 1)

    if collisionCheck(mID, mX, (mY-1), mMap) == 0:
        goto[0][1] = round(math.hypot(pX - mX, pY - (mY-1)), 1)

    if collisionCheck(mID, (mX+1), (mY-1), mMap) == 0:
        goto[0][2] = round(math.hypot(pX - (mX+1), pY - (mY-1)), 1)

    if main.collisionCheck(mID, (mX-1), mY, mMap) == 0:
        goto[1][0] = round(math.hypot(pX - (mX-1), pY - mY), 1)

    # goto[1][1] is skipped since that is the monsters current position

    if collisionCheck(mID, (mX+1), mY, mMap) == 0:
        goto[1][2] = round(math.hypot(pX - (mX+1), pY - mY), 1)

    if collisionCheck(mID, (mX-1), (mY+1), mMap) == 0:
        goto[2][0] = round(math.hypot(pX - (mX-1), pY - (mY+1)), 1)

    if collisionCheck(mID, mX, (mY+1), mMap) == 0:
        goto[2][1] = round(math.hypot(pX - mX, pY - (mY+1)), 1)

    if collisionCheck(mID, (mX+1), (mY+1), mMap) == 0:
        goto[2][2] = round(math.hypot(pX - (mX+1), pY - (mY+1)), 1)

    # get the lowest distance, and its key
    lowest = goto.min()
    lowestKey = goto.argmin()

    # if the lowest distance is lower than monsters current position, move

    if lowest < dist:
            if lowestKey == 0: 
                    newX = mX - 1
                    newY = mY - 1

            if lowestKey == 1:
                    newY = mY - 1

            if lowestKey == 2: 
                    newX = mX + 1
                    newY = mY - 1

            if lowestKey == 3: 
                    newX = mX - 1

            if lowestKey == 5: 
                    newX = mX + 1

            if lowestKey == 6: 
                    newY = mY + 1
                    newX = mX - 1

            if lowestKey == 7:
                    newY = mY + 1

            if lowestKey == 8: 
                    newX = mX + 1
                    newY = mY + 1

最干净、最简单、最快的方式是什么?这将一次循环多个怪物!


编辑:添加了collisionCheck()

def collisionCheck(mobID, newX, newY, mapName):
    blocked = 0
    if mobs.mobPos_arr[mapName][newX,newY] > -1:
        blocked = 1

    if mapCollision_arr[mapName][newX,newY] > 0:
        blocked = 1

    return int(blocked) 

也许将这个问题移动到代码审查会更好?在此之前:我已经准备好参与了。“最干净、最简单、最快速的方法”本身就是一个合格的问题,但在我看来它并不像一个问题陈述。 - Alex Yu
1个回答

1
你可以使用数组广播来一次性计算潜在的新位置:
delta = np.arange(-1, 2)
move = np.stack([np.repeat(delta, 3), np.tile(delta, 3)], axis=1)

# Assuming that m_pos.shape is (N: number of monsters, 2).
options = m_pos[:, None, :] + move  # Shape (N, 9, 2).

# Collision check.
zip_pos = tuple(zip(*options.reshape(-1, 2)))
check_1 = mobs.mobPos_arr[mapName][zip_pos] > -1
check_2 = mapCollision_arr[mapName][zip_pos] > 0
valid = ~(check_1 | check_2).reshape(-1, 9)

# Now compute distance.
distance = np.linalg.norm(p_pos - options, axis=-1)

# Incorporate whether moves are valid.
valid_distance = np.where(valid, distance, np.inf)

# Select the best move (the one with smallest valid distance).
best = np.argmin(valid_distance, axis=-1)

# Select new positions from the options, based on best move estimation.
new_pos = options[np.arange(len(options)), best]

谢谢,这非常简洁。我能把collisionCheck()加进去吗?我可以移动到的位置需要先通过它来运行。 - user1022585
1
@user1022585 那就取决于collisionCheck的详细实现(是否可以向量化)。你能提供一下具体的实现吗? - a_guest

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接