def reduce_move(self, cost_array, ship, destination): """Reduce the cost of moving to a neighbouring cell.""" # Indices. target_index = to_index(game_map[destination]) origin_index = to_index(ship) for neighbour_index in neighbours(origin_index): # Update cost matrix. first_cost = self.map_data.get_distance(ship, neighbour_index) remaining_cost = self.calculator.get_distance_from_index( ship, neighbour_index, target_index) cost_array[neighbour_index] = first_cost + remaining_cost
def assign_kamikaze(self, ship): """Attack with a ship that is no longer valuable, guard dropoffs.""" dropoff = self.map_data.get_closest_dropoff(ship) dropoff_index = to_index(dropoff) ship_index = to_index(ship) possible_targets = list(enemy_ships()) if possible_targets: target = min(possible_targets, key=lambda enemy_ship: self._kamikaze_cost( dropoff_index, ship_index, enemy_ship)) self.schedule.assign(ship, target.position) else: self.schedule.assign(ship, ship.position)
def reduce_stay_still(self, cost_array, ship, destination): """Reduce the cost of staying still.""" # Indices. target_index = to_index(game_map[destination]) origin_index = to_index(ship) # Partial costs for the first turn (stay still). threat_cost = self.map_data.calculator.threat_to_self(ship) wasted_cost = self.wasted_turn_cost(ship, target_index) # Update cost matrix. first_cost = 1.0 + threat_cost + wasted_cost remaining_cost = self.map_data.get_distance(ship, target_index) cost_array[origin_index] = first_cost + remaining_cost
def move(self): """Move this ghost dropoff to a more optimal nearby location.""" index = to_index(self) positions = (index, ) + neighbours(index) search_area = self.search_area() positions = [p for p in positions if p in search_area] self.position = self.best_position(positions)
def dropoff_ship(self): """Determine ship that creates the ghost dropoff.""" for ship in self.ships: if ship.position == self.ghost.position: if (self.me.halite_amount < self.dropoff_cost(ship) or to_cell(to_index(ship)).has_structure): return None return ship return None
def wasted_turn_cost(self, ship, target_index): """Costs (0.0 - 0.1) for a wasted turn. Also breaks some symmetry.""" if to_index(ship) == target_index: return 0.0 elif game_map[ship].has_structure: return 9999.0 else: cargo_space = constants.MAX_HALITE - ship.halite_amount mining_potential = math.ceil(0.25 * game_map[ship].halite_amount) mining_profit = min(cargo_space, mining_potential) return min(0.0, 0.1 - 0.001 * mining_profit)
def move_turns(self, ship, halite): """Turns spent on moving.""" distances = self.map_data.get_distances(ship) index = to_index(ship) distances[index] += self.map_data.calculator.threat_to_self(ship) return_distances = self.return_distances(ship) space = max(1, constants.MAX_HALITE - ship.halite_amount) move_turns = distances + param['return_distance_factor'] * ( halite / space) * return_distances move_turns[move_turns < 0.0] = 0.0 return move_turns
def destination(cls, assignment): """Destination or current location of a ship.""" cell = game_map[assignment.destination] if cell.has_structure and cell.structure.owner == me.id: cell = game_map[assignment.ship] return to_index(cell)
def near_dropoff(self, ship): """Return True if the ship can reach a dropoff/shipyard this turn.""" dropoff = self.map_data.get_closest_dropoff(ship) return to_index(ship) in neighbours(to_index(dropoff))
def distance(self, ships): """Simple distance of the current position to the nearest ship.""" index = to_index(self) return min([simple_distance(index, to_index(ship)) for ship in ships])
def _kamikaze_cost(self, dropoff_index, ship_index, enemy_ship): """Cost value used to determine which enemy ship should be attacked.""" i = to_index(enemy_ship) return simple_distance(dropoff_index, i) + simple_distance( ship_index, i)
def return_distances(self, ship): """Extra turns necessary to return to a dropoff.""" dropoff_distances = self.map_data.calculator.simple_dropoff_distances dropoff_distance = dropoff_distances[to_index(ship)] return dropoff_distances - dropoff_distance