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 resolve_nav_move(game, collision): """ Resolve a nav move. Note: The current position of the ship is 'given up'/marked safe for others in get_move(), there is no guarantee the ship can remain in it's current position - be sure to check is_occupied for the current cell if returning 'o' :param game :param collision Collision tuple: (0:ship1 1:ship2 2:move 3:dest1 4:res_func) :returns Returns move based on a number of special cases, if none of these exists, returns a random move excluding the original collision move. Returns 'o' if no move exists. """ ship1 = collision[0] ship2 = collision[1] move = collision[2] position = collision[3] collision_cell = game.game_map[position] ship_cell = game.game_map[ship1] if DEBUG & (DEBUG_NAV): logging.info("Nav - ship {} - Resolving nav move".format(ship1.id)) if DEBUG & (DEBUG_NAV): logging.info( "Nav - Ship {} collided with ship {} at {} while moving {}".format( ship1.id, ship2.id, position, move)) #base = get_base_positions(game, ship1.position) # don't let enemy ships on a dropoff/shipyard block arrivals or spawns. Halite from both ships will be deposited if collision_cell.structure_type is Shipyard and collision_cell.ship.owner != game.me.id: if DEBUG & (DEBUG_NAV): logging.info( "Nav - Ship {} collided with enemy ship {} at shipyard. Crashing" .format(ship1.id, ship2.id)) collision_cell.mark_unsafe(ship1) ship1.path.pop() new_move = move elif ship2.position == collision_cell.position and ship2.owner != game.me.id and collision_cell.position in get_base_surrounding_cardinals( game, ship1.position): game.base_clear_request.insert(0, { "position": collision_cell.position, "ship": ship2 }) # , "base": base if DEBUG & (DEBUG_NAV): logging.info( "Nav - Ship {} sent a dropoff clear request for {}. Blocked by {}" .format(ship1.id, collision_cell.position, ship2.id)) if game.game_map[ship1].is_occupied: new_move = None # None == unwind else: ship_cell.mark_unsafe(ship1) new_move = "o" # when arriving at a droppoff, wait from entry rather than making a move # this probably will not work as well without entry/exit lanes elif ship1.path and ship1.path[ 0] == game.me.shipyard.position and game.game_map.calculate_distance( ship1.position, game.me.shipyard.position) <= 2: if game.game_map[ship1].is_occupied: new_move = None # None == unwind else: ship_cell.mark_unsafe(ship1) new_move = "o" # when departing ... elif ship1.position == game.me.shipyard.position: # wait zero for enemy if collision_cell.ship.owner != game.me.id: collision_cell.mark_unsafe(ship1) ship1.path.pop() new_move = move # wait to leave for friendly, ... but make sure our old cell is available. prob should never happen # since we don't spawn with a ship already in shipyard, but rapid departure could cause this elif game.game_map[ship1].is_occupied: new_move = None # None == unwind else: ship_cell.mark_unsafe(ship1) new_move = 'o' else: if DEBUG & (DEBUG_NAV): logging.info( "Nav - ship {} collision at {} with ship {}. Resolving to random move {}" .format(ship1.id, position, ship2.id, move)) new_move = resolve_random_move(game, collision, { "moves": [Direction.convert(m) for m in Direction.laterals(move)] }) # popping the path point will allow nav around the blocking ship, buy this can # cause conjestion/screw up arrival/departure lanes if close to the dropoff if game.game_map.calculate_distance(ship2.position, game.me.shipyard.position) > 4: if len(ship1.path) > 1: ship1.path.pop() # # if we were not able to resolve above, unwind ... # if new_move is None: cnt = unwind(game, ship1) if DEBUG & (DEBUG_NAV): logging.info( "Nav - ship {} - Resolved by unwinding {} ships".format( ship1.id, cnt)) #ship_cell.mark_unsafe(ship1) this is handled by unwind new_move = 'o' if DEBUG & (DEBUG_NAV): logging.info( "Nav - ship {} - Successfully resolved nav move collision. Move: {}" .format(ship1.id, new_move)) return new_move
def get_nav_move(game, ship, waypoint_algorithm="astar", args={"move_cost": "turns"}): game_map = game.game_map if DEBUG & (DEBUG_NAV): logging.info("NAV - ship {} getting nav move for path {}".format( ship.id, ship.path)) if not check_fuel_cost(game, ship): return 'o' if len(ship.path) == 0: if DEBUG & (DEBUG_NAV): logging.info("NAV - ship {} empty path".format(ship.id)) return 'o' next_position = ship.path[len(ship.path) - 1] # check to see if we have a waypoint, not a continous path if game_map.calculate_distance(ship.position, next_position) > 1: normalized_next_position = game_map.normalize(next_position) if DEBUG & (DEBUG_NAV): logging.info( "NAV - ship {} found waypoint {}, calulating complete path". format(ship.id, next_position)) # calc a continous path path, cost = game_map.navigate(ship.position, normalized_next_position, waypoint_algorithm, args) if path is None: if DEBUG & (DEBUG_NAV): logging.info("NAV - ship {} Nav failed, can't reach {}".format( ship.id, normalized_next_position)) return 'o' else: if DEBUG & (DEBUG_NAV): logging.info( "NAV - ship {} path to waypoint found with a cost of {} ({} turns)" .format(ship.id, round(cost), len(path))) ship.path.pop() ship.path = ship.path + path new_position = ship.path[len(ship.path) - 1] if DEBUG & (DEBUG_NAV): logging.info("NAV - ship {} new_position: {}".format( ship.id, new_position)) normalized_new_position = game_map.normalize(new_position) if DEBUG & (DEBUG_NAV): logging.info("NAV - ship {} normalized_new_position: {}".format( ship.id, normalized_new_position)) # why? if normalized_new_position == ship.position: ship.path.pop() return 'o' cell = game_map[normalized_new_position] # use get_unsafe_moves() to get a normalized directional offset. We should always get one soln. offset = game_map.get_unsafe_moves(ship.position, normalized_new_position)[0] move = Direction.convert(offset) if DEBUG & (DEBUG_NAV): logging.info("NAV - Ship {} has potential move: {}".format( ship.id, move)) # once we have the move, handle collisions if cell.is_occupied: if DEBUG & (DEBUG_NAV): logging.info( "Nav - Ship {} has a collision at {} while moving {}".format( ship.id, normalized_new_position, move)) # don't let enemy ships block the dropoff if cell.structure_type is Shipyard and cell.ship.owner != game.me.id: cell.mark_unsafe(ship) ship.path.pop() # when arriving at a droppoff, wait from entry rather than making a random # this probably will not work as well if not using entry/exit lanes elif normalized_new_position == game.me.shipyard.position: move = "o" # when departing a shipyard, try not to head the wrong direction elif ship.position == game.me.shipyard.position: alternate_moves = Direction.laterals(move) move = "o" for alternate_move_offset in alternate_moves: alternate_pos = ship.position.directional_offset( alternate_move_offset) alternate_cell = game_map[alternate_pos] if not alternate_cell.is_occupied: alternate_cell.mark_unsafe(ship) move = Direction.convert(alternate_move_offset) else: move = get_random_move(game, ship) if move == "o": if DEBUG & (DEBUG_NAV): logging.info( "NAV - ship {} collision at {} with ship {}, using {}". format(ship.id, normalized_new_position, cell.ship.id, move)) else: cell.mark_unsafe(ship) ship.path.pop() return move
def get_density_move(game, ship): move = "o" if DEBUG & (DEBUG_NAV): logging.info("Nav - ship {} is getting a density based move".format( ship.id)) if not check_fuel_cost(game, ship): return move moves = [] for quadrant in get_surrounding_cell_blocks(game, ship, 3, 3): directional_offset = quadrant[0] block = quadrant[1] if block.get_max() > constants.MAX_HALITE * MINING_THRESHOLD_MULT: moves.append((directional_offset, block, block.get_mean())) sorted_blocks = sorted(moves, key=lambda item: item[2], reverse=True) if len(sorted_blocks) == 0: return get_random_move( game, ship ) # FIX ME FIX ME FIX ME FIX ME FIX ME FIX ME would be better to try a large search radius ??? best_bloc_data = sorted_blocks[0] max_cell = best_bloc_data[1].get_max() bc = best_bloc_data[1].get_cells() for best_cell in bc: if best_cell.halite_amount == max_cell: break move_offset = best_bloc_data[0] if DEBUG & (DEBUG_NAV): logging.info("Nav - Ship {} moveOffset: {}".format( ship.id, move_offset)) new_position = game.game_map.normalize( ship.position.directional_offset(move_offset)) if DEBUG & (DEBUG_NAV): logging.info("Nav - Ship {} new_position: {}".format( ship.id, new_position)) normalized_position = game.game_map.normalize(new_position) if DEBUG & (DEBUG_NAV): logging.info("Nav - Ship {} normalized_position: {}".format( ship.id, normalized_position)) cell = game.game_map[normalized_position] if not cell.is_occupied: move = Direction.convert(move_offset) cell.mark_unsafe(ship) #game.game_map[ship.position].mark_safe() # if we were not able to find a usable dense cell, try to find a random one if move == "o": if DEBUG & (DEBUG_NAV): logging.info( "Nav - Ship {} Collision, trying to find a random move".format( ship.id)) lateral_offsets = Direction.laterals(move_offset) lateral_moves = list( map(lambda direction_offset: Direction.convert(direction_offset), lateral_offsets)) move = get_random_move(game, ship, lateral_moves) if move == "o": if DEBUG & (DEBUG_NAV): logging.info( "Nav - Ship {} Collision, unable to find a move".format( ship.id)) move_plus_one = Position( best_cell.position.x, best_cell.position.y) # go one more move in the same direction if DEBUG & (DEBUG_NAV): logging.info("Nav - Ship {} has a move_plus_one of {}".format( ship.id, move_plus_one)) ship.path.append(move_plus_one) return move