def resolve_halite_move(game, collision): """ :param collision [0:ship1 1:ship2 2:move 3:dest1 4:res_func] :returns Returns the 'o' or the lateral move based on the one with the most halite. 'o' gets a 10% preference. """ ship = collision[0] move = collision[2] position = collision[3] if DEBUG & (DEBUG_NAV): logging.info("Nav - ship {} - Resolving density move".format(ship.id)) move_offsets = Direction.laterals(DIRECTIONS[move]) move_offsets.append(Direction.Still) move_offsets.append(Direction.invert(DIRECTIONS[move])) best_moves = [] for o in move_offsets: pos = ship.position.directional_offset(o) cell = game.game_map[pos] if o == Direction.Still: val = cell.halite_amount * 1.1 elif o == Direction.invert(DIRECTIONS[move]): val = cell.halite_amount * .5 else: val = cell.halite_amount best_moves.append((cell, val, o)) best_moves.sort(key=lambda item: item[1], reverse=True) new_offset = None new_cell = None # try the cells to the left/right of the direction orginally attempted in order of # desirability. Additionally check staying still. for m in best_moves: if not m[0].is_occupied: new_offset = m[2] new_cell = m[0] break; # if no cell available, we know ship lost it's original cell, and the two lateral moves are # blocked, try the only remaining option, the inverse of the original, otherwise rewind if new_offset is None: cnt = unwind(game, ship) if DEBUG & (DEBUG_NAV): logging.info("Nav - ship {} - Resolve failed, Unwinding {} ships and using 'o'".format(ship.id, cnt)) #game_map[ship].mark_unsafe(ship) # unwind will mark the cell unsafe move = 'o' else: if DEBUG & (DEBUG_NAV): logging.info("Nav - ship {} - Resolved by best cell {}".format(ship.id, new_cell.position)) new_cell.mark_unsafe(ship) move = Direction.convert(new_offset) if DEBUG & (DEBUG_NAV): logging.info("Nav - ship {} - Successfully resolved density move collision. Move: {}".format(ship.id, move)) return move
def get_backoff_point(game, ship, destination): destinationMoves = game.game_map.get_unsafe_moves(ship.position, destination) if len(destinationMoves) == 0: return ship.position choice = random.choice(destinationMoves) backoffDirection = Direction.invert(choice) # when there's a collion, we backoff between 1 and nShips/2 cells mult = random.randint(1, max(1, round(len(game.me.get_ships()) / 2))) backoffPoint = ship.position + Position(backoffDirection[0] * mult, backoffDirection[1] * mult) # if the backup point wrap, truncate it to the edge to prevent simple nav from failing if backoffPoint.x > game.game_map.width - 1: backoffPoint.x = game.game_map.width - 1 if backoffPoint.x < 0: backoffPoint.x = 0 if backoffPoint.y > game.game_map.height - 1: backoffPoint.y = game.game_map.height - 1 if backoffPoint.y < 0: backoffPoint.y = 0 if DEBUG & (DEBUG_NAV): logging.info( "Nav.get_backoff_point() - ship {} has backoffPoint {}".format( ship.id, backoffPoint)) return backoffPoint
def get_backoff_point(game, ship, destination): destinationMoves = game.game_map.get_unsafe_moves(ship.position, destination) if len(destinationMoves) == 0: return ship.position choice = random.choice(destinationMoves) backoffDirection = Direction.invert(choice) mult = random.randint(1, 8) backoffPoint = ship.position + Position(backoffDirection[0] * mult, backoffDirection[1] * mult) # if the backup point wrap, truncate it to the edge to prevent simple nav from failing if backoffPoint.x > game.game_map.width - 1: backoffPoint.x = game.game_map.width - 1 if backoffPoint.x < 0: backoffPoint.x = 0 if backoffPoint.y > game.game_map.height - 1: backoffPoint.y = game.game_map.height - 1 if backoffPoint.y < 0: backoffPoint.y = 0 logging.info("Ship - Ship {} backoffPoint {}".format( ship.id, backoffPoint)) return backoffPoint
def check_cycle(self): if len(self) == 4: if self[0] == self[2] and self[1] == self[3] and Direction.invert( self[0]) == self[1]: return True if self[0] == self[1] == self[2] == self[3] == Direction.Still: return True return False
def navigateShip(): if safeMoveCheck(): command_queue.append( ship.move(game_map.naive_navigate(ship, ship_target[ship.id]))) else: command_queue.append( ship.move( Direction.invert( game_map.naive_navigate(ship, ship_target[ship.id]))))
def navigateShip(): if game_map[ship.position].halite_amount * .1 <= ship.halite_amount: if safeMoveCheck(): command_queue.append( ship.move(game_map.naive_navigate(ship, ship_target[ship.id]))) else: command_queue.append( ship.move( Direction.invert( game_map.naive_navigate(ship, ship_target[ship.id]))))
def get_jiggle_dirs(moves): all = {Direction.North, Direction.South, Direction.East, Direction.West} if len(moves) == 0: return set() elif len(moves) == 1: return all - {moves[0], Direction.invert(moves[0])} else: return all - set(moves)
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 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
def get_unsafe_moves(game_map, source, destination): """ Return the Direction(s) to move closer to the target point, or empty if the points are the same. This move mechanic does not account for collisions. The multiple directions are if both directional movements are viable. :param source: The starting position :param destination: The destination towards which you wish to move your object. :return: A list of valid (closest) Directions towards your target. """ possible_moves = [] #distance = abs(destination - source) distance = Position(abs(destination.x - source.x), abs(destination.y - source.y)) y_cardinality, x_cardinality = _get_target_direction(source, destination) if distance.x != 0: possible_moves.append(x_cardinality if distance.x < ( game_map.width / 2) else Direction.invert(x_cardinality)) if distance.y != 0: possible_moves.append(y_cardinality if distance.y < ( game_map.height / 2) else Direction.invert(y_cardinality)) return possible_moves
def get_move_d(ship, game_map, safe_map): r = 1 max = 0 pos = ship.position all_pos = get_surrounding_cardinals(pos) max_dir = Direction.Still for p in all_pos: distance = Position(abs(p.x - pos.x), abs(p.y - pos.y)) y_cardinality, x_cardinality = _get_target_direction(pos, p) p = game_map.normalize(p) if safe_map[p.y][p.x] < 1 and game_map[p].halite_amount >= max: max = game_map[p].halite_amount if distance.x != 0: max_dir = (x_cardinality if distance.x < (game_map.width / 2) else Direction.invert(x_cardinality)) if distance.y != 0: max_dir = (y_cardinality if distance.y < (game_map.height / 2) else Direction.invert(y_cardinality)) #return max_dir return max_dir
def get_move_max(ship, game_map, safe_map, other_ships): r = 1 max = 0.25 * game_map[ship.position].halite_amount pos = ship.position all_pos = get_surrounding_cardinals(pos) max_dir = None pct = 0.35 if game_map.width > 40: pct = 0.4 if ship.halite_amount < 0.1 * game_map[ship.position].halite_amount: return max_dir for p in all_pos: distance = Position(abs(p.x - pos.x), abs(p.y - pos.y)) y_cardinality, x_cardinality = _get_target_direction(pos, p) p = game_map.normalize(p) if game_map[p].halite_amount < 50: continue if is_inspired(p, other_ships): new_amt = 0.5 * game_map[p].halite_amount - pct * game_map[ ship.position].halite_amount else: new_amt = 0.25 * game_map[p].halite_amount - pct * game_map[ ship.position].halite_amount if safe_map[p.y][p.x] != 2 and (new_amt) > max: #max_pos = p max = new_amt if distance.x != 0: max_dir = (x_cardinality if distance.x < (game_map.width / 2) else Direction.invert(x_cardinality)) if distance.y != 0: max_dir = (y_cardinality if distance.y < (game_map.height / 2) else Direction.invert(y_cardinality)) #return max_dir return max_dir
def choose_destination(ship): ''' takes a ship and returns a destination ''' destination = None moving_to_old_destination = False if len(promising_cells) != 0: min_value = 999 for cell in promising_cells: distance = game_map.calculate_distance(ship.position, cell) + 1 halite_amount = game_map[cell].halite_amount value = distance * distance / (halite_amount + 1) if value < min_value: destination = cell min_value = value if ship.id in ship_destinations: old_destination = ship_destinations[ship.id] distance = game_map.calculate_distance(ship.position, old_destination) + 1 halite_amount = game_map[old_destination].halite_amount value = distance * distance / (halite_amount + 1) if value < min_value: destination = old_destination min_value = value moving_to_old_destination = True if moving_to_old_destination == False: promising_cells.remove(destination) return destination # if promising_cells is empty elif len(promising_cells) == 0: distance = game_map.calculate_distance(ship.position, me.shipyard.position) if distance < 3: move = Direction.invert( game_map.naive_navigate(ship, me.shipyard.position)) if move == Direction.Still: move = random.choice(direction_order[:4]) else: #logging.info('ENTERED HERE') shipyard_direction = game_map.naive_navigate( ship, me.shipyard.position) random.shuffle(direction_order) for direction in direction_order: if direction not in [shipyard_direction, Direction.Still]: move = direction destination = ship.position + Position(*move) destination = game_map.normalize(destination) return destination
def get_backoff_point(game, ship, destination): """ Get a nav position in the opposite direction of travel a random number of cells away Currently the backoff distance is a function of ship count. This function isn't currently used :param game :param ship :return Return a position n cells away with an inverse direction. """ destinationMoves = game.game_map.get_unsafe_moves(ship.position, destination) if len(destinationMoves) == 0: return ship.position choice = random.choice(destinationMoves) backoffDirection = Direction.invert(choice) # when there's a collion, we backoff between 1 and nShips/2 cells mult = random.randint(1, max(1, round(len(game.me.get_ships()) / 2))) backoffPoint = ship.position + Position(backoffDirection[0] * mult, backoffDirection[1] * mult) # if the backup point wrap, truncate it to the edge to prevent simple nav from failing if backoffPoint.x > game.game_map.width - 1: backoffPoint.x = game.game_map.width - 1 if backoffPoint.x < 0: backoffPoint.x = 0 if backoffPoint.y > game.game_map.height - 1: backoffPoint.y = game.game_map.height - 1 if backoffPoint.y < 0: backoffPoint.y = 0 if DEBUG & (DEBUG_NAV): logging.info("Nav - Ship {} has backoffPoint {}".format( ship.id, backoffPoint)) return backoffPoint
def getBackoffPoint(game, ship, destination): destinationMoves = game.game_map.get_unsafe_moves(ship.position, destination) if len(destinationMoves) == 0: return ship.position choice = random.choice(destinationMoves) backoffDirection = Direction.invert(choice) mult = random.randint(1, 8) backoffPoint = ship.position + Position(backoffDirection[0] * mult, backoffDirection[1] * mult) logging.info("Ship - Ship {} backoffPoint {}".format( ship.id, backoffPoint)) return backoffPoint
def move_to_dropoff(player, ship, game_map): #TODO: probably shouldn't be returning to base anymore if cargo hold is empty if ship.halite_amount < game_map[ship.position].halite_amount/10: direction = Direction.Still # Add the planned movement to the list command_queue.append(ship.stay_still())#move( direction )) next_moves[ship.id] = ship.position.directional_offset(direction) return direction # TODO: incorporate dropoffs, not just shipyard # Derived from naive_navigate() moves = game_map.get_unsafe_moves(ship.position, player.shipyard.position) # Randomize the moves to evenly distribute the ships on the map random.shuffle(moves) for direction in moves: target_pos = ship.position.directional_offset(direction) # Crash into shipyard if near end of game # Go to tile if enemy is there # Go to tile if not occupied or going to be occupied if (type(current_game) is Endgame and game_map.calculate_distance(ship.position, player.shipyard.position) == 1 ) or (for_real_occupied(target_pos, player, game_map) and not player.has_ship(game_map[target_pos].ship.id) and target_pos == player.shipyard.position ) or (not for_real_occupied(target_pos, player, game_map) and (next_moves.values() is None or not target_pos in next_moves.values())): command_queue.append(ship.move(direction)) # Add the planned movement to the list next_moves[ship.id] = ship.position.directional_offset(direction) return direction # Swap ships if possible, and if they are both friendlies. elif for_real_occupied(target_pos, player, game_map) and player.has_ship(game_map[target_pos].ship.id): other_ship = game_map[target_pos].ship if other_ship.halite_amount < ship.halite_amount and other_ship.halite_amount >= game_map[target_pos].halite_amount/10 and ship.halite_amount >= game_map[ship.position].halite_amount/10 and (next_moves.keys() is None or not other_ship.id in next_moves.keys()): opposite_direction = Direction.invert(direction) # move the other ship and keep track of it in the lists command_queue.append(other_ship.move( opposite_direction )) next_moves[other_ship.id] = ship.position command_queue.append(ship.move(direction)) # Add the planned movement to the list next_moves[ship.id] = ship.position.directional_offset(direction) return direction command_queue.append(ship.stay_still()) next_moves[ship.id] = ship.position return Direction.Still
# if can't move closer to shipyard, swap with a blocking ship if possible if game_map[blocking_ship.position] != game_map[target_pos] or \ blocking_ship.halite_amount < game_map[blocking_ship.position].halite_amount * 0.1: continue state = ship_states[ blocking_ship. id] if blocking_ship.id in ship_states else "collecting" flag = commands_dict[blocking_ship.id][ 1] if blocking_ship.id in commands_dict else False if state != "depositing" and flag == False: directional_choice = direction commands_dict[blocking_ship.id] = ( blocking_ship.move( Direction.invert(directional_choice)), True) break commands_dict[ship.id] = (ship.move(directional_choice), False) # Move towards the most halite if the ship is in collecting phase if ship_states[ship.id] == "collecting": hlt_left = game_map[ship.position].halite_amount if not halite_dict or ship.halite_amount < hlt_left * 0.1 or hlt_left > 80: directional_choice = Direction.Still else: dir_max = max(halite_dict, key=lambda v: halite_dict[v]) directional_choice = Direction.Still if hlt_left > halite_dict[ dir_max] // 2 else dir_max
def safeMoveCheck(ship): for x in range(-5 , 5, 1): for y in range(-5 , 5, 1): if game_map[Position(x, y)].is_occupied: if game_map.calculate_distance(ship.position, Position(x, y)) <= 2.0: command_queue.append(ship.move(Direction.invert(game_map.naive_navigate(ship, Position(x, y)))))
# Moving all depositors back to base position_options = ship.position.get_surrounding_cardinals() + [ ship.position ] position_dict = {} for n, direction in enumerate(direction_order): position_dict[direction] = position_options[n] if ship_states[ship.id] == "depositing": moves = game_map.get_unsafe_moves(ship.position, me.shipyard.position) moves.append(Direction.Still) moves.append(Direction.invert(moves[0])) moves.append(Direction.invert(moves[1])) for potential_move in moves: position = position_dict[potential_move] if game_map[position].is_safe == True: move = potential_move break position = position_dict[move] ship.set_current_move(move) ship.set_moved(True) game_map[position].mark_unsafe(ship) command_queue.append(ship.move(move))
def getBack(ship, drop): possPos = [] returning = 1 mustGetBack = False same = False for dir in game_map.get_unsafe_moves(ship.position, drop): possPos.append(ship.position.directional_offset(dir)) if ship.position.x == drop.x and ship.position.y == drop.y: possPos.append(ship.position) same = True if ship.id not in shipsToReturn: returning = -1 if returning == 1 and remainingTurns - game_map.calculate_distance( ship.position, locateClosestDropoff(ship)) <= 10: mustGetBack = True min = possPos[0] last = shipsbeen[ship.id] # Min for returning, make sure that it doesn't go into the enemy territory if possible # Max not returning, make sure that it doesn't go into the enemy territory if possible for pos in possPos: if (returning == 1 and game_map[pos].halite_amount < game_map[min].halite_amount and pos not in nogozone and last != pos) or (min in nogozone and pos not in nogozone) or (min == last): min = pos elif (returning == -1 and game_map[pos].halite_amount > game_map[min].halite_amount and pos not in nogozone and last != pos) or (min in nogozone and pos not in nogozone) or (min == last): min = pos moves = game_map.get_unsafe_moves(ship.position, min) min = game_map.normalize(min) if not same: # Move if my ship isnt in the way if nextmap[min.x][min.y] == -1 or (nextmap[min.x][min.y] == -2 and min == drop): command_queue.append(ship.move(Direction.convert(moves[0]))) shipsOrdered.append(ship.id) nextmap[min.x][min.y] = ship.id nextmap[ship.position.x][ship.position.y] = -1 shipsbeen[ship.id] = Position(-1, -1) elif nextmap[min.x][min.y] == -2: badpos = list( map( lambda x: game_map.normalize( ship.position.directional_offset(Direction.invert(x))), game_map.get_unsafe_moves(ship.position, drop))) if returning == 1: max = 22000 maxpos = Position(-1, -1) else: max = -5 maxpos = Position(-1, -1) for pos in ship.position.get_surrounding_cardinals(): temp = game_map.normalize(pos) if temp not in badpos and nextmap[temp.x][temp.y] == -1: if returning == 1 and game_map[ temp].halite_amount < max and temp != last: max = game_map[temp].halite_amount maxpos = temp elif returning == -1 and game_map[ temp].halite_amount > max and temp != last: max = game_map[temp].halite_amount maxpos = temp if (returning == 1 and max < 22000) or (returning == -1 and max > -5): command_queue.append( ship.move( Direction.convert( game_map.get_unsafe_moves(ship.position, maxpos)[0]))) shipsOrdered.append(ship.id) nextmap[ship.position.x][ship.position.y] = -1 nextmap[maxpos.x][maxpos.y] = ship.id shipsbeen[ship.id] = ship.position else: command_queue.append(ship.stay_still()) shipsOrdered.append(ship.id) shipsToStay.append(ship.id) shipsbeen[ship.id] = Position(-1, -1) elif mustGetBack and (min == me.shipyard.position or min in list( map(lambda x: x.position, me.get_dropoffs()))): command_queue.append(ship.move(Direction.convert(moves[0]))) shipsOrdered.append(ship.id) nextmap[min.x][min.y] = ship.id nextmap[ship.position.x][ship.position.y] = -1 shipsbeen[ship.id] = Position(-1, -1) # When you don't want to swap since it would make the other ship further from goal elif ship.id not in shipsToReturn and nextmap[min.x][ min.y] >= 0 and game_map.calculate_distance( ship.position, shiptargets[nextmap[min.x][ min.y]]) > game_map.calculate_distance( min, shiptargets[nextmap[min.x][min.y]]): if game_map[ship.position].halite_amount < halitethreshold: #something I put in for testing purposes, get rid of it if it's bad # Don't just sit there if there's someone ahead and the cell is almost empty, move to nearest highest halite location max = game_map[ship.position].halite_amount maxpos = ship.position for pos in ship.position.get_surrounding_cardinals(): pos = game_map.normalize(pos) if nextmap[pos.x][ pos.y] == -1 and game_map[pos].halite_amount > max: max = game_map[pos].halite_amount maxpos = pos if maxpos != ship.position and (max >= halitethreshold or ship.position == me.shipyard.position): command_queue.append( ship.move( game_map.get_unsafe_moves(ship.position, maxpos)[0])) shipsOrdered.append(ship.id) nextmap[maxpos.x][maxpos.y] = ship.id nextmap[ship.position.x][ship.position.y] = -1 elif ship.position != me.shipyard.position: command_queue.append(ship.stay_still()) shipsOrdered.append(ship.id) shipsToStay.append(ship.id) shipsbeen[ship.id] = Position(-1, -1) # Swap positions of ships if first one is higher in priority elif nextmap[min.x][min.y] >= 0 and nextmap[min.x][ min.y] not in shipsToStay and nextmap[min.x][ min.y] not in shipsToReturn and nextmap[min.x][ min.y] not in shipsOrdered: command_queue.append(ship.move(Direction.convert(moves[0]))) command_queue.append(game.game_map[min].ship.move( Direction.invert(moves[0]))) shipsOrdered.append(ship.id) shipsOrdered.append(game.game_map[min].ship.id) nextmap[ship.position.x][ ship.position.y] = game.game_map[min].ship.id nextmap[min.x][min.y] = ship.id shipsbeen[ship.id] = Position(-1, -1) else: # if the destination is reached and it has less than 10 halite, go to the nearest highest halite square if game_map[drop].halite_amount < halitethreshold and ( drop.x, drop.y) not in forecast: max = game_map[drop].halite_amount maxpos = ship.position for pos in ship.position.get_surrounding_cardinals(): pos = game_map.normalize(pos) if nextmap[pos.x][pos.y] == -1 and game_map[ pos].halite_amount > game_map[ ship.position].halite_amount and game_map[ pos].halite_amount > max: max = game_map[pos].halite_amount maxpos = pos if max > game_map[drop].halite_amount and max >= halitethreshold: command_queue.append( ship.move( game_map.get_unsafe_moves(ship.position, maxpos)[0])) shipsOrdered.append(ship.id) nextmap[maxpos.x][maxpos.y] = ship.id nextmap[ship.position.x][ship.position.y] = -1 else: command_queue.append(ship.stay_still()) shipsOrdered.append(ship.id) shipsToStay.append(ship.id) else: command_queue.append(ship.stay_still()) shipsOrdered.append(ship.id) shipsToStay.append(ship.id) shipsbeen[ship.id] = Position(-1, -1)
if ship.halite_amount == 0 and ship.id in ships_return: ships_return.remove(ship.id) # Master branch of what the ship should do # Return to shipyard without collisions if ship.id in ships_return: next_step = game_map.get_unsafe_moves(ship.position, me.shipyard.position) next_step = next_step[0] next_step_pos = ship.position.directional_offset(next_step) if game_map[next_step_pos].is_occupied is True: #remove occupied forward position, and back position poss_dir = [(0, -1), (0, 1), (1, 0), (-1, 0)] poss_dir.remove(next_step) poss_dir.remove(Direction.invert(next_step)) next_step = random.choice(poss_dir) #pick a direction and check if it's occupied next_step_pos = ship.position.directional_offset(next_step) if game_map[next_step_pos].is_occupied is True: poss_dir.remove(next_step) if game_map[ship.position.directional_offset(poss_dir[0])].is_occupied is True: #if it's occupied, all squares are occupied, hit the lowest ship near_ships = {'n': game_map[ship.position.directional_offset((0, -1))].halite_amount, 'e': game_map[ship.position.directional_offset((0, 1))].halite_amount, 's': game_map[ship.position.directional_offset((1, 0))].halite_amount, 'w': game_map[ship.position.directional_offset((-1, 0))].halite_amount } low_ship = min(near_ships.items(), key=operator.itemgetter(1))[0] command_queue.append( ship.move(