def find_adhesion_cone_circle_centered(b, r): """ Compute the coordinates of the intersection between the circle of center b and radius r and its tangent passing by a. A is at the origin of the space :param b: Position of point B :type b: Position :param r: Sum of the radius of A and B :type r: float :return: The coordinates of the intersections :rtype: tuple(Position) """ d2 = b.x**2 + b.x**2 r2 = r**2 norm_c_2 = d2 - r2 norm_c = math.sqrt(norm_c_2) # NB can be solved with determinant computation # Solving using scalar product and vectorial product and using the # the geometrical projection to have explicit expression of sin and cos p1 = Position(*solve_x_y([b.x, -b.x], [b.x, b.x], [norm_c_2, norm_c * r])) p2 = Position(*solve_x_y([b.x, b.x], [b.x, -b.x], [norm_c_2, norm_c * r])) return (p1, p2)
def check_velocity_constraint(entity1, entity2, max_speed): """ :param entity1: :type entity1: Entity :param entity2: :type entity2: Entity :return: :rtype: """ origin = Position.from_entity(entity1) b = Position.from_entity(entity2) - origin d = math.sqrt(b.x**2 + b.x**2) r = entity1.radius + entity2.radius if d - r < 2 * max_speed: p1, p2 = find_adhesion_cone_circle_centered(b, r) # diff_vel = entity1.vel - entity2.vel # orthogonal because tangent definition ray_normals = [b - p1, b - p2] np.array([[ray_normals[0].x, ray_normals[0].y], [ray_normals[0].x, ray_normals[0].y]]) def constraint(diff_vel): return (ray_normals[0] * diff_vel < 0 or ray_normals[1] * diff_vel < 0 or b * diff_vel < 1 - r / d) else: constraint = None return constraint
def has_planet(self, x, y): if x <= 0 or x >= self._game.map.width or y <= 0 or y >= self._game.map.height: return True pos = Position(x, y) for planet in self._game.map.all_planets(): if pos.calculate_distance_between( planet) <= planet.radius + .50001: return True return False
def velocity_constraint_parabola(entity1, entity2, max_speed): origin = Position.from_entity(entity1) b = Position.from_entity(entity2) - origin r = entity1.radius + entity2.radius norm_b = Position.normed(b) orth_b = Position.orth(norm_b) apex = b - norm_b * r # velocity difference as if the apex was the origin, # simplify operations later diff_vel = entity1.vel - entity2.vel - apex constraint = diff_vel.dot(norm_b)**2 - 2 * r * diff_vel.dot(orth_b) < 0 return constraint
def ship_against_ship(ship, enemy_ship, game_map): p = Position(enemy_ship.x, enemy_ship.y) c = ship.navigate(p, game_map, speed=int(hlt.constants.MAX_SPEED), ignore_ships=False, ignore_planets=False) if not c: logging.warning("Couldn't attack enemy %s with ship %s" % (enemy_ship.id, ship.id)) return c
def attack_planet(ship, planet, game_map): p = Position(planet.x, planet.y) c = ship.navigate( p, game_map, speed=int(hlt.constants.MAX_SPEED), ignore_ships=False, ignore_planets=False) if not c: logging.warning("Couldn't attack planet %s with ship %s" % (planet.id, ship.id)) return c
def regroup(self): """ # Order all drone to move to center :return: """ center = self.gravitational_center() position = Position(center.x, center.y) position.pos.radius = self.nb_members() * SQUAD_SCATTERED_THRESHOLD / 2.0 # Assign the position as target self.assign_target(position, target_type=TargetType.POSITION)
def attack_planet(ship, planet, game_map): p = Position(planet.x, planet.y) c = None speed = int(hlt.constants.MAX_SPEED) while speed > 0: c = ship.navigate( p, game_map, speed=speed, ignore_ships=True, ignore_planets=True) if c: return c speed -= 1 logging.warning("Couldn't attack planet %s with ship %s" % (planet.id, ship.id)) return c
def cornershipmove(): ship = cornershipfinder() shippos = np.array([[ship.x, ship.y]]) corners = np.array([[0, 0], [game_map.width, game_map.height], [0, game_map.height], [game_map.width, 0]]) distances = scipy.spatial.distance.cdist(shippos, corners) index, distance = min(enumerate(distances[0]), key=lambda distance: distance[1]) desiredcornerX, desiredcornerY = corners[index] navigate_command = ship.navigate(ship.closest_point_to( Position(desiredcornerX, desiredcornerY)), game_map, speed=int(hlt.constants.MAX_SPEED), ignore_ships=False, angular_step=8) if navigate_command: command_queue.append(navigate_command)
def test_compute_1RVOCone_constraint(self): m = 4 n = 1 all_entities = self.entities[:m] all_entities[1].vel = Position(0, -20) preprocess = constraints_pre_cone(n, m, all_entities, self.max_speed) all_pos, diff_pos, sum_rad, u1, u2, u3, d3, speed_sq, collision_idx, \ prev_vel = preprocess cons = const_RVO_cone(diff_pos, sum_rad, u1, u2, u3, d3, speed_sq, collision_idx, prev_vel) x = self.entities[0].x y = self.entities[0].y cons((100 - x, 40 - y)) n_cons = len(cons([0, 0])) # for k in range(n_cons): # print("#"*10) # for j in range(20): # print(" ".join(["{:3}".format(cons([i * 10 - x, j * 10 - # y])[k]<=0) # for i in range(20)])) # for k in range(n_cons): # print("#"*10) # img = [[cons([i - x, j - y])[k] < 0 # for i in range(200)] # for j in range(200)] # img = np.array(img, dtype=np.uint8) # img = img * 255 # img = np.dstack((img, img, img)) # draw_entities(img, all_entities) img = [[ all([cons([i - x, j - y])[k] < 0 for k in range(n_cons)]) for i in range(200) ] for j in range(200)] img = np.array(img, dtype=np.uint8) img = img * 255 img = np.dstack((img, img, img)) draw_entities(img, all_entities)
def __init__(self, load_from_disk=None, debug=False, args=None): self._t0 = time.time() self._game = pw.load('game_init.p') if load_from_disk else hlt.Game( 'DaanV123' + ('_debug' if debug else '')) self._debug = debug self._turn_idx = 0 if self._debug: pw.dump(self._game, "game_init.p") pw.dump(args, "args.p") if load_from_disk: args = pw.load("args.p") print(args) self._num_players = len(self._game.map.all_players()) heads_up = self._num_players == 2 self._r_attack_docked = args.r_attack_docked self._r2_chase_enemy = args.r_chase_enemy**2 self._enemy_weight = args.enemy_weight_2p if heads_up else args.enemy_weight_4p self._unowned_planet_weight = args.unowned_planet_weight self._r_enemy_no_dock = args.r_enemy_no_dock self._owned_planet_weight = args.owned_planet_weight self._enemy_planet_weight = args.enemy_planet_weight self._expected_enemy_theta = args.expected_enemy_theta self._distances_to_planets = { planet.id: compute_distances(self._game.map, planet.x, planet.y, planet.radius + 3) for planet in self._game.map.all_planets() } center = Position(self._game.map.width / 2, self._game.map.height / 2) self._planet_distance_from_center = { planet.id: planet.calculate_distance_sq_between(center) for planet in self._game.map.all_planets() } self._should_i_dock = True self._should_i_undock = False self._hide = False self.compute_stuff()
def intersect_segment_circle(start, end, circle, *, fudge=0.5): """ Test whether a line segment and circle intersect. :param Entity start: The start of the line segment. (Needs x, y attributes) :param Entity end: The end of the line segment. (Needs x, y attributes) :param Entity circle: The circle to test against. (Needs x, y, r attributes) :param float fudge: A fudge factor; additional distance to leave between the segment and circle. (Probably set this to the ship radius, 0.5.) :return: True if intersects, False otherwise :rtype: bool """ # Derived with SymPy # Parameterize the segment as start + t * (end - start), # and substitute into the equation of a circle # Solve for t dx = end.x - start.x dy = end.y - start.y a = dx**2 + dy**2 b = -2 * (start.x**2 - start.x * end.x - start.x * circle.x + end.x * circle.x + start.y**2 - start.y * end.y - start.y * circle.y + end.y * circle.y) c = (start.x - circle.x)**2 + (start.y - circle.y)**2 if a == 0.0: # Start and end are the same point return start.calculate_distance_between( circle) <= circle.radius + fudge # Time along segment when closest to the circle (vertex of the quadratic) t = min(-b / (2 * a), 1.0) if t < 0: return False closest_x = start.x + dx * t closest_y = start.y + dy * t closest_distance = Position( closest_x, closest_y).calculate_distance_between(circle) return closest_distance <= circle.radius + fudge
def get_centroid(entities: List[Entity], width: float, height: float) -> Position: """ Calculate centroid of entities. :param entities: :param width: :param height: :return: Position """ cx, cy = 0.0, 0.0 if entities: for entity in entities: cx += entity.x cy += entity.y cx /= len(entities) cy /= len(entities) if width: cx /= width if height: cy /= height return Position(cx, cy)
def assign_targets(self): """ Assign a target for each ship using planet attractivity The attractivity is discounted by the distance """ my_ships = self.my_undocked_ships planets = self.all_planets() ship_pos = np.array([[e.x, e.y] for e in my_ships]) planet_pos = np.array([[e.x, e.y] for e in planets]) planet_att = np.array([e.attractivity_level for e in planets]) n_ship = ship_pos.shape[0] n_planet = planet_pos.shape[0] diff_pos = (np.broadcast_to(ship_pos.reshape(n_ship, 1, 2), (n_ship, n_planet, 2)) - np.broadcast_to(planet_pos.reshape(1, n_planet, 2), (n_ship, n_planet, 2))) dist = np.sum(diff_pos * diff_pos, axis=2) dist = np.power(dist, DIST_POWER) attractivity = dist * planet_att for i, ship in enumerate(my_ships): planet_ind = np.argmax(attractivity[i, :]) ship.target = Position.from_entity(planets[planet_ind])
rem_dock[e] -= 1 cmds.append(nav_cmd) if move: move_table[s] = move unassigned.discard(s) elif type(e) == hlt.entity.Ship: # WITHIN POTENTIAL ATTACK RANGE if s.dist_to(e) <= WEAPON_RADIUS + 2*MAX_SPEED: # ATTACK if s in has_atked: nav_cmd, move = helper.nav(s,s.closest_pt_to(e,6),gmap,None,move_table) else: nav_cmd, move = helper.nav(s,s.closest_pt_to(e),gmap,None,move_table) if move: atk_pos = Position(move.p2) else: atk_pos = Position(s.loc, s.loc + Point.polar(MAX_SPEED,s.angle_to(e))) atk_ens = [t for t in gmap.en_uships() if t.dist_to(atk_pos) <= WEAPON_RADIUS + MAX_SPEED] atk_frs = [t for t in gmap.my_uships() if t.dist_to(atk_pos) <= MAX_SPEED+2] if len(atk_frs) > len(atk_ens): if nav_cmd: en_ship_assigned[e] -= 1 cmds.append(nav_cmd) if move: move_table[s] = move unassigned.discard(s) continue # OTHER OPTIONS en_dships = sorted(gmap.en_dships(),key=lambda t:s.dist_to(t))
def navigate(ship, target, game_map, speed, avoid_obstacles=True, max_corrections=90, angular_step=1, ignore_ships=False, ignore_planets=False, clockwise=True, iteration=0): """ Move a ship to a specific target position (Entity). It is recommended to place the position itself here, else navigate will crash into the target. If avoid_obstacles is set to True (default) will avoid obstacles on the way, with up to max_corrections corrections. Note that each correction accounts for angular_step degrees difference, meaning that the algorithm will naively try max_correction degrees before giving up (and returning None). The navigation will only consist of up to one command; call this method again in the next turn to continue navigating to the position. :param Entity target: The entity to which you will navigate :param game_map.Map game_map: The map of the game, from which obstacles will be extracted :param int speed: The (max) speed to navigate. If the obstacle is nearer, will adjust accordingly. :param bool avoid_obstacles: Whether to avoid the obstacles in the way (simple pathfinding). :param int max_corrections: The maximum number of degrees to deviate per turn while trying to pathfind. If exceeded returns None. :param int angular_step: The degree difference to deviate if the original destination has obstacles :param bool ignore_ships: Whether to ignore ships in calkculations (this will make your movement faster, but more precarious) :param bool ignore_planets: Whether to ignore planets in calculations (useful if you want to crash onto planets) :return string: The command trying to be passed to the Halite engine or None if movement is not possible within max_corrections degrees. :rtype: str """ # Assumes a position, not planet (as it would go to the center of the planet otherwise) if max_corrections <= 0: return 0, 0 distance = ship.calculate_distance_between(target) angle = ship.calculate_angle_between(target) ignore = () if not (ignore_ships or ignore_planets) \ else Ship if (ignore_ships and not ignore_planets) \ else Planet if (ignore_planets and not ignore_ships) \ else Entity if avoid_obstacles and game_map.obstacles_between(ship, target, ignore): iteration += 1 if clockwise: new_angle = angle - iteration * angular_step clockwise = False else: new_angle = angle + iteration * angular_step clockwise = True new_target_dx = math.cos(math.radians(new_angle)) * distance new_target_dy = math.sin(math.radians(new_angle)) * distance new_target = Position(ship.x + new_target_dx, ship.y + new_target_dy) return navigate(ship, new_target, game_map, speed, True, max_corrections - 1, angular_step, clockwise=clockwise, iteration=iteration) speed = speed if (distance >= speed) else distance return speed, angle
def _get_commands(self, action, world_map: hlt.game_map.Map): commands = [] player_id = world_map.get_me().id planets = world_map.all_planets() all_ships = world_map._all_ships() ships = [ship for ship in all_ships if ship.owner.id == player_id] enemy_ships = [ ship for ship in world_map._all_ships() if ship.owner.id != player_id ] free_planets = [] enemy_planets = [] enemy_ships_on_tile = [] target_tile = floor(action) for planet in planets: planet_tile = self.grid.get_tile_id(planet.x, planet.y) if planet_tile == target_tile and not planet.is_owned(): free_planets.append(planet) elif planet_tile == target_tile and planet.owner.id != player_id: enemy_planets.append(planet) tile_center_x, tile_center_y = self.grid.get_tile_center_by_id( target_tile) for ship in enemy_ships: ship_tile = self.grid.get_tile_id(ship.x, ship.y) if ship_tile == target_tile: enemy_ships_on_tile.append(ship) if len(free_planets) > 0: for ship in ships: dest_planet = free_planets[np.argmin([ np.linalg.norm((planet.x - ship.x, planet.y - ship.y)) for planet in free_planets ])] if ship.can_dock(dest_planet): commands.append(ship.dock(dest_planet)) else: commands.append( navigate(world_map, self.start_round, ship, ship.closest_point_to(dest_planet), speed=int(hlt.constants.MAX_SPEED / 2))) # elif len(enemy_ships_on_tile) > 0: # for ship in ships: # dest_ship = enemy_ships_on_tile[np.argmin([ # np.linalg.norm((enemy.x - ship.x, enemy.y - ship.y)) # for enemy in enemy_ships_on_tile # ])] # commands.append(attack( # world_map, # ship, # Position(dest_ship.x, dest_ship.y), # speed=int(hlt.constants.MAX_SPEED / 2))) elif len(enemy_planets) > 0: for ship in ships: dest_planet = enemy_planets[np.argmin([ np.linalg.norm((planet.x - ship.x, planet.y - ship.y)) for planet in enemy_planets ])] if len(dest_planet.all_docked_ships()) == 0: if ship.can_dock(dest_planet): commands.append(ship.dock(dest_planet)) else: commands.append( navigate(world_map, self.start_round, ship, ship.closest_point_to(dest_planet), speed=int(hlt.constants.MAX_SPEED / 2))) else: weakest_ship = None for s in dest_planet.all_docked_ships(): if weakest_ship is None or weakest_ship.health > s.health: weakest_ship = s commands.append( navigate(world_map, self.start_round, ship, ship.closest_point_to(weakest_ship), int(hlt.constants.MAX_SPEED / 2))) else: for ship in ships: commands.append( navigate(world_map, self.start_round, ship, Position(tile_center_x, tile_center_y), speed=int(hlt.constants.MAX_SPEED / 2))) return commands
def compute_utility(self, x, y, ship, enemy_ships): planet_utilities, docked_ship_utilities, enemy_ship_utility = [0 ], [0 ], 0 pos = Position(x, y) if self._hide: hiding_positions = [ Position(3, 3), Position(self._game.map.width - 3, 3), Position(3, self._game.map.height - 3), Position(self._game.map.width - 3, self._game.map.height - 3) ] utility = 0 for hiding_position in hiding_positions: utility += 1 / pos.calculate_distance_sq_between( hiding_position) return utility for planet in self._game.map.all_planets(): r = self.distance_to_planet(planet.id, x, y) if r == np.infty: continue r += 1 planet_weight = 1 if self._num_players < 3 else self._planet_distance_from_center[ planet.id] if not planet.is_owned() and self._should_i_dock: free_docking_spots = planet.num_docking_spots - planet.num_docked_ships( ) planet_utilities.append(planet_weight * free_docking_spots * self._unowned_planet_weight / r**2) elif planet.owner == self._game.map.get_me( ) and not planet.is_full() and self._should_i_dock: planet_utilities.append(planet_weight * self._owned_planet_weight / r**2) elif planet.is_owned() and planet.owner != self._game.map.get_me(): planet_utilities.append(planet_weight * self._enemy_planet_weight / r**2) if r < self._r_attack_docked: angle_pos = planet.calculate_angle_between(pos) docked_ship_utility = 0 for docked_ship in planet.all_docked_ships(): angle_ship = planet.calculate_angle_between( docked_ship) angle_diff = (angle_ship - angle_pos) % 360 angle_diff = min(angle_diff, 360 - angle_diff) docked_ship_utility += 180 - angle_diff docked_ship_utilities.append(docked_ship_utility) for enemy_ship in enemy_ships: enemy_ship_previous = self._game.map.get_player_previous( enemy_ship.owner.id).get_ship(enemy_ship.id) enemy_ship_previous = enemy_ship_previous if enemy_ship_previous else enemy_ship x, y = enemy_ship.x, enemy_ship.y dx = enemy_ship.x - enemy_ship_previous.x dy = enemy_ship.y - enemy_ship_previous.y theta = self._expected_enemy_theta expected_next_pos = Position(x + theta * dx, y + theta * dy) r2 = pos.calculate_distance_sq_between(expected_next_pos) if r2 < self._r2_chase_enemy: enemy_ship_utility += self._enemy_weight / r2 return np.sum(planet_utilities) + max( docked_ship_utilities) + enemy_ship_utility
def avoid_collision(self, ship, entity, collision): logging.info('Avoid Collision') logging.info(ship) logging.info(entity) logging.info(collision) # We want to modifiy how much the ship moves based on # If the ship is close to the target, deviate less # If the ship is going slow, deviate less (will not move if speed is 0) if ship.distance_to_target == 0 and entity.distance_to_target == 0: # They both reached their targets init_ship_modifier = (ship.magnitude / hlt.constants.MAX_SPEED) init_entity_modifier = (entity.magnitude / hlt.constants.MAX_SPEED) else: init_ship_modifier = (ship.magnitude / hlt.constants.MAX_SPEED) * \ (ship.distance_to_target / (ship.distance_to_target + entity.distance_to_target)) init_entity_modifier = (entity.magnitude / hlt.constants.MAX_SPEED) * \ (entity.distance_to_target / (entity.distance_to_target + ship.distance_to_target)) if init_ship_modifier == 0 and init_entity_modifier == 0: return # They are already colliding... ship_modifier = init_ship_modifier / (init_ship_modifier + init_entity_modifier) entity_modifier = init_entity_modifier / (init_ship_modifier + init_entity_modifier) logging.info('ship_modifer: {} entity_modifer: {}'.format( ship_modifier, entity_modifier)) if ship.magnitude == 0 and entity.magnitude == 0: raise (Exception('Both ships are not moving...')) # Note: By always taking the shortest path to something the rotation + distance modifier # should (almost) always keep the ship in range of the target # TODO: Check if the ships paths cross (below only works for co-liniar # Find where the collision first happened t = collision[3] ship_position = Position(ship.x + ship.vel_x * t, ship.y + ship.vel_y * t) entity_position = Position(entity.x + entity.vel_x * t, entity.y + entity.vel_y * t) logging.info( 'collision happened at ship_position: {} entity_position: {}'. format(ship_position, entity_position)) # Work out the closest point they meet ship_velocity_step = Position(ship.vel_x / VELOCITY_STEPS, ship.vel_y / VELOCITY_STEPS) entity_velocity_step = Position(entity.vel_x / VELOCITY_STEPS, entity.vel_y / VELOCITY_STEPS) logging.info('velocity step ship: {} entity: {}'.format( ship_velocity_step, entity_velocity_step)) min_distance = math.inf velocity_step = None min_ship_position = None min_entity_position = None for step in range(VELOCITY_STEPS): current_ship_position = Position( ship_position.x + ship_velocity_step.x * step, ship_position.y + ship_velocity_step.y * step) current_entity_position = Position( entity_position.x + entity_velocity_step.x * step, entity_position.y + entity_velocity_step.y * step) distance = current_ship_position.calculate_distance_between( current_entity_position) if distance < min_distance: min_distance = distance velocity_step = step min_ship_position = current_ship_position min_entity_position = current_entity_position logging.info('min distance {}'.format(min_distance)) # Required distance required_distance = ship.radius + entity.radius distance_to_deflect = required_distance - min_distance logging.info('required_distance {}, distance_to_reflect'.format( required_distance, distance_to_deflect)) if ship.docking_status != ship.DockingStatus.UNDOCKED: logging.info('Ship is docked') elif ship.magnitude == 0: logging.info( 'Entity is not moving atm (it may have just started to dock)') else: new_ship_angle = self.get_deflected_angle( ship, entity, distance_to_deflect * ship_modifier) ship.thrust(ship.magnitude, new_ship_angle) #logging.info('new_ship_angle {}, ship.magnitude'.format(ship.magnitude, new_ship_angle)) if isinstance(entity, hlt.entity.Planet): logging.info('Entity is planet') elif entity.docking_status != entity.DockingStatus.UNDOCKED: logging.info('Entity is docked') elif entity.magnitude == 0: logging.info( 'Entity is not moving atm (it may have just started to dock)') else: new_entity_angle = self.get_deflected_angle( entity, ship, distance_to_deflect * entity_modifier) entity.thrust(entity.magnitude, new_entity_angle) logging.info('new_entity_angle {}, entity.magnitude'.format( new_entity_angle, entity.magnitude))
# Then we print our start message to the logs logging.info("Starting my Greedy bot!") game_state = 0 first_turn = True while True: # TURN START # Update the map for the new turn and get the latest version game_map = game.update_map() if first_turn == True: enemies = game_map.all_players() enemies.remove(game_map.get_me()) centre_place = Position(0, 0) centre_place.x = game_map.get_me().all_ships()[0].x centre_place.y = game_map.get_me().all_ships()[0].y centre_enemy = Position(0, 0) for enemy in enemies: centre_enemy.x += enemy.all_ships()[0].x centre_enemy.y += enemy.all_ships()[0].y centre_enemy.x /= len(enemies) centre_enemy.y /= len(enemies) first_turn = False #logging.info("Centre.x: " + str(centre_place.x)) #logging.info("Centre.y: " + str(centre_place.y)) # Here we define the set of commands to be sent to the Halite engine at the end of the turn
def compute_command_queue(self): my_ships = [ship for ship in self._game.map.get_me().all_ships()] my_docked_ships = [ ship for ship in my_ships if ship.docking_status in (Ship.DockingStatus.DOCKED, Ship.DockingStatus.DOCKING, Ship.DockingStatus.UNDOCKING) ] my_undocked_ships = [ ship for ship in my_ships if ship.docking_status == Ship.DockingStatus.UNDOCKED ] enemy_ships = [ ship for player in self._game.map.all_players() if not player == self._game.map.get_me() for ship in player.all_ships() ] moves = [] def no_collision(source: Entity, target: Entity): for s, t in moves: collision_possible = abs(source.x - s.x) < 15 and abs(source.y - s.y) < 15 if collision_possible and min_r2(source, target, s, t) < 1.001: return False return True for ship in my_docked_ships: moves.append((ship, ship)) potential_new_positions_and_utilities = [] free_docking_spots = {} for planet in self._game.map.all_planets(): if not planet.is_owned() or planet.owner == self._game.map.get_me( ): free_docking_spots[ planet. id] = planet.num_docking_spots - planet.num_docked_ships() else: free_docking_spots[planet.id] = 0 for ship in my_undocked_ships: time_left = self.time_left() if time_left < 0.3: break potential_new_positions_and_utilities += self.compute_potential_new_positions_and_utilities( ship, enemy_ships) command_queue = [] ships_moved = set() if self._should_i_undock: for ship in my_docked_ships: if ship.docking_status == Ship.DockingStatus.DOCKED: command_queue.append(ship.undock()) for utility, new_x, new_y, speed, angle, ship in sorted( potential_new_positions_and_utilities, key=first): time_left = self.time_left() if time_left < 0.2: return command_queue if ship not in ships_moved: for planet in self._game.map.all_planets(): if self._should_i_dock and free_docking_spots[ planet.id] > 0 and ship.can_dock( planet) and no_collision( ship, ship) and self.no_enemy_close( ship, enemy_ships): free_docking_spots[planet.id] -= 1 command_queue.append(ship.dock(planet)) ships_moved.add(ship) moves.append((ship, ship)) # print('Ship {}: I''m docking'.format(ship.id)) break else: new_position = Position(new_x, new_y) if no_collision( ship, new_position) and self.no_crash_into_planet( ship, new_position): command_queue.append(ship.thrust(speed, angle)) ships_moved.add(ship) moves.append((ship, new_position)) # print('Ship {}: I''m moving to {} {} ({})'.format(ship.id, new_x, new_y, utility)) return command_queue
move_table[s] = move unassigned.discard(s) elif type(e) == hlt.entity.Ship: # WITHIN POTENTIAL ATTACK RANGE if s.dist_to(e) <= WEAPON_RADIUS + 2 * MAX_SPEED: if not doomed: # ATTACK if s in has_atked: nav_cmd, move = helper.nav(s, s.closest_pt_to(e, 6), gmap, None, move_table) else: nav_cmd, move = helper.nav(s, s.closest_pt_to(e), gmap, None, move_table) if move: atk_pos = Position(move.p2) else: atk_pos = Position( s.loc, s.loc + Point.polar(MAX_SPEED, s.angle_to(e))) atk_ens = [ t for t in gmap.en_uships() if t.dist_to(atk_pos) <= WEAPON_RADIUS + MAX_SPEED ] atk_frs = [ t for t in gmap.my_uships() if t.dist_to(atk_pos) <= MAX_SPEED + 2 ] if len(atk_frs) > len(atk_ens): if nav_cmd: en_ship_assigned[e] -= 1