I am developing a bot for Starcraft II. In my code for unit movement, I often find myself doing this:
- Calculate points around the current position of the unit
- Check if these points are valid and can be reached
- Get the best n points that fit condition A (for example, the n points that are furthest away from the closest enemy unit)
- Of these n points, get the best point that fits condition B (for example, the point that is closest to the closest friendly unit)
I already made a numpy version to speed it up a bit, but would like this to run even faster. Maybe there is a way to combine the two conditions somehow.
import heapq import math import timeit import numpy as np # Point2 objects are needed here for the starcraft bot, they have .x and .y properties # positions have 15 decimal places from sc2.position import Point2 DIRECTIONS_AMOUNT = 16 # add  to have current position in points DIRECTION_OFFSETS = (  + [round(math.cos(2 * math.pi / DIRECTIONS_AMOUNT * p), 15) for p in range(DIRECTIONS_AMOUNT)],  + [round(math.sin(2 * math.pi / DIRECTIONS_AMOUNT * p), 15) for p in range(DIRECTIONS_AMOUNT)], ) # the current position of the unit position = Point2((65.11906509381345, 127.15779037493655)) # urrent position of closest enemy closestEnemy = Point2((74.11906509381345, 112.15779037493655)) # current position of closest friend closestFriend = Point2((68.11906509381345, 131.15312313133655)) # directions + original position for the case that standing still is the best option retreatPoints = [ Point2((position.x + DIRECTION_OFFSETS[p], position.y + DIRECTION_OFFSETS[p])) for p in range(DIRECTIONS_AMOUNT + 1) ] # select some points which are far away from the enemy retreatPointsChoice = heapq.nlargest(3, retreatPoints, key=lambda p: p.distance_to(closestEnemy)) # final point where the unit moves to based on distance to closest friend retreatPoint = min(retreatPointsChoice, key=lambda p: p.distance_to(closestFriend)) # with numpy, i improved it to this: np_retreatPoints = np.array(retreatPoints) def numpy_distance_sort(direction_points, target_point, amount=6, sort="min"): if sort == "max": results = np.add( np.square(np.subtract(target_point.x, direction_points[:, 0])), np.square(np.subtract(target_point.y, direction_points[:, 1])), ) if sort == "min": results = -1 * np.add( np.square(np.subtract(target_point.x, direction_points[:, 0])), np.square(np.subtract(target_point.y, direction_points[:, 1])), ) return [np_retreatPoints[i] for i in np.argpartition(-results, amount)[:amount]] np_retreatPointsChoice = numpy_distance_sort(np_retreatPoints, closestEnemy, 3, "max") np_retreatPoint = min(retreatPointsChoice, key=lambda p: p.distance_to(closestFriend))