def moveShipSmart(self, ship, target, unsafe=False): # Used for seen and keeps track of which cell the best path came from # Except for initial cells which contain direction prevCell = dict() # Cells still to be searched toSearch = list() def cost(halite, distance): adjustedInv = (ship.halite_amount - halite) / fastPow( GROWTH, distance) return ship.halite_amount - adjustedInv def heuristic(pos, halite, distance): furtherDistance = self.game_map.calculate_distance(target, pos) newDistance = distance + furtherDistance expHalite = int((MINE_T + MINE_T * (1.0 - 1.0 / constants.EXTRACT_RATIO)) / 2.0) newHalite = halite + furtherDistance * expHalite // constants.MOVE_COST_RATIO return cost(newHalite, newDistance) # Add initial cells to search space for dir in Direction.get_all_cardinals(): newPos = self.game_map.normalize( ship.position.directional_offset(dir)) halite = self.game_map[ ship.position].halite_amount // constants.MOVE_COST_RATIO distance = 1 Cost = cost(halite, distance) heapq.heappush(toSearch, (heuristic( newPos, halite, distance), halite, distance, newPos)) prevCell[newPos] = (Cost, ship.position, dir) curr = target # Search for target while toSearch: adjCost, halite, distance, pos = heapq.heappop(toSearch) if pos == target: curr = pos break for dir in Direction.get_all_cardinals(): newPos = self.game_map.normalize(pos.directional_offset(dir)) newHalite = halite + self.game_map[ pos].halite_amount // constants.MOVE_COST_RATIO newDistance = distance + 1 Cost = cost(newHalite, newDistance) if newPos not in prevCell: heapq.heappush(toSearch, (heuristic(newPos, newHalite, newDistance), newHalite, newDistance, newPos)) prevCell[newPos] = (Cost, pos, dir) else: prevCell[newPos] = min(prevCell[newPos], (Cost, pos, dir)) logging.info(prevCell) # Find original cell while prevCell[curr][1] != ship.position: logging.info(curr) curr = prevCell[curr][1] return self.moveShip(ship, prevCell[curr][2])
def moveShipSmart(self, ship, target, unsafe=False): seen = set() toSearch = list() # Priority Queue def cost(pos): return squareCost(self.getHalitePos(pos)) def heuristic(pos): return self.game_map.calculate_distance(target, pos) * 10 # Initialize queue for dir in Direction.get_all_cardinals(): newPos = self.game_map.normalize( ship.position.directional_offset(dir)) heapq.heappush(toSearch, (cost(ship.position) + heuristic(newPos) - heuristic(ship.position), newPos, dir)) # Go through the search queue while toSearch: c, pos, dir = heapq.heappop(toSearch) if pos in seen: continue seen.add(pos) if pos == target: if self.moveShip(ship, dir): return True return False else: for d in Direction.get_all_cardinals(): newPos = self.game_map.normalize(pos.directional_offset(d)) if newPos not in seen: heapq.heappush(toSearch, ((c + cost(pos) + heuristic(newPos) - heuristic(pos), newPos, dir)))
def findTarget(self, startHalite, start, maxDis=10): toSearch = deque() seen = set() def evalPoint(halite, distance, pos): r_dis = self.game_map.calculate_distance(pos, start) adjHalite = halite - r_dis * MINE_T // constants.MOVE_COST_RATIO return adjHalite / pow(GROWTH_RATE, distance + r_dis) # Format = (halite, distance, pos) dHal, dDis = squareCost(self.command.game_map[start].halite_amount) toSearch.append((startHalite + dHal, dDis, start)) seen.add(start) best = (evalPoint(halite + dHal, dDis, start), start) while toSearch: halite, dis, pos = heapq.heappop(toSearch) if self.command.game_map.calculateDistance( pos, start) < maxDis and newHalite < RETURN_T: for dir in Direction.get_all_cardinals(): newPos = self.command.game_map.normalize( pos.get_directional_offset(dir)) squareHalite = self.command.game_map[newPos].halite_amount dHalite, dDis = squareCost(squareHalite) newDis = dis + dDis newHalite = min(halite + dHalite, constants.MAX_HALITE) best = max(best, (evalPoint(newHalite, newDis, pos), pos)) if newPos not in seen: toSearch.append((newHalite, newDis, newPos)) seen.add(newPos) if best[1] != start: return best[1] return start
def findNearTargets(self, ship, maxDis=5): toSearch = deque() seen = set() toSearch.append((0, ship.position)) seen.add(tup(ship.position)) bestSquare = (self.command.game_map[ship.position].halite_amount, tup(ship.position)) while toSearch: depth, pos = toSearch.popleft() tPos = tup(pos) #TODO: modify structure of targets so that it is dict for easier search by position or ship id bestSquare = max( (self.command.game_map[pos].halite_amount, tup(pos)), bestSquare) if depth < maxDis: for dir in Direction.get_all_cardinals(): newPos = self.command.game_map.normalize( pos.directional_offset(dir)) newTPos = tup(newPos) if newTPos not in seen: seen.add(newTPos) toSearch.append((depth + 1, newPos)) if bestSquare[1] != tup(ship.position): return bestSquare[1] return None
def getClosestSpot(ship): possible = [] cleanPlaces(targetArea) for i in targetArea: if i != ship.position: pickDir = game_map.get_unsafe_moves(ship.position, i)[0] if ((pickDir).__ne__(Direction.Still)) and (ship.position.__ne__( i)) and game_map[i].halite_amount > 100: possible.append(i) if len(possible) > 0: closest = possible[0] for i in possible: if game_map.calculate_distance(ship.position, i) < game_map.calculate_distance( ship.position, closest): if game_map.get_unsafe_moves(ship.position, i)[0] != Direction.Still: closest = i return Direction.convert( game_map.get_unsafe_moves(ship.position, closest)[0]) else: for i in Direction.get_all_cardinals(): if (game_map[ship.position.directional_offset(i)].is_occupied == False): return Direction.convert( game_map.get_unsafe_moves( ship.position, ship.position.directional_offset(i))[0])
def findNearTarget(self, ship, maxDis=10): toSearch = deque() seen = set() toSearch.append((0, ship.position)) seen.add(ship.position) def metric(pos): halite = self.command.getHalitePos(pos) # - MINE_T #distance = (self.command.game_map.calculate_distance(pos, self.command.shipyard.position) + self.command.game_map.calculate_distance(pos, ship.position) + 1) distance = ( self.command.game_map.calculate_distance(pos, ship.position) + 1) return halite / distance bestSquare = (metric(ship.position), ship.position) while toSearch: depth, pos = toSearch.popleft() if not self.posAssigned(pos): bestSquare = max((metric(pos), pos), bestSquare) if depth < maxDis: for dir in Direction.get_all_cardinals(): newPos = self.command.game_map.normalize( pos.directional_offset(dir)) if newPos not in seen: seen.add(newPos) toSearch.append((depth + 1, newPos)) if bestSquare[1] != ship.position: return bestSquare[1] return None
def moveShipSmart(self, ship, target, unsafe = False, maxDepth = 10): # Used for seen and keeps track of which cell the best path came from # Except for initial cells which contain direction prevCell = dict() # Cells still to be searched toSearch = list() # We account for cost of current square upon landing in it. # So distance is one less than actual distance def cost(halite, distance): adjustedInv = (ship.halite_amount - halite)/fastPow(GROWTH, distance - 1) return ship.halite_amount - adjustedInv # Estimate total cost as cost up to this point plus cost assuming # some minimum amount of halite in remaining squares def heuristic(pos, halite, distance): furtherDistance = self.game_map.calculate_distance(target, pos) newDistance = distance + furtherDistance expHalite = MINE_T newHalite = halite + furtherDistance * expHalite // constants.MOVE_COST_RATIO return cost(newHalite, newDistance) # Add initial cells to search space for dir in Direction.get_all_cardinals(): newPos = self.game_map.normalize(ship.position.directional_offset(dir)) halite = (self.game_map[ship.position].halite_amount + self.game_map[newPos].halite_amount) // constants.MOVE_COST_RATIO distance = 1 Cost = cost(halite, distance) heapq.heappush(toSearch, (heuristic(newPos, halite, distance), halite, distance, newPos)) prevCell[newPos] = (Cost, ship.position, dir) curr = target # Search for target while toSearch: adjCost, halite, distance, pos = heapq.heappop(toSearch) if pos == target: curr = pos break for dir in self.game_map.get_unsafe_moves(pos, target): newPos = self.game_map.normalize(pos.directional_offset(dir)) newHalite = halite + self.game_map[newPos].halite_amount // constants.MOVE_COST_RATIO newDistance = distance + 1 Cost = cost(newHalite, newDistance) if newPos not in prevCell: heapq.heappush(toSearch, (heuristic(newPos, newHalite, newDistance), newHalite, newDistance, newPos)) prevCell[newPos] = (Cost, pos, dir) else: prevCell[newPos] = min(prevCell[newPos], (Cost, pos, dir)) logging.info(prevCell) # Find original cell while prevCell[curr][1] != ship.position: logging.info(curr) curr = prevCell[curr][1] return self.moveShip(ship, prevCell[curr][2])
def get_surrounding_cardinals(pos): """ :return: Returns a list of all positions around this specific position in each cardinal direction """ return [ pos.directional_offset(current_direction) for current_direction in Direction.get_all_cardinals() ]
def dir_to_dest(self, pos, dest): """ Precondition: position one move away """ normalized_dest = self.game_map.normalize(dest) for d in Direction.get_all_cardinals(): new_pos = self.game_map.normalize(pos.directional_offset(d)) if new_pos == normalized_dest: return d return Direction.Still # should never happen
def get_valid_position(self, vertex): directions = Direction.get_all_cardinals() shuffle(directions) possible_positions = [ vertex.directional_offset(direction) for direction in directions ] for index, position in enumerate(possible_positions): if self.tup(position) not in utils.tiles_visited: return directions[index]
def get_random_direction(self, ship=None): direction_list = Direction.get_all_cardinals() direction = random.choice(direction_list) if ship is not None: if ship.position.directional_offset(direction) == self.game.me.shipyard.position: direction_list.remove(direction) direction = random.choice(direction_list) return direction
def get_safe_random_direction(ship: Ship, game_map: GameMap): safe_choices = [] for direction in Direction.get_all_cardinals(): if not game_map[ship.position.directional_offset( direction)].is_occupied: safe_choices.append(direction) if safe_choices: chosen_direction = random.choice(safe_choices) game_map[ship.position.directional_offset( chosen_direction)].mark_unsafe(ship) return chosen_direction return None
def side_or_side(ship, destination, game_map): possible_moves = Direction.get_all_cardinals() direct_move = game_map.get_unsafe_moves(ship.position, destination) possible_moves.remove(direct_move[0]) possible_moves.remove(Direction.invert(direct_move[0])) next_step = random.choice(possible_moves) if game_map[ship.position.directional_offset( next_step)].is_occupied is True: possible_moves.remove(next_step) return possible_moves[0] else: return next_step
def getShipMove(ship,sy): bestSpot = [] best = 0 amount = 820 if game_map[game_map.normalize(ship.position)].halite_amount < constants.MAX_HALITE / 35 and (ship.halite_amount < amount ): for i in Direction.get_all_cardinals(): if(game_map[ship.position.directional_offset(i)].is_occupied == False): bestSpot.append(game_map[ship.position.directional_offset(i)]) for i in bestSpot: if(i.halite_amount > best): #bestDir = game_map.naive_navigate(ship, i.position) best = i.halite_amount bestDir = game_map.get_unsafe_moves(ship.position, i.position)[0] if best < 50: bestDir = Direction.convertStr(random.choice(["n", "s","e","w"])) place = game_map[ship.position.directional_offset((bestDir))].position inPicked = False for i in placepicked: if (i.__eq__(place)): inPicked = True if inPicked == False and game_map[ship.position.directional_offset(bestDir)].is_occupied == False: placepicked.append(ship.position.directional_offset(bestDir)) command_queue.append((ship.move(bestDir))) else: placepicked.append(ship.position) command_queue.append(ship.stay_still()) #returnCommand = (ship.move(bestDir)) else: if ship.is_full or ship.halite_amount > amount: #command_queue.append(game_map.get_unsafe_moves(ship.position, Shipyard)[0]) placeVal = game_map[ship.position.directional_offset(game_map.get_unsafe_moves(ship.position, Shipyard)[0])].position inPicked = False for e in placepicked: if (placeVal.__eq__(e)): inPicked = True if inPicked == True: command_queue.append(ship.stay_still()) placepicked.append(ship.position) else: command_queue.append(ship.move(game_map.naive_navigate(ship, Shipyard))) placepicked.append(placeVal) else: command_queue.append(ship.stay_still()) placepicked.append(ship.position)
def decision(ship): # returns a list of priority moves with corresponding destination rep = [] ship_position = ship.position ship_halite = ship.halite_amount to_assign = set( chain([Direction.Still], Direction.get_all_cardinals())) for one_move in to_assign.copy(): if normalize_position( ship_position.directional_offset( one_move)) in basic_occupied_cells: to_assign.remove(one_move) map_to_cell = { d: ship_position.directional_offset(d) for d in to_assign } def assign(move): if move in to_assign: rep.append((move, normalize_position(map_to_cell[move]))) to_assign.remove(move) def assign_still(): assign(Direction.Still) def go_home(): home_position = find_closest_home(ship_position) moves = game_map.get_unsafe_moves( ship_position, home_position)[::-1] # invert x/y priority on return for move in moves: assign(move) if len(moves) == 1: assign_still() my_move = moves[0] to_assign.discard( Direction.invert(my_move) ) # don't walk back, but you can go on the sides if ship_halite >= 0: go_home() assign_still() # learn to wait in line # return rep else: for move in to_assign: assign(move) return rep
def __init__(self): game = hlt.Game() game.ready("vise") self.game = game self.ship_spawn_value = (constants.MAX_TURNS / 2) self.halite_return_value = (9 * constants.MAX_HALITE / 10) self.mining_prioritization_value = 3 self.direction_order = Direction.get_all_cardinals() self.direction_order.append(Direction.Still) self.ship_states = defaultdict(lambda: ShipStates.Collecting) logging.info("Successfully created bot! My Player ID is {}.".format(game.my_id))
def findNearTarget(self, ship, maxDis=10): toSearch = deque() seen = set() toSearch.append((0, ship.position)) seen.add(ship.position) bestSquare = (self.command.getHalitePos(ship.position), ship.position) while toSearch: depth, pos = toSearch.popleft() if not self.posAssigned(pos): bestSquare = max((self.command.getHalitePos(pos) / (depth + 1), pos), bestSquare) if depth < maxDis: for dir in Direction.get_all_cardinals(): newPos = self.command.game_map.normalize(pos.directional_offset(dir)) if newPos not in seen: seen.add(newPos) toSearch.append((depth+1, newPos)) if bestSquare[1] != ship.position: return bestSquare[1] return None
def _executeOrder(self, ship, order): if not order: return # Only happens when no order to give command, pos, backup = order if command == 'mine': # Mine a specific target/region # At target if self.inRegion(ship.position, pos): # Mineable if self.goodTarget(pos) and ship.halite_amount < RETURN_T: if not self.command.holdShip(ship): # Backup plan self._executeOrder(ship, backup) return else: # Ship issued a return order self.unasignShip(ship.id) self.fleetOrders[ship.id] = ( 'move', self.command.shipyard.position, ('hold', None, ('rand', None, None))) self._executeOrder(ship, self.fleetOrders[ship.id]) else: # Mine if space above threshold if self.goodTarget( ship.position) and ship.halite_amount < RETURN_T: if not self.command.holdShip(ship): self._executeOrder(ship, backup) return elif ship.halite_amount >= RETURN_T: # Ship issued a return order self.unasignShip(ship.id) self.fleetOrders[ship.id] = ( 'move', self.command.shipyard.position, ('hold', None, ('rand', None, None))) self._executeOrder(ship, self.fleetOrders[ship.id]) elif not self.command.moveShipSmart(ship, pos): self._executeOrder(ship, backup) return elif command == 'move': # Move to a specific place if ship.position == pos: self.issueNewCommand(ship) else: if not self.command.moveShipSmart(ship, pos): self._executeOrder(ship, backup) return elif command == 'hold': # Stay Still if not self.command.holdShip(ship): self._executeOrder(ship, backup) return elif command == 'rand': # Move in a random direction moved = False dirs = Direction.get_all_cardinals() random.shuffle(dirs) for dir in dirs: if self.command.moveShip(ship, dir): moved = True break if not moved: self._executeOrder(ship, backup) return elif command == 'done': # Move ship towards home, disregarding crashes if not self.command.moveShipTowards( ship, self.command.shipyard.position, unsafe=True): self.command.holdShip(ship) elif command == 'drop': # Unimplemented a = 1 else: logging.info(f"Illegal Command {command} Given to ship {ship.id}")
def smart_navigate(self, ship, destination): ''' Uses A* pathing algorithm to find the "best" path from the ship to the destination. If progress cannot be made towards the target, the ship will stand still unless it must move to prevent crashing into another ship. Takes a 'ship' and a 'position' ''' start = utils.tup(ship.position) goal = utils.tup(destination) # Set of notes already evaluated closedSet = set() # Set of discovered notes (not evaluated) openSet = set() openSet.add(start) # For each node, node it can most efficiently be reached from cameFrom = dict() # Cost from start node to that node gScore = dict() gScore[start] = 0 # Cost from start node to goal by passing through node - partly heuristic fScore = dict() fScore[start] = self.heuristic_cost_estimate(start, goal) # While we have nodes we have not evaluated while len(openSet) != 0: # Get lowest fScore minValue = math.inf current = None for node in openSet: if fScore[node] < minValue: minValue = fScore[node] current = node if current == goal: logging.info("arrived at goal") return self.reconstruct_path(cameFrom, current) openSet.remove(current) closedSet.add(current) directions = Direction.get_all_cardinals() possible_positions = [ self.detup(current).directional_offset(direction) for direction in directions ] # Go through neighbors of current for neighbor in possible_positions: # Ignore neighbors we already evaluated if self.tup(neighbor) in closedSet: continue # Distance from start to neighbor tentative_gScore = gScore[current] + self.dist_between( current, self.tup(neighbor)) # Discovered a new node if self.tup(neighbor) not in openSet: openSet.add(self.tup(neighbor)) elif tentative_gScore >= gScore[self.tup(neighbor)]: continue # We already had a better path cameFrom[self.tup(neighbor)] = current gScore[self.tup(neighbor)] = tentative_gScore fScore[self.tup( neighbor )] = tentative_gScore + self.heuristic_cost_estimate( self.tup(neighbor), goal)
if target == pos: targetted = True if not targetted: if cost < resources and len(path) != 0 and utils.tup( ship.position.directional_offset( path[0])) not in utils.tiles_visited: score = (resources - cost)**2.5 / steps_ahead if score > max_score: max_score = score directionToMove = path[0] target = pos foundDirection = True # Get all tiles you can access from it directions = Direction.get_all_cardinals() random.shuffle(directions) possible_positions = [ vertex.directional_offset(direction) for direction in directions ] # For each tile, check if we have already visited it. If not, add to the queue for index, position in enumerate(possible_positions): if position not in visited: visited.append(position) L = [ position, path + [directions[index]], cost + (.1 * resources) ] queue.append(L)
def main(): """" <<<Game Begin>>> """ game = hlt.Game() game.ready("MyPythonBot") logging.info("Successfully created bot! My Player ID is {}.".format( game.my_id)) """ <<<Game Loop>>> """ ship_targets = {} # Ship : Position ship_states = {} # Ship : ShipState while True: game.update_frame() me = game.me game_map = game.game_map ships = me.get_ships() # Removing Dead ships dead_ships = [] for ship_id in ship_states: if not me.has_ship(ship_id): dead_ships.append(ship_id) for ds in dead_ships: del ship_states[ds] position_value_list = game_map.get_cell_values( me.shipyard.position, MIN_HALITE) # (position, value) # Targets already assigned for p in position_value_list: if p[0] in ship_targets.values(): position_value_list.remove(p) next_targets = position_value_list next_targets.sort(key=itemgetter(1)) # Prioritizing targets # Setting Ship States for ship in ships: if ship.id not in ship_states: ship_targets[ship.id] = next_targets.pop()[0] ship_states[ship.id] = ShipStates.Outbound elif ship.position == me.shipyard.position: ship_targets[ship.id] = next_targets.pop()[0] ship_states[ship.id] = ShipStates.Outbound if ship_states[ship.id] == ShipStates.Outbound and ship_targets[ ship.id] == ship.position: ship_states[ship.id] = ShipStates.Collect if ship_states[ship.id] == ShipStates.Collect and ship.is_full: ship_targets[ship.id] = me.shipyard.position ship_states[ship.id] = ShipStates.Inbound if ship_states[ship.id] == ShipStates.Inbound and ship_targets[ ship.id] == ship.position: ship_targets[ship.id] = next_targets.pop()[0] ship_states[ship.id] = ShipStates.Outbound if constants.MAX_TURNS - game.turn_number == game_map.height / 2: # TODO improve ship_targets[ship.id] = me.shipyard.position ship_states[ship.id] = ShipStates.Inbound logging.info("SHIPS: {}".format(len(ships))) logging.info("SHIPS States: {}".format(ship_states)) logging.info("SHIPS Targets: {}".format(ship_targets)) # Commands ship_moves = {} # Ship : Position command_queue = [] # Command list # Stuck Ships for ship in ships: if ship.halite_amount < game_map[ ship.position].halite_amount / constants.MOVE_COST_RATIO: ship_moves[ship.id] = ship.position command_queue.append(ship.move(Direction.Still)) log_move(ship, ship_states[ship.id], ship_targets[ship.id], Direction.Still, "STUCK") # Moving Ships for ship in ships: if ship.id not in ship_moves: safe_directions = {} # {direction : halite} priority_list = [] # (direction, halite) log_reason = "NONE" # Get safe moves: for d in Direction.get_all(): if game_map.normalize(ship.position.directional_offset( d)) not in ship_moves.values(): safe_directions[d] = game_map[game_map.normalize( ship.position.directional_offset(d))].halite_amount # Transit order if ship_states[ship.id] == ShipStates.Inbound or ship_states[ ship.id] == ShipStates.Outbound: for d in game_map.get_unsafe_moves(ship.position, ship_targets[ship.id]): if d in safe_directions: priority_list.append((d, safe_directions[d])) log_reason = "NAV" priority_list.sort(key=itemgetter(1)) # Lowest first for d in safe_directions: if d not in priority_list: priority_list.append((d, safe_directions[d])) # Collect order elif ship_states[ship.id] == ShipStates.Collect: if Direction.Still in safe_directions and game_map[ ship.position].halite_amount > MIN_HALITE: priority_list.append( (Direction.Still, safe_directions[Direction.Still])) log_reason = "COLLECT" else: for d in Direction.get_all_cardinals(): if d in safe_directions: priority_list.append((d, safe_directions[d])) log_reason = "COL MOV" priority_list.sort(key=itemgetter(1), reverse=True) # Highest first # NO MOVES if len(priority_list) == 0: priority_list.append((Direction.Still, 0)) log_reason = "NO MOVE" # Make move final_direction = (priority_list[0])[0] ship_moves[ship.id] = game_map.normalize( ship.position.directional_offset(final_direction)) command_queue.append(ship.move(final_direction)) log_move(ship, ship_states[ship.id], ship_targets[ship.id], final_direction, log_reason) # Spawning if me.halite_amount >= constants.SHIP_COST and game.turn_number < 200: shipyard_is_empty = True for p in ship_moves.values(): if p == me.shipyard.position: shipyard_is_empty = False break if shipyard_is_empty: command_queue.append(me.shipyard.spawn()) logging.info("___SPAWNED SHIP___") logging.info("ALL MOVES: {}".format(ship_moves)) game.end_turn(command_queue)
else: add_move_affinity(moves, ship.stay_still(), 20)''' if game.turn_number <= 15: if ship_num == 1: add_move_affinity(moves, Direction.North, 40) if ship_num == 2: add_move_affinity(moves, Direction.South, 40) if ship_num == 3: add_move_affinity(moves, Direction.East, 40) if ship_num == 4: add_move_affinity(moves, Direction.West, 40) # For each of your ships, move randomly if the ship is on a low halite location or the ship is full. # Else, collect halite. for direct in Direction.get_all_cardinals( ): # reduces chances of running into each other :) pos = ship.position.directional_offset(direct) if game_map[pos].is_occupied: add_move_affinity(moves, direct, -10000) if me.halite_amount > 4000 and 1 < len(me.get_ships()) < 5 and len( me.get_dropoffs()) / len(me.get_ships()) <= .5: add_move_affinity(moves, ship.make_dropoff(), 40) if ship.halite_amount >= 500: close_drop = me.shipyard # for drop in me.get_dropoffs(): # sets close_drop to the closest dropoff location # if game_map.calculate_distance(ship.position, drop.position) < game_map.calculate_distance(ship.position, close_drop.position): # close_drop = drop # if close_drop.position is ship.position: # add_move_affinity(moves, ship.stay_still(), 30)
def run(): global spent_so_far destinations = {} ships_des = {} while True: game.update_frame() # You extract player metadata and the updated map metadata here for convenience. me = game.me game_map = game.game_map turns_left = constants.MAX_TURNS - game.turn_number halite_left = get_halite_amount() halite_percent = halite_left / starting_halite_amount # astar_cache.clear() highs = [] # spots = PriorityQueue() for x, y in itertools.product(range(game_map.width), range(game_map.height)): highs.append(Position(x, y)) enemy_locations = { ship.position for i in game.players for ship in game.players[i].get_ships() if game.players[i].id != game.my_id } highs = sorted(highs, key=lambda p: game_map[p].halite_amount, reverse=True)[:LOOK_AMOUNT] do_spots = highs[:SO_LOOK_AMOUNT] positions_used = set() command_queue = [] ship_queue = me.get_ships() for do in me.get_dropoffs(): pos = do.position if pos not in dropoffs: dropoffs.append(pos) # top10 = [highs.get().position for _ in range(10)] # logging.info(top10) # sort ships by proximity to shipyard ship_queue = sorted( ship_queue, key=lambda s: game_map.calculate_distance(s.position, syp), reverse=True) # ship_queue = sorted(ship_queue, key=lambda s: s.id, # reverse=True) dropoff = False for ship in ship_queue: # is ship in inspired state? num_of_enemies = 0 for x, y in itertools.product(range(-4, 5), range(-4, 5)): pos = ship.position.directional_offset((x, y)) if pos in enemy_locations: num_of_enemies += 1 if num_of_enemies >= 2: ship.inspired = True break else: ship.inspired = False ship.collect_amount = game_map[ship.position].halite_amount * .25 if ship.inspired: ship.collect_amount += ship.collect_amount * 2 # inspiration bonus if ship.id not in first_seen: first_seen[ship.id] = game.turn_number ship.staying = False ship.returning = False if ship.position in destinations: s = destinations[ship.position] del ships_des[s] del destinations[ship.position] if (constants.MAX_TURNS - game.turn_number) < 6 and ship.position in dropoffs: # ignore ship completely so that it can die ship.staying = True # should we build a drop-off? elif (len(ship_queue) >= SHIP_DO_RATIO * len(dropoffs) and ship.position in do_spots and game_map.calculate_distance( ship.position, closest_dropoff(ship.position)) > DO_DISTANCE and me.halite_amount > constants.DROPOFF_COST - game_map[ship.position].halite_amount + ship.halite_amount and game.turn_number < constants.MAX_TURNS * DO_TURN_FACTOR and halite_percent > DO_HALITE_FACTOR and # len(dropoffs) < 4 and not dropoff): dropoff = True spent_so_far += constants.DROPOFF_COST - game_map[ ship.position].halite_amount command_queue.append(ship.make_dropoff()) ship.staying = True positions_used.add(ship.position) d = ships_des.pop(ship.id, None) destinations.pop(d, None) # can it move? elif (game_map[ship.position].halite_amount * (1 / constants.MOVE_COST_RATIO)) > ship.halite_amount: # can't move, stay put # logging.info(f'ship {ship.id} staying with {ship.halite_amount} avaliable') move(ship.position, ship.position, ship, positions_used, command_queue) ship.staying = True elif ((ship.halite_amount > RETURN_AMOUNT) or (game_map.calculate_distance( ship.position, closest_dropoff(ship.position)) + 6 >= (constants.MAX_TURNS - game.turn_number))): returning.add(ship.id) ship.returning = True elif (ship.halite_amount + ship.collect_amount > 1000): # its not worth staying on the square, just go home ship.returning = True returning.add(ship.id) # mark enemy ships if we don't control more than half the ships on the board if len(ship_queue) < len(enemy_locations): for pos in enemy_locations: for d in Direction.get_all_cardinals(): location = game_map.normalize(pos.directional_offset(d)) if game_map.calculate_distance(location, closest_dropoff(pos)) > 1: positions_used.add(location) logging.info(enemy_locations) for ship in ship_queue: if ship.position in dropoffs: returning.discard(ship.id) ship.returning = False elif ship.id in returning and not ship.staying: # move to drop-off # logging.info('move to dropoff') ship.returning = True if constants.MAX_TURNS - game.turn_number <= 10: collide = True else: collide = False d = ships_des.pop(ship.id, None) destinations.pop(d, None) move(closest_dropoff(ship.position), ship.position, ship, positions_used, command_queue, collide=collide, shortest=True) for ship in ship_queue: if ship.returning or ship.staying: continue elif (ship.halite_amount + ship.collect_amount > RETURN_AMOUNT): # will staying make me cross over the line? ship.staying = True move(ship.position, ship.position, ship, positions_used, command_queue) else: logging.info(f'd {destinations}') highest_so_far = ship.collect_amount * STAY_FACTOR best = ship.position if ship.id in ships_des: p = ships_des[ship.id] # where I was going w = game_map[p].halite_amount / ( game_map.calculate_distance(ship.position, p) * DISTANCE_FACTOR + 1) if p in enemy_locations: w *= ENEMY_FACTOR if w > highest_so_far: best = p else: for p in highs: # p = game_map.normalize(p) if p in destinations: continue hal = game_map[p].halite_amount if p in dropoffs: hal = ship.halite_amount weighted = hal / (game_map.calculate_distance( ship.position, p) * DISTANCE_FACTOR + 1) if weighted > highest_so_far: best = p if p in destinations and destinations[p] != ship.id: # logging.info(f'nope on {p} for ship {ship.id}') continue p = best logging.info(f'Ship {ship.id} moving to position {p}') if ship.id in ships_des: if ships_des[ship.id] != p: if ships_des[ship.id] in destinations: del destinations[ships_des[ship.id]] else: logging.info( f'Mismatch. Expected {ships_des[ship.id]} in {destinations}' ) ships_des[ship.id] = p destinations[p] = ship.id if p in dropoffs: shortest = True else: shortest = False move(p, ship.position, ship, positions_used, command_queue, shortest=shortest) '''''' halite_collected = me.halite_amount + spent_so_far - 5000 ship_turns = 0 for id, turn in first_seen.items(): ship_turns += game.turn_number - turn collection_per_turn.append(halite_collected) if game.turn_number < 20: avg_per_ship_per_turn = 2000 else: # halite_diff = collection_per_turn[game.turn_number - 1] - \ # collection_per_turn[game.turn_number - 21] avg_per_ship_per_turn = halite_collected / ship_turns logging.info( f'turn {game.turn_number} has avg {avg_per_ship_per_turn}') # if (avg_per_ship_per_turn * turns_left >= 1400 and if ((avg_per_ship_per_turn * turns_left >= BUILD_FACTOR) and me.halite_amount >= constants.SHIP_COST and not dropoff and halite_percent > BUILD_HALITE_LIMIT and syp not in positions_used): spent_so_far += constants.SHIP_COST positions_used.add(syp) command_queue.append(me.shipyard.spawn()) # Send your moves back to the game environment, ending this turn. logging.info(command_queue) game.end_turn(command_queue)
for i in range(0, game.game_map.height): current_value = [] for j in range(0, game.game_map.width): current_value.append( calculate_tile_value(Position(i, j), game.me.shipyard.position)) tileValues.append(current_value) while True: game.update_frame() me = game.me game_map = game.game_map command_queue = [] direction_order = Direction.get_all_cardinals() + [Direction.Still] def _ship_needs_tile(ship): "Simply Writing out for clarity." if ship.id not in ship_states: return True if ship_states[ship.id] in [ EXPLORING, DEPOSITING ] and ship.position == previous_positions[ship.id]: return True if ship_states[ship.id] == HARVESTING and game_map[ ship.position].halite_amount <= 10: return True else: return False
def run(): global spent_so_far destinations = {} ships_des = {} while True: game.update_frame() # You extract player metadata and the updated map metadata here for convenience. me = game.me game_map = game.game_map turns_left = constants.MAX_TURNS - game.turn_number halite_left = get_halite_amount() halite_percent = halite_left / starting_halite_amount highs = [] # spots = PriorityQueue() for x, y in itertools.product(range(game_map.width), range(game_map.height)): highs.append(Position(x, y)) highs = sorted(highs, key=lambda p: game_map[p].halite_amount, reverse=True)[:150] positions_used = set() command_queue = [] ship_queue = me.get_ships() for do in me.get_dropoffs(): pos = do.position if pos not in dropoffs: dropoffs.append(pos) # top10 = [highs.get().position for _ in range(10)] # logging.info(top10) # sort ships by proximity to shipyard ship_queue = sorted( ship_queue, key=lambda s: game_map.calculate_distance(s.position, syp), reverse=True) # ship_queue = sorted(ship_queue, key=lambda s: s.id, # reverse=True) dropoff = False for ship in ship_queue: if ship.id not in first_seen: first_seen[ship.id] = game.turn_number ship.staying = False ship.returning = False if ship.position in destinations: del destinations[ship.position] if (constants.MAX_TURNS - game.turn_number) < 4 and ship.position in dropoffs: # ignore ship completely so that it can die ship.staying = True # should we build a drop-off? elif (len(ship_queue) >= 10 * len(dropoffs) and ship.position in highs and game_map.calculate_distance( ship.position, closest_dropoff(ship.position)) > 15 and me.halite_amount > constants.DROPOFF_COST - game_map[ship.position].halite_amount + ship.halite_amount and game.turn_number < constants.MAX_TURNS * 0.75 and halite_percent > 0.4 and # len(dropoffs) < 4 and not dropoff): dropoff = True spent_so_far += constants.DROPOFF_COST - game_map[ ship.position].halite_amount command_queue.append(ship.make_dropoff()) ship.staying = True positions_used.add(ship.position) # can it move? elif (game_map[ship.position].halite_amount * 0.1) > ship.halite_amount: # can't move, stay put # logging.info(f'ship {ship.id} staying with {ship.halite_amount} avaliable') move(ship.position, ship.position, ship, positions_used, command_queue) ship.staying = True elif ((ship.halite_amount > RETURN_AMOUNT) or (game_map.calculate_distance( ship.position, closest_dropoff(ship.position)) + 4 >= (constants.MAX_TURNS - game.turn_number))): returning.add(ship.id) ship.returning = True elif (ship.halite_amount + (game_map[ship.position].halite_amount * 0.25) > 1000): # its not worth staying on the square, just go home ship.returning = True returning.add(ship.id) # mark enemy ships if we don't control more than half the ships on the board total_num_of_ships = 0 for i in game.players: total_num_of_ships += len(game.players[i].get_ships()) if len(ship_queue) < total_num_of_ships: for i in game.players: if i == game.my_id: continue player = game.players[i] for ship in player.get_ships(): for d in Direction.get_all_cardinals() + [(0, 0)]: location = game_map.normalize( ship.position.directional_offset(d)) if game_map.calculate_distance( location, closest_dropoff(ship.position)) <= 1: pass # elif (ship.halite_amount > 950 and # len(game.players[ship.owner].get_ships()) < len(ship_queue)): # its fine to collide with a high halite ship and steal its halite # pass else: positions_used.add(location) for ship in ship_queue: if ship.position in dropoffs: returning.discard(ship.id) ship.returning = False elif ship.id in returning and not ship.staying: # move to drop-off # logging.info('move to dropoff') ship.returning = True if constants.MAX_TURNS - game.turn_number <= 10: collide = True else: collide = False move(closest_dropoff(ship.position), ship.position, ship, positions_used, command_queue, collide=collide, shortest=True) for ship in ship_queue: if ship.returning or ship.staying: continue elif (ship.halite_amount + (game_map[ship.position].halite_amount * 0.25) > RETURN_AMOUNT): # will staying make me cross over the line? ship.staying = True move(ship.position, ship.position, ship, positions_used, command_queue) else: logging.info(f'd {destinations}') highest_so_far = game_map[ship.position].halite_amount best = ship.position for p in highs: # p = game_map.normalize(p) if p in destinations: continue hal = game_map[p].halite_amount if p in dropoffs: hal = ship.halite_amount weighted = hal / ( game_map.calculate_distance(ship.position, p) + 1) if weighted > highest_so_far: best = p if p in destinations and destinations[p] != ship.id: # logging.info(f'nope on {p} for ship {ship.id}') continue p = best logging.info(f'Ship {ship.id} moving to position {p}') if ship.id in ships_des: if ships_des[ship.id] != p: if ships_des[ship.id] in destinations: del destinations[ships_des[ship.id]] else: logging.info( f'Mismatch. Expected {ships_des[ship.id]} in {destinations}' ) ships_des[ship.id] = p destinations[p] = ship.id # if p in dropoffs: # p. move(p, ship.position, ship, positions_used, command_queue, shortest=False) '''''' halite_collected = me.halite_amount + spent_so_far - 5000 ship_turns = 0 for id, turn in first_seen.items(): ship_turns += game.turn_number - turn collection_per_turn.append(halite_collected) if game.turn_number < 20: avg_per_ship_per_turn = 2000 else: # halite_diff = collection_per_turn[game.turn_number - 1] - \ # collection_per_turn[game.turn_number - 21] avg_per_ship_per_turn = halite_collected / ship_turns / 1.1 logging.info( f'turn {game.turn_number} has avg {avg_per_ship_per_turn}') # if (avg_per_ship_per_turn * turns_left >= 1400 and if (((turns_left > 150 and not NEW_SPAWN) or (avg_per_ship_per_turn * turns_left >= 1800 and NEW_SPAWN)) and me.halite_amount >= constants.SHIP_COST and not dropoff and halite_percent > 0.4 and syp not in positions_used): spent_so_far += constants.SHIP_COST command_queue.append(me.shipyard.spawn()) # Send your moves back to the game environment, ending this turn. logging.info(command_queue) game.end_turn(command_queue)
ship.position, close_drop.position) * 20) + ( game.turn_number * 2) and game_map[ship.position].halite_amount > 600: command_queue.append(ship.stay_still()) else: shipyard_dist = int(2 + game.turn_number // 150) #** if game.turn_number == 100 and shipyard_dist == 3: shipyard_dist += 1 dist = game_map.calculate_distance(ship.position, close_drop.position) if dist < shipyard_dist: rand_move = rand_move_num % 4 #random.randInt(0,3)rand_move_num%4 if ship.position == close_drop.position: # rand_move_num += random.randint(0,4) dir = Direction.get_all_cardinals()[random.randint(0, 3)] if game_map[ship.position.directional_offset( dir)].is_occupied or game_map[ ship.position.directional_offset( dir)].has_structure: dir = game_map.naive_navigate( ship, ship.position.directional_offset(dir)) command_queue.append(ship.move(dir)) else: if game_map[ship.position].halite_amount > 700: command_queue.append(ship.stay_still()) else: dir = game_map.naive_navigate(ship, close_drop.position) orig_dir = dir if dir == Direction.North:
def getShipMove(ship, sy): cleanPlaces(targetArea) bestSpot = [] best = 0 amount = 700 options = 0 if ship.position == Shipyard: openSpot = False for i in Direction.get_all_cardinals(): if (game_map[ship.position.directional_offset(i)].is_occupied == False): openSpot = True if openSpot == False: bestDir = Direction.North placepicked.append(ship.position.directional_offset(bestDir)) command_queue.append(ship.move(bestDir)) return 0 #< constants.MAX_HALITE / 35 if (game_map[ship.position].halite_amount <= 50 and (ship.halite_amount < amount)) or (Shipyard.__eq__(ship.position)): #print("WOOOOOOLK") for i in Direction.get_all_cardinals(): if (game_map[ship.position.directional_offset(i)].is_occupied == False): bestSpot.append(game_map[ship.position.directional_offset(i)]) options += 1 for i in bestSpot: if (i.halite_amount >= best): #bestDir = game_map.naive_navigate(ship, i.position) best = i.halite_amount bestDir = game_map.get_unsafe_moves(ship.position, i.position)[0] if best < 100: if len(targetArea) == 0: pos = [] for i in Direction.get_all_cardinals(): found = False if (game_map[ship.position.directional_offset( i)].is_occupied == False and game_map[ship.position.directional_offset(i)]. position.__ne__(game_map[me.shipyard].position)): pos.append(i) #bestDir = (i) found = True bestDir = random.choice(pos) if found == False: bestDir = (0, 0) placepicked.append(ship.position.directional_offset(bestDir)) command_queue.append(ship.move(bestDir)) return 0 else: bestDir = Direction.convertStr(getClosestSpot(ship)) if game_map[ship.position.directional_offset( bestDir)].is_occupied == False and not game_map[ ship.position.directional_offset( bestDir)].position in placepicked: placepicked.append( ship.position.directional_offset(bestDir)) command_queue.append(ship.move(bestDir)) return 0 bestDir = (0, 0) place = game_map[ship.position.directional_offset((bestDir))].position inPicked = False for i in placepicked: if (i.__eq__(place)): inPicked = True if inPicked == False and game_map[ship.position.directional_offset( bestDir)].is_occupied == False: placepicked.append(ship.position.directional_offset(bestDir)) command_queue.append((ship.move(bestDir))) return 0 else: isFound = False bestDir = (0, 0) for i in Direction.get_all_cardinals(): if (game_map[ship.position.directional_offset(i)].is_occupied == False) and ((game_map[ ship.position.directional_offset(i)].position in placepicked) == False): bestDir = (game_map.get_unsafe_moves( ship.position, ship.position.directional_offset(i))[0]) isFound = True placepicked.append( ship.position.directional_offset(bestDir)) command_queue.append(ship.move(bestDir)) return 0 if isFound == False: command_queue.append(ship.stay_still()) placepicked.append(ship.position) return 0 #returnCommand = (ship.move(bestDir)) else: if ship.is_full or ship.halite_amount > amount: #command_queue.append(game_map.get_unsafe_moves(ship.position, Shipyard)[0]) placeVal = game_map[ship.position.directional_offset( game_map.get_unsafe_moves(ship.position, Shipyard)[0])].position inPicked = False for e in placepicked: if (placeVal.__eq__(e)): inPicked = True if inPicked == True: isFound = False bestDir = (0, 0) for i in Direction.get_all_cardinals(): if (game_map[ship.position.directional_offset( i)].is_occupied == False) and ( (game_map[ship.position.directional_offset( i)].position in placepicked) == False): bestDir = (game_map.get_unsafe_moves( ship.position, ship.position.directional_offset(i))[0]) isFound = True placepicked.append( ship.position.directional_offset(bestDir)) command_queue.append(ship.move(bestDir)) return 0 ##command_queue.append(ship.stay_still()) ##placepicked.append(ship.position) ##return 0 else: command_queue.append( ship.move(game_map.naive_navigate(ship, Shipyard))) placepicked.append(placeVal) return 0 else: if game_map[ship.position].halite_amount > 0: command_queue.append(ship.stay_still()) placepicked.append(ship.position) return 0 else: isFound = False bestDir = (0, 0) for i in Direction.get_all_cardinals(): if (game_map[ship.position.directional_offset( i)].is_occupied == False) and ( (game_map[ship.position.directional_offset( i)].position in placepicked) == False): bestDir = (game_map.get_unsafe_moves( ship.position, ship.position.directional_offset(i))[0]) isFound = True placepicked.append(ship.position.directional_offset(bestDir)) command_queue.append(ship.move(bestDir)) return 0
def run(self): """ <<<Game Begin>>> """ # This game object contains the initial game state. # game = hlt.Game() game = self.game # Give ships extra time to make it back to a dock, may not be necessary with drop offs in place now TURN_REMAINING_FUDGE = 6 # Don't go back out if the game is over, sit and get crashed # TURN_NO_NEW_ORDERS = 16 # Build new ships until this turn BUILD_UNTIL = 200 # Maximum number of drop offs to build MAX_DROPOFF = 2 # Drop offs must be built at least this far from any other dock MIN_DIST_TO_DOCK = 16 # width and height of a square used to find halite clusters CLUSTER_SIZE = 2 # width and height of the game map MAP_SIZE = game.game_map.width # maximum number of turns in this game MAX_TURNS = 400 # the number of players in the game NUM_PLAYERS = len(game.players) # which job is assigned to this ship SHIP_JOBS = {} # which position this ship is trying to reach SHIP_ORDERS = {} # amount of halite to return with RETURN_WITH = 900 # todo: tune the following params # distance at which a ship counts towards NEAREST_SHIP_COUNT NEAREST_SHIP_DIST = 10 # number of ships that must be nearby to consider making a dock NEAREST_SHIP_COUNT = 5 # amount of halite gained required to move to a new tile REQUIRED_GAIN = 1.4 # amount of gain required during CLEAN before switching to CLUSTER BEST_GAIN_THRESHOLD = 5 # todo: determine if this param is valuable, block tiles near enemy ships in 4p games ENEMY_RADIUS = 0 # set default params per map size if MAP_SIZE == 40: MAX_TURNS = 425 BUILD_UNTIL = 225 MAX_DROPOFF = 2 # MIN_DIST_TO_DOCK = 18 # TURN_REMAINING_FUDGE = 6 # TURN_NO_NEW_ORDERS = 14 CLUSTER_SIZE = 2 elif MAP_SIZE == 48: MAX_TURNS = 450 BUILD_UNTIL = 250 MAX_DROPOFF = 3 # MIN_DIST_TO_DOCK = 20 # TURN_REMAINING_FUDGE = 6 # TURN_NO_NEW_ORDERS = 10 CLUSTER_SIZE = 2 elif MAP_SIZE == 56: MAX_TURNS = 475 BUILD_UNTIL = 275 MAX_DROPOFF = 4 # MIN_DIST_TO_DOCK = 22 # TURN_REMAINING_FUDGE = 6 # TURN_NO_NEW_ORDERS = 8 CLUSTER_SIZE = 2 elif MAP_SIZE == 64: MAX_TURNS = 500 BUILD_UNTIL = 300 MAX_DROPOFF = 6 # MIN_DIST_TO_DOCK = 24 # TURN_REMAINING_FUDGE = 6 # TURN_NO_NEW_ORDERS = 6 CLUSTER_SIZE = 2 # update params based on the number of players if NUM_PLAYERS > 2: MAX_DROPOFF -= 1 ENEMY_RADIUS = 1 # calculate clusters cluster_values_o = [[0 for x in range(MAP_SIZE)] for y in range(MAP_SIZE)] for x in range(MAP_SIZE): for y in range(MAP_SIZE): for y1 in range(y - CLUSTER_SIZE, y + CLUSTER_SIZE): for x1 in range(x - CLUSTER_SIZE, x + CLUSTER_SIZE): cluster_values_o[y][x] += game.game_map[Position( x1, y1)].halite_amount cluster_avg_o = np.matrix(cluster_values_o).mean() cluster_std_o = np.matrix(cluster_values_o).std() game.ready("v19-2p") """ <<<Game Loop>>> """ while True: game.update_frame() game_map = game.game_map me = game.me halite_available = me.halite_amount command_queue = [] ship_moves = {} # Keep up with how many turns are left turns_remaining = MAX_TURNS - game.turn_number logging.info("turns remaining {}".format(turns_remaining)) # calculate current cluster values cluster_values_n = [[0 for x in range(MAP_SIZE)] for y in range(MAP_SIZE)] tile_values_n = [[0 for x in range(MAP_SIZE)] for y in range(MAP_SIZE)] for x in range(MAP_SIZE): for y in range(MAP_SIZE): tile_values_n[y][x] = game.game_map[Position( x, y)].halite_amount for y1 in range(y - CLUSTER_SIZE, y + CLUSTER_SIZE): for x1 in range(x - CLUSTER_SIZE, x + CLUSTER_SIZE): cluster_values_n[y][x] += game.game_map[Position( x1, y1)].halite_amount cluster_avg_n = np.matrix(cluster_values_n).mean() cluster_std_n = np.matrix(cluster_values_n).std() cluster_threshold = cluster_avg_n + (cluster_std_n * .5) tiles_avg_n = np.matrix(tile_values_n).mean() tiles_std_n = np.matrix(tile_values_n).std() # dropoff calculations dropoffs = me.get_dropoffs() dropoff_p1 = halite_available > constants.DROPOFF_COST and len( dropoffs) < MAX_DROPOFF dropoff_built = False # calculate blocked/dangerous tiles # permanently blocked cells - enemy shipyards, update with enemy docks as game progresses blocked_tiles_n = [[False for x in range(MAP_SIZE)] for y in range(MAP_SIZE)] danger_tiles_n = [[0 for x in range(MAP_SIZE)] for y in range(MAP_SIZE)] for player in game.players.values(): if player.id == game.me.id: continue blocked = player.shipyard.position blocked_tiles_n[blocked.y][blocked.x] = True for player in game.players.values(): if player.id == me.id: continue for ship in player.get_ships(): blocked_tiles_n[ship.position.y][ship.position.x] = True # in 4p games, consider all tiles around enemies dangerous if ENEMY_RADIUS > 0: for p_blocked in ship.position.get_surrounding_cardinals( ): p_norm = game_map.normalize(p_blocked) danger_tiles_n[p_norm.y][p_norm.x] += 1 for dropoff in player.get_dropoffs(): blocked_tiles_n[dropoff.position.y][ dropoff.position.x] = True # always consider the tiles around a dropoff extremely dangerous for x in range(dropoff.position.x - 1, dropoff.position.x + 1): for y in range(dropoff.position.y - 1, dropoff.position.y + 1): p_norm = game_map.normalize(Position(x, y)) danger_tiles_n[p_norm.y][p_norm.x] += 4 # blocked_tiles_n[p_norm.y][p_norm.x] = True # clear my shipyard blocked_tiles_n[me.shipyard.position.y][ me.shipyard.position.x] = False # clear my dropoffs for dropoff in dropoffs: blocked_tiles_n[dropoff.position.y][dropoff.position.x] = False # iterate through my ships and block their locations # this is done outside of the all players loop so that I ignore enemy ships in my docks for ship in me.get_ships(): blocked_tiles_n[ship.position.y][ship.position.x] = True # clean up ship orders by removing orders tied to ships that have been lost orders_to_clear = [] for key in SHIP_ORDERS.keys(): try: if me.get_ship(key) is None: orders_to_clear.append(key) except KeyError: orders_to_clear.append(key) for key in orders_to_clear: del SHIP_ORDERS[key] # iterate through my ships and give them orders for ship in me.get_ships(): logging.info("Ship {} at position {} has {} halite.".format( ship.id, ship.position, ship.halite_amount)) logging.info("Ship {} job {} target {}".format( ship.id, SHIP_JOBS.get(ship.id), SHIP_ORDERS.get(ship.id))) # find closest dock, starting with shipyard closest_dock = me.shipyard distance_to_dock = game_map.calculate_distance( ship.position, me.shipyard.position) # assign default job to new ships and order them out of the shipyard if SHIP_JOBS.get(ship.id) is None or distance_to_dock == 0: SHIP_JOBS[ship.id] = "CLEAN" unsafe_moves = Direction.get_all_cardinals() logging.info("Ship {} needs to gtfo of the dock".format( ship.id, len(unsafe_moves))) logging.info("Ship {} submitted {} potential moves".format( ship.id, len(unsafe_moves))) ship_moves[ship.id] = unsafe_moves # on to the next ship continue # check for closer dropoff for dropoff in dropoffs: new_dist = game_map.calculate_distance( ship.position, dropoff.position) if new_dist < distance_to_dock: distance_to_dock = new_dist closest_dock = dropoff logging.info("Ship {} closest_dock {} distance {}".format( ship.id, closest_dock, distance_to_dock)) # determine if this ship should convert to a dropoff if dropoff_p1 and not dropoff_built and distance_to_dock > MIN_DIST_TO_DOCK: logging.info( 'todo: determine if ship should become dropoff') dropoff_p2 = False dropoff_p3 = False # evaluate cluster value at ship position if cluster_values_n[ship.position.y][ ship.position.x] > cluster_threshold: dropoff_p2 = True if dropoff_p2: nearby_ships = [] for ship_a in me.get_ships(): # ignore this ship if ship_a.id == ship.id: continue if game_map.calculate_distance( ship_a.position, ship.position) < NEAREST_SHIP_DIST: nearby_ships.append(ship_a) if len(nearby_ships) > NEAREST_SHIP_COUNT: dropoff_p3 = True break if dropoff_p3: logging.info('should become dropoff') dropoff_built = True halite_available -= constants.DROPOFF_COST command_queue.append(ship.make_dropoff()) blocked_tiles_n[ship.position.y][ ship.position.x] = False # move on to next ship continue # start heading home if the game is almost over if turns_remaining - TURN_REMAINING_FUDGE <= distance_to_dock: logging.info("Ship {} converted to {}".format( ship.id, 'CRASH')) SHIP_JOBS[ship.id] = "CRASH" # Job == CRASH if SHIP_JOBS.get(ship.id) == "CRASH": logging.info("Ship {} job {}".format(ship.id, 'CRASH')) # do nothing, game is almost over if distance_to_dock == 0: logging.info("Ship {} waiting for the end".format( ship.id, 'RETURN')) continue # get moves that will move this ship towards the closest dock unsafe_moves = game_map.get_unsafe_moves( ship.position, closest_dock.position) # move into dock, ignoring collisions if distance_to_dock == 1: logging.info("Ship {} crashing dock {}".format( ship.id, closest_dock)) for move in unsafe_moves: command_queue.append(ship.move(move)) blocked_tiles_n[ship.position.y][ ship.position.x] = False break # next ship continue else: logging.info( "Ship {} submitted {} potential moves".format( ship.id, len(unsafe_moves))) ship_moves[ship.id] = unsafe_moves # return home if carrying a lot of halite if ship.halite_amount > RETURN_WITH: SHIP_JOBS[ship.id] = "RETURN" # JOB == RETURN if SHIP_JOBS.get(ship.id) == "RETURN": logging.info("Ship {} job {}".format(ship.id, 'RETURN')) # in the dock already if distance_to_dock == 0: # game almost over if "CRASH" in SHIP_JOBS.values(): logging.info("Ship {} waiting for the end".format( ship.id)) # todo: make sure I don't need to mark this as free # wait to be destroyed continue # assign new job logging.info("Ship {} assigned job {}".format( ship.id, "CLEAN")) SHIP_JOBS[ship.id] = "CLEAN" # get out of the dock # del SHIP_JOBS[ship.id] # unsafe_moves = Direction.get_all_cardinals() # logging.info("Ship {} needs to gtfo of the dock".format(ship.id, len(unsafe_moves))) # logging.info("Ship {} submitted {} potential moves".format(ship.id, len(unsafe_moves))) # ship_moves[ship.id] = unsafe_moves elif distance_to_dock == 1: if "CRASH" in SHIP_JOBS.values(): logging.info("Ship {} crashing dock {}".format( ship.id, closest_dock)) unsafe_moves = game_map.get_unsafe_moves( ship.position, closest_dock.position) for move in unsafe_moves: command_queue.append(ship.move(move)) blocked_tiles_n[ship.position.y][ ship.position.x] = False break # move to next ship continue else: unsafe_moves = game_map.get_unsafe_moves( ship.position, closest_dock.position) logging.info( "Ship {} submitted {} potential moves".format( ship.id, len(unsafe_moves))) ship_moves[ship.id] = unsafe_moves else: logging.info("Ship {} heading to dock {}".format( ship.id, closest_dock)) unsafe_moves = game_map.get_unsafe_moves( ship.position, closest_dock.position) logging.info( "Ship {} submitted {} potential moves".format( ship.id, len(unsafe_moves))) ship_moves[ship.id] = unsafe_moves # JOB == CLEAN if SHIP_JOBS.get(ship.id) == "CLEAN": logging.info("Ship {} job {}".format(ship.id, 'CLEAN')) cur_pos_val = game_map[ship.position].halite_amount cur_pos_gain = math.ceil(cur_pos_val * .25) cur_pos_val_next = cur_pos_val - cur_pos_gain cost_to_move = math.floor(cur_pos_val / 10) nearby_positions = ship.position.get_surrounding_cardinals( ) best_gain = cur_pos_gain best_position = ship.position min_gain = cur_pos_gain * REQUIRED_GAIN ranked_positions = {} for position in nearby_positions: p_norm = game_map.normalize(position) logging.info("Ship {} considering {}.".format( ship.id, p_norm)) # ignore closest dock if p_norm == closest_dock.position: continue tile_value = game_map[p_norm].halite_amount potential_gain = math.ceil( tile_value * .25) - cost_to_move logging.info( "Ship {} considering {} halite {}.".format( ship.id, p_norm, tile_value)) if min_gain < potential_gain: logging.info( "Ship {} considering {} potential_gain {}.". format(ship.id, p_norm, potential_gain)) ranked_positions[potential_gain] = p_norm if potential_gain > best_gain: best_position = p_norm best_gain = potential_gain # todo: confirm this works, sometimes we might be better off sitting still if best_gain < BEST_GAIN_THRESHOLD: logging.info("Ship {} assigned job {}".format( ship.id, "CLUSTER")) SHIP_JOBS[ship.id] = "CLUSTER" elif best_gain == cur_pos_gain: logging.info("Ship {} {}".format( ship.id, "staying still")) else: # order positions and append to requested moves unsafe_moves = [] for k in sorted(ranked_positions.keys(), reverse=True): unsafe_moves += game_map.get_unsafe_moves( ship.position, ranked_positions[k]) logging.info( "Ship {} submitted {} potential moves".format( ship.id, len(unsafe_moves))) ship_moves[ship.id] = unsafe_moves # JOB == CLUSTER if SHIP_JOBS.get(ship.id) == "CLUSTER": logging.info("Ship {} job {}".format(ship.id, 'CLUSTER')) needs_assignment = True # validate existing order if SHIP_ORDERS.get(ship.id): order = SHIP_ORDERS.get(ship.id) logging.info( "Ship {} has existing assignment {}".format( ship.id, order)) # if ship at target, clean, else determine if target is still valid if game_map.calculate_distance(ship.position, order) == 0: logging.info("Ship {} reached target {}".format( ship.id, order)) logging.info("Ship {} {}".format( ship.id, "staying still")) logging.info("Ship {} assigned job {}".format( ship.id, "CLEAN")) del SHIP_ORDERS[ship.id] SHIP_JOBS[ship.id] = "CLEAN" needs_assignment = False else: logging.info( "Ship {} has not reached target {}".format( ship.id, order)) cluster_ratio = cluster_values_n[order.y][ order.x] / cluster_values_o[order.y][order.x] if cluster_ratio < .6: # todo: this might not work towards the end of a game with high performance bots logging.info( "Ship {} target {} remaining {} - new target" .format(ship.id, order, cluster_ratio)) elif game_map[order].is_occupied: logging.info( "Ship {} target {} occupied - new target". format(ship.id, order)) else: needs_assignment = False logging.info( 'Ship {} continuing towards {}'.format( ship.id, order)) unsafe_moves = game_map.get_unsafe_moves( ship.position, order) logging.info( "Ship {} submitted {} potential moves". format(ship.id, len(unsafe_moves))) ship_moves[ship.id] = unsafe_moves if needs_assignment: logging.info("Ship {} {}".format( ship.id, 'getting new assignment')) clusters = {} for x in range(MAP_SIZE): for y in range(MAP_SIZE): cluster_value = cluster_values_n[y][x] if cluster_value > cluster_threshold: cluster_position = Position(x, y) cluster_distance = game_map.calculate_distance( ship.position, cluster_position) if cluster_distance == 0: cluster_distance = 1 else: cluster_distance = cluster_distance * cluster_distance clusters[ cluster_value / cluster_distance] = cluster_position if len(clusters.keys()) > 0: best_position = None for cluster in sorted(clusters.keys(), reverse=True): logging.info( 'Ship {} testing Position {} value {}'. format(ship.id, clusters[cluster], cluster)) if game_map[clusters[cluster]].is_occupied: logging.info( 'Ship {} Position {} is occupied'. format(ship.id, clusters[cluster])) continue if clusters[cluster] in SHIP_ORDERS.values(): logging.info( 'Ship {} Position {} is already assigned' .format(ship.id, clusters[cluster])) continue # determine if there are too many ships close to this cluster already x = clusters[cluster].x y = clusters[cluster].y ships_in_cluster = 0 for y1 in range(y - CLUSTER_SIZE, y + CLUSTER_SIZE): for x1 in range(x - CLUSTER_SIZE, x + CLUSTER_SIZE): if game_map[Position(x1, y1)].is_occupied: ships_in_cluster += 1 # todo: validate this number is relevant if ships_in_cluster > 10: continue # todo: determine if this ship can move towards cluster best_position = clusters[cluster] SHIP_ORDERS[ship.id] = best_position break if best_position: logging.info( 'Ship {} targeting best cluster {}'.format( ship.id, best_position)) unsafe_moves = game_map.get_unsafe_moves( ship.position, best_position) logging.info( "Ship {} submitted {} potential moves". format(ship.id, len(unsafe_moves))) ship_moves[ship.id] = unsafe_moves # attempt to solve traffic jams changes_made = True while changes_made: if len(ship_moves.keys()) == 0: break changes_made = False ship_ids_resolved = [] for k in ship_moves.keys(): ship = me.get_ship(k) unsafe_moves = ship_moves[k] # if ship does not have enough halite to move, mark it resolved cur_pos_val = game_map[ship.position].halite_amount cost_to_move = math.floor(cur_pos_val / 10) if ship.halite_amount < cost_to_move: logging.info('Ship {} cannot move'.format(ship.id)) ship_ids_resolved.append(k) continue for move in unsafe_moves: potential_position = game_map.normalize( ship.position.directional_offset(move)) logging.info("Ship {} testing {}".format( ship.id, potential_position)) # tile is blocked if blocked_tiles_n[potential_position.y][ potential_position.x]: logging.info( "Ship {} testing {} is blocked".format( ship.id, potential_position)) logging.info("{} occupied {}".format( potential_position, game_map[potential_position].is_occupied)) continue # tile is dangerous if ENEMY_RADIUS > 0 and SHIP_JOBS.get( ship.id) == "CLEAN": danger_rating = danger_tiles_n[ potential_position.y][potential_position.x] # ignore dangerous tiles if danger_rating > 3: logging.info("{} danger {}".format( potential_position, danger_rating)) continue # todo: test danger ratio of tile if job is clean if danger_rating > 0 and tile_values_n[ potential_position.y][ potential_position.x] < tiles_avg_n + ( tiles_std_n * danger_rating): continue logging.info('Ship {} moving to {}'.format( ship.id, potential_position)) command_queue.append(ship.move(move)) blocked_tiles_n[ship.position.y][ ship.position.x] = False blocked_tiles_n[potential_position.y][ potential_position.x] = True changes_made = True ship_ids_resolved.append(k) break # clear out resolved moves if len(ship_ids_resolved) > 0: logging.info('Resolved {} ships'.format( len(ship_ids_resolved))) for ship_id in ship_ids_resolved: del ship_moves[ship_id] # ships could not move due to blocked tiles, attempt to swap if len(ship_moves.keys()) > 0: logging.info("{} ships did not move, attempting swaps".format( len(ship_moves.keys()))) changes_made = True while changes_made: if len(ship_moves.keys()) == 0: break changes_made = False ship_ids_resolved = [] for k in ship_moves.keys(): for k1 in ship_moves.keys(): if k == k1: continue ship_a = me.get_ship(k) ship_b = me.get_ship(k1) if game_map.calculate_distance( ship_a.position, ship_b.position) > 1: continue positions_a = [] moves_a = ship_moves[k] for move in moves_a: positions_a.append( game_map.normalize( ship_a.position.directional_offset( move))) positions_b = [] moves_b = ship_moves[k1] for move in moves_b: positions_b.append( game_map.normalize( ship_b.position.directional_offset( move))) if ship_a.position in positions_b and ship_b.position in positions_a: logging.info( "ship {} at {} can swap with ship {} at {}" .format(k, ship_a.position, k1, ship_b.position)) unsafe_a = game_map.get_unsafe_moves( ship_a.position, ship_b.position) unsafe_b = game_map.get_unsafe_moves( ship_b.position, ship_a.position) command_queue.append(ship_a.move(unsafe_a[0])) command_queue.append(ship_b.move(unsafe_b[0])) changes_made = True ship_ids_resolved.append(k) ship_ids_resolved.append(k1) break if changes_made: # ship a and b swapped, neither one is valid anymore and they need to be cleaned up break # clear out resolved moves if len(ship_ids_resolved) > 0: logging.info("Swapping resolved {} ships".format( len(ship_ids_resolved))) for ship_id in ship_ids_resolved: del ship_moves[ship_id] logging.info("{} ships did not move".format(len( ship_moves.keys()))) # spawn ships if game.turn_number <= BUILD_UNTIL and halite_available >= constants.SHIP_COST and not \ blocked_tiles_n[me.shipyard.position.y][me.shipyard.position.x]: command_queue.append(me.shipyard.spawn()) halite_available -= constants.SHIP_COST # Send your moves back to the game environment, ending this turn. game.end_turn(command_queue)
def run(): global spent_so_far while True: game.update_frame() # You extract player metadata and the updated map metadata here for convenience. me = game.me game_map = game.game_map turns_left = constants.MAX_TURNS - game.turn_number halite_left = get_halite_amount() halite_percent = halite_left / starting_halite_amount # highs = PriorityQueue() # spots = PriorityQueue() # for x, y in itertools.product(range(game_map.width), range(game_map.height)): # highs.put( # PP( # (constants.MAX_HALITE - game_map[Position(x, y)].halite_amount * .25) + # (game_map.calculate_distance(Position(x,y),(0, 0) syp)) * 2, # Position(x, y))) positions_used = set() destinations = set() command_queue = [] ship_queue = me.get_ships() for do in me.get_dropoffs(): pos = do.position if pos not in dropoffs: dropoffs.append(pos) # top10 = [highs.get().position for _ in range(10)] # logging.info(top10) # sort ships by proximity to shipyard # ship_queue = sorted(ship_queue, key=lambda s: game_map.calculate_distance(s.position, syp), # reverse=True) ship_queue = sorted(ship_queue, key=lambda s: s.id, reverse=True) dropoff = False for ship in ship_queue: if ship.id not in first_seen: first_seen[ship.id] = game.turn_number ship.staying = False ship.returning = False if ship.position in destinations: destinations.remove(ship.position) if (constants.MAX_TURNS - game.turn_number) < 4 and ship.position in dropoffs: # ignore ship completely so that it can die ship.staying = True # should we build a drop-off? elif (len(ship_queue) > 12 * len(dropoffs) and game_map.calculate_distance( ship.position, closest_dropoff(ship.position)) > 15 and me.halite_amount > constants.DROPOFF_COST - game_map[ship.position].halite_amount + ship.halite_amount and game.turn_number < constants.MAX_TURNS * 0.75 and halite_percent > 0.4 and # len(dropoffs) < 4 and not dropoff): dropoff = True spent_so_far += constants.DROPOFF_COST - game_map[ ship.position].halite_amount command_queue.append(ship.make_dropoff()) ship.staying = True positions_used.add(ship.position) # can it move? elif (game_map[ship.position].halite_amount * 0.1) > ship.halite_amount: # can't move, stay put # logging.info(f'ship {ship.id} staying with {ship.halite_amount} avaliable') move(ship.position, ship.position, ship, positions_used, command_queue) ship.staying = True elif ((ship.halite_amount > 850) or (game_map.calculate_distance( ship.position, closest_dropoff(ship.position)) + 4 >= (constants.MAX_TURNS - game.turn_number))): returning.add(ship.id) ship.returning = True elif (ship.halite_amount + (game_map[ship.position].halite_amount * 0.25) > 1000): # its not worth staying on the square, just go home ship.returning = True returning.add(ship.id) # mark enemy ships if we don't control more than half the ships on the board total_num_of_ships = 0 for i in game.players: total_num_of_ships += len(game.players[i].get_ships()) if len(ship_queue) < total_num_of_ships: for i in game.players: if i == game.my_id: continue player = game.players[i] for ship in player.get_ships(): for d in Direction.get_all_cardinals() + [(0, 0)]: location = game_map.normalize( ship.position.directional_offset(d)) if game_map.calculate_distance( location, closest_dropoff(ship.position)) <= 1: pass # elif (ship.halite_amount > 950 and # len(game.players[ship.owner].get_ships()) < len(ship_queue)): # its fine to collide with a high halite ship and steal its halite # pass else: positions_used.add(location) for ship in ship_queue: if ship.position in dropoffs: returning.discard(ship.id) ship.returning = False elif ship.id in returning and not ship.staying: # move to drop-off # logging.info('move to dropoff') ship.returning = True if constants.MAX_TURNS - game.turn_number <= 10: collide = True else: collide = False move(closest_dropoff(ship.position), ship.position, ship, positions_used, command_queue, collide=collide, shortest=True) for ship in ship_queue: if ship.returning or ship.staying: continue elif ((ship.halite_amount + (game_map[ship.position].halite_amount * 0.25) > 850)): #or # game_map[ship.position].halite_amount > constants.MAX_HALITE / 14): # will staying make me cross over the line? ship.staying = True move(ship.position, ship.position, ship, positions_used, command_queue) # ships_left = [ship for ship in ship_queue if not ship.staying and not ship.returning] # if ships_left: # ps = PriorityQueue() # """a = np.array([(x,y) for x,y in itertools.product(range(ship.position.x-25, ship.position.x+25), # range(ship.position.y-25, ship.position.y+25))]) # # """ # for x, y in itertools.product(range(game_map.height), range(game_map.width)): # p = Position(x, y) # if p in dropoffs:distance_array = np.array([[abs(i) + abs(j) for i in range(-20, 21)] for j in range(-20, 21)]) # continue # # # result = abs(p - closest_dropoff(p)) # # a = min(result.x, game_map.width - result.x) # # b = min(result.y, game_map.height - result.y) # # priority = (game_map[p].halite_amount / # # (math.sqrt(a ** 2 + b ** 2) / 2)) # priority = (game_map[p].halite_amount / # (game_map.calculate_distance(p, closest_dropoff(p)) / 3)) # ps.put(PP(- priority, p)) # # while True: # if ps.empty(): # break # # logging.info(f'ships left: {ships_left}') # pp = ps.get() # best_so_far = 10000 # current_best = 0 # # find closest ship # for ship in ships_left: # distance = game_map.calculate_distance(ship.position, pp.position) # rate = - game_map[ship.position].halite_amount * 1.4 # if distance <= best_so_far: # if rate > pp.priority: # best_so_far = distance # current_best = ship # ship = current_best # if ship: # move(pp.position, ship.position, ship, positions_used, command_queue, # shortest=False) # ships_left.remove(ship) # # # logging.info(f'ships left: {ships_left}') # for ship in ships_left: # # logging.info(f'ship left {ship}') # move(ship.position, ship.position, ship, positions_used, command_queue) else: halite_grid = [[0] * 41] * 41 for x, y in itertools.product( range(ship.position.x - 20, ship.position.x + 21), range(ship.position.y - 20, ship.position.y + 21)): p = game_map.normalize(Position(x, y)) if p in destinations: continue cell = game_map[p] hal = cell.halite_amount best_so_far = 0 # if p == ship.position: # continue # if p in dropoffs: # Gravity for the dropoff is equivalent to halite in ship # hal = ship.halite_amount # if cell.ship and cell.ship.owner != me.id: # hal -= 200 # p_val = (0.07 * hal / # (game_map.calculate_distance(ship.position, p) + 1) ** 2) halite_grid[x - ship.position.x - 20][y - ship.position.y - 20] = hal # p_val = (hal / # (game_map.calculate_distance(ship.position, p) + 1)) # if p_val > best_so_far: # best_so_far = p_val # current_best = p hal_ar = np.array(halite_grid) grav = hal_ar / distance_2 # grav = grav / distance_array u = Direction.North, grav[:21, :] d = Direction.South, grav[20:, :] l = Direction.West, grav[:, :21] r = Direction.East, grav[:, 20:] moves = [(Direction.Still, game_map[ship.position].halite_amount)] for dir, g in (u, d, l, r): n = np.linalg.norm(g) moves.append((dir, n)) moves = sorted(moves, key=lambda x: x[1], reverse=True) logging.info(f'moves {moves}') for d, _ in moves: p = ship.position.directional_offset(d) if p not in positions_used: if p in dropoffs: # move to drop-off shortest = True else: shortest = False move(p, ship.position, ship, positions_used, command_queue, shortest=shortest) break else: move(ship.position, ship.position, ship, positions_used, command_queue) # logging.info(halite_grid) # p = ps.get().position # p = current_best # destinations.add(p) # move(p, ship.position, ship, positions_used, command_queue, shortest=shortest) '''''' halite_collected = me.halite_amount + spent_so_far - 5000 ship_turns = 0 for id, turn in first_seen.items(): ship_turns += game.turn_number - turn collection_per_turn.append(halite_collected) if game.turn_number < 20: avg_per_ship_per_turn = 2000 else: # halite_diff = collection_per_turn[game.turn_number - 1] - \ # collection_per_turn[game.turn_number - 21] avg_per_ship_per_turn = halite_collected / ship_turns / 1.2 logging.info( f'turn {game.turn_number} has avg {avg_per_ship_per_turn}') # if (turns_left > 175 and # Don't spawn a ship if you currently have a ship at port, though - the ships will collide. # if (avg_per_ship_per_turn * turns_left >= 1400 and if (((6 * turns_left > 1400 and not NEW_SPAWN) or (avg_per_ship_per_turn * turns_left >= 1800 and NEW_SPAWN)) and me.halite_amount >= constants.SHIP_COST and not dropoff and halite_percent > 0.5 and syp not in positions_used): spent_so_far += constants.SHIP_COST command_queue.append(me.shipyard.spawn()) # Send your moves back to the game environment, ending this turn. logging.info(command_queue) game.end_turn(command_queue)
def calculate_real_distance(target, source, positions, enemy_locations, amount, ship, collide=False, turn=0, la=13): # if turn == 1: source = game.game_map.normalize(source) if turn == la: return 1, amount, [(0, 0)] if turn == 1: # logging.info(f'zz: {target}, {source}, {positions}, {amount}, {turn}') if collide and source in dropoffs: pass elif source in positions: return 100, -5, [(0, 0)] elif source in enemy_locations and amount > 100: enemy_ship = enemy_locations[source] if enemy_ship.halite_amount > 600: # ignore this ship pass else: return 30, -1, [(0, 0)] elif amount > 600: for d in Direction.get_all_cardinals(): if game.game_map.normalize( source.directional_offset(d)) in enemy_locations: return 30, -1, [(0, 0)] if turn in (2, 3, 4): ship_id = claimed_moves[game.turn_number + 1].get(source) if ship_id and ship_id != ship.id: return 50, -2, [(0, 0)] if target == source and turn != 0: if turn == 0: logging.info('hit') return 1, amount, [(0, 0)] stay_moves = 0 cost_of_move = game.game_map[source].halite_amount * 0.1 if amount - int(cost_of_move) < 0: # must stay stay_moves += 1 collected = math.ceil(game.game_map[source].halite_amount * 0.25) spot_new = game.game_map[source].halite_amount - collected amount = min(amount + collected, 1000) - int(spot_new * 0.1) stayed = True else: amount = amount - int(cost_of_move) stayed = False def calc_move(d, cur_best): new_pos = source.directional_offset(d) num_moves, new_amount, direcs = calculate_real_distance( target, new_pos, positions, enemy_locations, amount, ship, collide=collide, turn=turn + 1, la=la) if turn == 0 and ship.id == 14: logging.info(f'{num_moves} : {new_amount} : {direcs}') if d == (0, 0): collected = math.ceil(game.game_map[new_pos].halite_amount * 0.25) new_amount = min(new_amount + collected, 1000) # logging.info(f'target {target} to source {source}: {}') # if num_moves >= 80: # return cur_best # if (num_moves < cur_best[0] or # (num_moves == cur_best[0] and amount > cur_best[1])): if (new_amount > cur_best[1]) or (new_amount == cur_best[1] and num_moves < cur_best[0]): return num_moves, new_amount, [d] + direcs return cur_best # stay, up, right, left, down - bottom left # all_possible = {(0, 0), (0, 1), (1, 0), (-1, 0), (0, -1)} # stay, left, right, down, up - upper right # all_possible = {(0, 0), (-1, 0), (1, 0), (0, -1), (0, 1)} # stay, right, left, up, down - bottom left # all_possible = {(0, 0), (1, 0), (-1, 0), (0, 1), (0, -1)} # stay, down, right, left, up - upper right # all_possible = {(0, 0), (0, -1), (1, 0), (-1, 0), (0, 1)} # stay, up, left, right, down - bottom left # all_possible = {(0, 0), (0, 1), (-1, 0), (0, 1), (0, -1)} # stay, up, left, down, right - bottom left all_possible = { (0, 1), (-1, 0), (0, -1), (1, 0), (0, 0), } # stay, down, left, up, right - bottom right # all_possible = {(0, 0), (0, -1), (-1, 0), (0, 1), (1, 0)} # all_possible = {(0,0), (0, -1), (1, 0), (-1, 0), (0, 1)} # if game.turn_number < 20: # for dop in all_possible: # logging.info(dop) ideal = set() medio = set() fallback = set() moves = game.game_map.get_unsafe_moves(source, target) if target == source: assert len(moves) == 0 ideal.add((0, 0)) all_possible.discard((0, 0)) fallback = all_possible elif len(moves) == 1: # try move first direction = moves[0] ideal.add(direction) all_possible.discard(direction) reverse = (direction[0] * -1, direction[1] * -1) fallback.add(reverse) all_possible.discard(reverse) medio = all_possible elif len(moves) in (2, 3): for m in moves: ideal.add(m) all_possible.discard(m) medio.add((0, 0)) all_possible.discard((0, 0)) fallback = all_possible else: logging.info("How did this happen?") cur_best = 100, -10, source for d in ideal: cur_best = calc_move(d, cur_best) if cur_best[0] > 25: logging.info('medio') for d in medio: cur_best = calc_move(d, cur_best) if cur_best[0] > 25: logging.info('fallback') for d in fallback: cur_best = calc_move(d, cur_best) if cur_best[0] >= 100: return 100, -10, [(0, 0)] # now calc out own move num_moves, new_amount, direcs = cur_best if stayed: direcs = [(0, 0)] + direcs num_moves += 1 + stay_moves if turn == 0: logging.info(f'{ship.id}, {num_moves}, {new_amount}, {direcs}') return num_moves, new_amount, direcs