Example #1
0
    def get_observation_state(self, board, pos, enemies, bomb_map):
        """
        Need just the board layout to decide everything
        board -> np.array
        pos   -> tuple
        enemies -> list
        """
        def convert_bombs(bomb_map):
            '''Flatten outs the bomb array'''
            ret = []
            locations = np.where(bomb_map > 0)
            for r, c in zip(locations[0], locations[1]):
                ret.append(crazy_util.dotdict({
                    'position': (r, c),
                    'blast_strength': int(bomb_map[(r, c)])
                }))
            return ret

        bombs = convert_bombs(np.array(bomb_map))

        has_bomb = False
        has_enemy = False
        has_wood = False
        los_bomb = False

        x, y = pos
        dirX = [-1,0,1,0]
        dirY = [0,1,0,-1]
        for k1 in dirX:
            for k2 in dirY:
                newX = x+k1
                newY = y+k2
                # print((newX, newY), board.shape)
                if newX < board.shape[0] and newY < board.shape[1] and newX >=0 and  newY >= 0:
                    if utility.position_is_bomb(bombs, (newX, newY)):
                        has_bomb = True
                    if utility.position_is_wood(board, (newX, newY)):
                        has_wood = True
                    if utility.position_is_enemy(board, pos, enemies):
                        has_enemy = True

        for k1 in range(0, board.shape[0]):
            if utility.position_is_bomb(bombs, (k1, y)):
                los_bomb = True
            elif utility.position_is_bomb(bombs, (x, k1)):
                los_bomb = True

        if utility.position_is_bomb(bombs, (x,y)):
            has_bomb = True

        if has_bomb:
            return 0
        elif los_bomb:
            return 4
        elif has_enemy:
            return 1
        elif has_wood:
            return 2
        else:
            return 3
Example #2
0
    def get_observation_state(self, board, pos, enemies, bomb_map, bomb_life,
                              ammo):
        """
        Need just the board layout to decide everything
        board -> np.array
        pos   -> tuple
        enemies -> list
        """

        bombs = self.convert_bombs(np.array(bomb_map), np.array(bomb_life))

        has_bomb = False
        has_enemy = False
        has_wood = False
        los_bomb = False
        has_ammo = False

        if ammo > 0:
            has_ammo = True

        x, y = pos
        dirX = [-1, 1, 0, 0]
        dirY = [0, 0, -1, 1]
        for k in range(0, len(dirX)):
            newX = x + dirX[k]
            newY = y + dirY[k]
            # print((newX, newY), board.shape)
            if newX < board.shape[0] and newY < board.shape[
                    1] and newX >= 0 and newY >= 0:
                if utility.position_is_bomb(bombs, (newX, newY)):
                    has_bomb = True
                if utility.position_is_wood(board, (newX, newY)):
                    has_wood = True
                if utility.position_is_enemy(board, pos, enemies):
                    has_enemy = True

                los_bomb = self.check_bomb((newX, newY), bombs)

        if utility.position_is_bomb(bombs, (x, y)):
            has_bomb = True

        state = 3

        if has_bomb:
            state = 0
        elif los_bomb:
            state = 4
        elif has_enemy:
            state = 1
        elif has_wood:
            state = 2
        else:
            state = 3

        if has_ammo:
            state = 2 * state

        return state
Example #3
0
def position_is_passable(board, position, enemies):
    '''Determins if a possible can be passed'''
    return all([
        any([
            utility.position_is_agent(board, position),
            utility.position_is_powerup(board, position),
            utility.position_is_passage(board, position),
            utility.position_is_fog(board, position),
        ]), not utility.position_is_enemy(board, position, enemies)
    ])
def _opponent_test(board, candidate_position, enemies):
    assert (position_is_passable(board, candidate_position))
    #make sure this passage is not next to the opponent, otherwise the opponent may come to this position
    for direction in [
            constants.Action.Left, constants.Action.Up, constants.Action.Right,
            constants.Action.Down
    ]:
        position = utility.get_next_position(candidate_position, direction)
        if not utility.position_on_board(board, position):
            continue
        if utility.position_is_enemy(board, position, enemies):
            return False
    return True
Example #5
0
    def get_observation_state(self, board, pos, enemies, bomb_map, bomb_life,
                              ammo, can_kick):
        """
        Need just the board layout to decide everything
        board -> np.array
        pos   -> tuple
        enemies -> list
        """

        bombs = self.convert_bombs(np.array(bomb_map), np.array(bomb_life))

        has_bomb = False
        has_enemy = False
        # is_surrounded = False
        is_surrounded = False
        los_bomb = False
        has_ammo = False
        # can kick is also a valid state

        if ammo > 0:
            has_ammo = True

        x, y = pos
        dirX = [-1, 1, 0, 0]
        dirY = [0, 0, -1, 1]
        blocks = 0
        for k in range(0, len(dirX)):
            newX = x + dirX[k]
            newY = y + dirY[k]
            # print((newX, newY), board.shape)
            if newX < board.shape[0] and newY < board.shape[
                    1] and newX >= 0 and newY >= 0:
                if utility.position_is_bomb(bombs, (newX, newY)):
                    has_bomb = True
                if utility.position_is_rigid(board, (newX, newY)):
                    # is_surrounded = True
                    blocks += 1
                if utility.position_is_enemy(board, pos, enemies):
                    has_enemy = True

                los_bomb = self.check_bomb((newX, newY), bombs) or los_bomb

        if utility.position_is_bomb(bombs, (x, y)) or self.check_bomb(
            (x, y), bombs):
            has_bomb = True

        if blocks > 2:
            is_surrounded = True

        return State(has_bomb, has_enemy, is_surrounded, los_bomb, has_ammo,
                     can_kick)
Example #6
0
    def get_observation_state(self, board, pos, enemies, bomb_map, ammo):
        """
        Need just the board layout to decide everything
        board -> np.array
        pos   -> tuple
        enemies -> list
        """

        bombs = self.convert_bombs(np.array(bomb_map))

        has_bomb = False
        has_enemy = False
        has_wood = False
        los_bomb = False
        has_ammo = False

        if ammo > 0:
            has_ammo = True

        x, y = pos
        dirX = [-1, 1, 0, 0]
        dirY = [0, 0, -1, 1]
        for k in range(0, len(dirX)):
            newX = x + dirX[k]
            newY = y + dirY[k]
            # print((newX, newY), board.shape)
            if newX < board.shape[0] and newY < board.shape[
                    1] and newX >= 0 and newY >= 0:
                if utility.position_is_bomb(bombs, (newX, newY)):
                    has_bomb = True
                if utility.position_is_wood(board, (newX, newY)):
                    has_wood = True
                if utility.position_is_enemy(board, pos, enemies):
                    has_enemy = True
                for bomb in bombs:
                    if ((abs(newX - bomb['position'][0]) <=
                         bomb['blast_strength']
                         and newY == bomb['position'][1])
                            or (abs(newY - bomb['position'][1]) <=
                                bomb['blast_strength']
                                and newX == bomb['position'][0])):
                        los_bomb = True

        if utility.position_is_bomb(bombs, (x, y)):
            has_bomb = True

        return State(has_bomb, has_enemy, has_wood, los_bomb, has_ammo)
Example #7
0
    def get_observation_state(self, obs):
        """
        Need just the board layout to decide everything
        board -> np.array
        pos   -> tuple
        enemies -> list

        Interesting keys: 
           obs['board'],
           obs['position'],
           obs['teammate'],
           obs['enemies'],
           obs['bomb_blast_strength'],
           obs['bomb_life'],
           obs['ammo'],
           obs['can_kick']
        """

        board = obs["board"]

        bombs = self.convert_bombs(np.array(obs["bomb_blast_strength"]), np.array(obs["bomb_life"]))

        d = collections.OrderedDict({
            "bomb_nearby": Proximity.NONE,
            "enemy_nearby": Proximity.NONE,
            "is_surrounded": False,
            "los_bomb": False,
            "ammo": 3 if obs['ammo'] > 3 else obs['ammo'],
            "can_kick": obs['can_kick'],
            "blast_strength": BlastStrength.LOW if obs['blast_strength'] <= 2 else BlastStrength.HIGH ,
            "enemies_alive": len(list(filter(lambda enemy: enemy.value in obs['alive'], obs['enemies']))),
            "nearby_enemy_has_bomb": False,
            "nearby_enemy_can_kick": False,
            "next_to_wood": False
        })


        x, y = obs['position']

        nearby_enemy_id = None

        for del_x in range(-2, 3):
            for del_y in range(-2, 3):
                newX = x + del_x
                newY = y + del_y

                immediate_zone = abs(del_x) <= 1 and abs(del_y) <= 1

                if newX < board.shape[0] and newY < board.shape[1] and newX >= 0 and  newY >= 0:
                    if utility.position_is_bomb(bombs, (newX, newY)):
                        d['bomb_nearby'] = Proximity.IMMEDIATE if immediate_zone else Proximity.CLOSE

                    if immediate_zone and obs["board"][newX, newY] == 2:
                        d["next_to_wood"] = True

                    if utility.position_is_enemy(obs['board'], (newX, newY), obs['enemies']):
                        nearby_enemy_id = obs['board'][newX, newY]
                        d['enemy_nearby'] = Proximity.IMMEDIATE if immediate_zone else Proximity.CLOSE

                    d['los_bomb'] = self.check_bomb((newX, newY), bombs) or d['los_bomb']

        if utility.position_is_bomb(bombs, (x,y)) or self.check_bomb((x,y), bombs): # TODO why two conditions?
            d["bomb_nearby"] = Proximity.IMMEDIATE

        d["is_surrounded"] = ep.is_pos_surrounded(obs["board"], obs["position"], self.agent_value)
        #print(d["is_surrounded"])
        
        if nearby_enemy_id and self.enemy_info:
            #print(self.enemy_info)
            enemy_object = self.enemy_info[nearby_enemy_id - 10] # 10, 11, 12, 13 index, one assumes 
            d["nearby_enemy_has_bomb"] = enemy_object['ammo'] > 0
            d["nearby_enemy_can_kick"] = enemy_object['can_kick'] > 0

        return AliveState(**d)
Example #8
0
    def act(self, obs, action_space, info):

        #
        # Definitions
        #

        board = obs['board']
        my_position = obs["position"]  # tuple([x,y]): my position
        my_kick = obs["can_kick"]  # whether I can kick
        my_enemies = [constants.Item(e) for e in obs['enemies']]
        my_teammate = obs["teammate"]

        # List of the set of survivable time-positions at each time
        # and preceding positions
        survivable, prev, succ, _ \
            = self._search_time_expanded_network(info["list_boards_no_move"],
                                                 my_position)

        # Survivable actions
        is_survivable, survivable_with_bomb \
            = self._get_survivable_actions(survivable,
                                           obs,
                                           info["curr_bombs"],
                                           info["curr_flames"],
                                           enemy_mobility=0)

        survivable_actions = [a for a in is_survivable if is_survivable[a]]

        n_survivable = dict()
        kick_actions = list()
        if my_kick:
            # Positions where we kick a bomb if we move to
            kickable = self._kickable_positions(obs, info["moving_direction"])
            for next_position in kickable:
                # consider what happens if I kick a bomb
                my_action = self._get_direction(my_position, next_position)

                # do not kick into fog
                dx = next_position[0] - my_position[0]
                dy = next_position[1] - my_position[1]
                position = next_position
                is_fog = False
                while self._on_board(position):
                    if utility.position_is_fog(board, position):
                        is_fog = True
                        break
                    position = (position[0] + dx, position[1] + dy)
                if is_fog:
                    continue

                list_boards_with_kick, next_position \
                    = self._board_sequence(obs["board"],
                                           info["curr_bombs"],
                                           info["curr_flames"],
                                           self._search_range,
                                           my_position,
                                           my_action=my_action,
                                           can_kick=True,
                                           enemy_mobility=0)
                #print(list_boards_with_kick)
                survivable_with_kick, prev_kick, succ_kick, _ \
                    = self._search_time_expanded_network(list_boards_with_kick[1:],
                                                         next_position)
                if next_position in survivable_with_kick[0]:
                    survivable_actions.append(my_action)
                    is_survivable[my_action] = True
                    n_survivable[my_action] = [1] + [
                        len(s) for s in survivable_with_kick[1:]
                    ]
                    kick_actions.append(my_action)
        else:
            kickable = set()

        x, y = my_position
        for action in survivable_actions:
            # for each survivable action, check the survivability
            if action == constants.Action.Bomb:
                n_survivable[action] = [
                    len(s) for s in survivable_with_bomb[1:]
                ]
                continue

            if action == constants.Action.Up:
                dx = -1
                dy = 0
            elif action == constants.Action.Down:
                dx = 1
                dy = 0
            elif action == constants.Action.Left:
                dx = 0
                dy = -1
            elif action == constants.Action.Right:
                dx = 0
                dy = 1
            elif action == constants.Action.Stop:
                dx = 0
                dy = 0
            else:
                raise ValueError()
            next_position = (x + dx, y + dy)
            n_survivable[action], _info = self._count_survivable(
                succ, 1, next_position)

        most_survivable_action = None
        if survivable_actions:
            survivable_score = dict()
            for action in n_survivable:
                #survivable_score[action] = sum([-n**(-5) for n in n_survivable[action]])
                survivable_score[action] = sum(
                    [n for n in n_survivable[action]])
                if verbose:
                    print(action, survivable_score[action],
                          n_survivable[action])
            best_survivable_score = max(survivable_score.values())

            random.shuffle(survivable_actions)
            for action in survivable_actions:
                if survivable_score[action] == best_survivable_score:
                    most_survivable_action = action
                    break

        if most_survivable_action is not None:
            print("Most survivable action", most_survivable_action)
            return most_survivable_action.value

        # kick if possible
        if my_kick:
            kickable = self._kickable_positions(obs, info["moving_direction"])
        else:
            kickable = set()
        print("Kickable", my_kick, kickable)
        while kickable:
            next_position = kickable.pop()
            action = self._get_direction(my_position, next_position)
            print("Must kick to survive", action)
            return action.value

        # move towards a teammate if she is blocking
        for action in [
                constants.Action.Right, constants.Action.Left,
                constants.Action.Down, constants.Action.Up
        ]:
            next_position = utility.get_next_position(my_position, action)
            if not self._on_board(next_position):
                continue
            if utility._position_is_item(board, next_position, my_teammate):
                print("Must move to teammate to survive", action)
                return action.value

        # move towards an enemy
        for action in [
                constants.Action.Right, constants.Action.Left,
                constants.Action.Down, constants.Action.Up
        ]:
            next_position = utility.get_next_position(my_position, action)
            if not self._on_board(next_position):
                continue
            if utility.position_is_enemy(board, next_position, my_enemies):
                print("Must move to enemy to survive", action)
                return action.value

        # move towards anywhere besides ridid
        for action in [
                constants.Action.Right, constants.Action.Left,
                constants.Action.Down, constants.Action.Up
        ]:
            next_position = utility.get_next_position(my_position, action)
            if not self._on_board(next_position):
                continue
            if utility.position_is_rigid(board, next_position):
                continue
            if utility.position_is_wood(board, next_position):
                continue
            if utility.position_is_bomb(info["curr_bombs"], next_position):
                continue
            print("Try moving to survive", action)
            return action.value

        action = constants.Action.Stop
        print("Must die", action)
        return action
Example #9
0
    def act(self, obs, action_space, info):

        #
        # Definitions
        #

        self._search_range = 10

        board = obs['board']
        my_position = obs["position"]  # tuple([x,y]): my position
        my_ammo = obs['ammo']  # int: the number of bombs I have
        my_blast_strength = obs['blast_strength']
        my_enemies = [constants.Item(e) for e in obs['enemies']]
        my_teammate = obs["teammate"]
        my_kick = obs["can_kick"]  # whether I can kick

        print("my position", my_position, end="\t")

        #
        # Understand current situation
        #

        # List of the set of survivable time-positions at each time
        # and preceding positions
        survivable_no_move, prev_no_move \
            = self._search_time_expanded_network(info["list_boards_no_move"],
                                                 my_position)

        # Items that can be reached in a survivable manner
        reachable_items_no_move, reached_no_move, next_to_items_no_move \
            = self._find_reachable_items(info["list_boards_no_move"],
                                         my_position,
                                         survivable_no_move)

        # Simulation assuming enemies move

        for enemy_mobility in range(3, -1, -1):
            # List of boards simulated
            list_boards, _ = self._board_sequence(
                board,
                info["curr_bombs"],
                info["curr_flames"],
                self._search_range,
                my_position,
                enemy_mobility=enemy_mobility)

            # List of the set of survivable time-positions at each time
            # and preceding positions
            survivable, prev = self._search_time_expanded_network(
                list_boards, my_position)

            if len(survivable[1]) > 0:
                # Gradually reduce the mobility of enemy, so we have at least one survivable action
                break

        # Items that can be reached in a survivable manner
        reachable_items, reached, next_to_items \
            = self._find_reachable_items(list_boards,
                                         my_position,
                                         survivable)

        # Survivable actions
        is_survivable, survivable_with_bomb \
            = self._get_survivable_actions(survivable,
                                           obs,
                                           info["curr_bombs"],
                                           info["curr_flames"])

        survivable_actions = [a for a in is_survivable if is_survivable[a]]

        # if verbose:
        if True:
            print("survivable actions are", survivable_actions)

        # Positions where we kick a bomb if we move to
        if my_kick:
            kickable = self._kickable_positions(obs, info["moving_direction"])
        else:
            kickable = set()

        print()
        for t in range(0):
            print(list_boards[t])
            print(survivable[t])
            for key in prev[t]:
                print(key, prev[t][key])

        #
        # Choose an action
        #
        """
        # This is not effective in the current form
        if len(survivable_actions) > 1:
            # avoid the position if only one position at the following step
            # the number of positions that can be reached from the next position
            next = defaultdict(set)
            next_count = defaultdict(int)
            for position in survivable[1]:
                next[position] = set([p for p in prev[2] if position in prev[2][p]])
                next_count[position] = len(next[position])
            print("next count", next_count)
            if max(next_count.values()) > 1:
                for position in survivable[1]:
                    if next_count[position] == 1:
                        risky_action = self._get_direction(my_position, position)
                        is_survivable[risky_action] = False
                survivable_actions = [a for a in is_survivable if is_survivable[a]]                
        """

        # Do not stay on a bomb if I can
        if all([
                obs["bomb_life"][my_position] > 0,
                len(survivable_actions) > 1,
                is_survivable[constants.Action.Stop]
        ]):
            is_survivable[constants.Action.Stop] = False
            survivable_actions = [a for a in is_survivable if is_survivable[a]]

        if len(survivable_actions) == 0:

            print("Must die")
            return None

        elif len(survivable_actions) == 1:

            # move to the position if it is the only survivable position
            action = survivable_actions[0]
            print("The only survivable action", action)
            return action.value

        # TODO : shoud check the survivability of all agents in one method

        # Place a bomb if
        # - it does not significantly reduce my survivability
        # - it can reduce the survivability of enemies

        consider_bomb = True
        if survivable_with_bomb is None:
            consider_bomb = False
        elif any([len(s) <= 2 for s in survivable_with_bomb[1:]]):
            # if not sufficiently survivable all the time after bomb, do not bomb
            consider_bomb = False

        if consider_bomb:
            # place bomb if can reach fog/enemy
            if self._can_break(info["list_boards_no_move"][-1], my_position,
                               my_blast_strength,
                               [constants.Item.Fog] + my_enemies):
                print("Bomb to break fog/enemy", constants.Action.Bomb)
                print(info["list_boards_no_move"][-1])
                return constants.Action.Bomb.value

            for enemy in my_enemies:
                # check if the enemy is reachable
                if len(reachable_items_no_move[enemy]) == 0:
                    continue

                # can reach the enemy at enemy_position in enemy_time step
                enemy_time = reachable_items_no_move[enemy][0][0]
                enemy_position = reachable_items_no_move[enemy][0][1:3]

                # check if placing a bomb can reduce the survivability
                # of the enemy
                survivable_before, _ = self._search_time_expanded_network(
                    info["list_boards_no_move"], enemy_position)

                board_with_bomb = deepcopy(obs["board"])
                curr_bombs_with_bomb = deepcopy(info["curr_bombs"])
                # lay a bomb
                board_with_bomb[my_position] = constants.Item.Bomb.value
                bomb = characters.Bomb(
                    characters.Bomber(),  # dummy owner of the bomb
                    my_position,
                    constants.DEFAULT_BOMB_LIFE,
                    my_blast_strength,
                    None)
                curr_bombs_with_bomb.append(bomb)
                list_boards_with_bomb, _ \
                    = self._board_sequence(board_with_bomb,
                                           curr_bombs_with_bomb,
                                           info["curr_flames"],
                                           self._search_range,
                                           my_position,
                                           enemy_mobility=0)
                survivable_after, _ \
                    = self._search_time_expanded_network(list_boards_with_bomb,
                                                         enemy_position)

                good_before = np.array([len(s) for s in survivable_before])
                good_after = np.array([len(s) for s in survivable_after])

                # TODO : what are good criteria?
                if any(good_after < good_before):
                    # place a bomb if it makes sense
                    print("Bomb to kill an enemy", constants.Action.Bomb)
                    print("before", good_before)
                    print("after ", good_after)
                    print([len(s) for s in survivable])
                    print([len(s) for s in survivable_with_bomb])
                    return constants.Action.Bomb.value
                """
                # find direction towards enemy
                positions = set([x[1:3] for x in next_to_items_no_move[enemy]])
                for t in range(enemy_time, 1, -1):
                    _positions = set()
                    for position in positions:
                        _positions = _positions.union(prev_no_move[t][position])
                    positions = _positions.copy()

                if enemy_time <= my_blast_strength:
                    #if True:
                    positions.add(my_position)
                    positions_after_bomb = set(survivable[1]).difference(positions)
                    if positions_after_bomb:
                        print("Bomb to kill an enemy", enemy, constants.Action.Bomb)
                        return constants.Action.Bomb.value
                """

            # if I can kick, consider placing a bomb to kick
            if my_kick and my_position in survivable_with_bomb[3]:
                # consdier a sequence of actions: place bomb -> move (action) -> move back (kick)
                for action in [
                        constants.Action.Up, constants.Action.Down,
                        constants.Action.Left, constants.Action.Right
                ]:
                    if not is_survivable[action]:
                        continue

                    if action == constants.Action.Up:
                        # kick direction is down
                        dx = 1
                        dy = 0
                    elif action == constants.Action.Down:
                        # kick direction is up
                        dx = -1
                        dy = 0
                    elif action == constants.Action.Left:
                        # kick direction is right
                        dx = 0
                        dy = 1
                    elif action == constants.Action.Right:
                        # kick direction is left
                        dx = 0
                        dy = -1
                    else:
                        raise ValueError()

                    _next_position = (my_position[0] + dx, my_position[1] + dy)
                    if not self._on_board(_next_position):
                        continue
                    else:
                        next_position = _next_position

                    # Find where the bomb stops if kicked
                    for t in range(int(obs["bomb_life"][my_position]) - 2):
                        if not utility.position_is_passage(
                                board, next_position):
                            break
                        _next_position = (next_position[0] + dx,
                                          next_position[1] + dy)
                        if not self._on_board(_next_position):
                            break
                        else:
                            next_position = _next_position
                        if utility.position_is_fog(board, next_position):
                            print("Bomb to kick into fog", action)
                            return constants.Action.Bomb.value
                        elif utility.position_is_enemy(list_boards[t + 2],
                                                       next_position,
                                                       my_enemies):
                            print("Bomb to kick towards enemy", action)
                            return constants.Action.Bomb.value
                """
                x0, y0 = my_position
                positions_against = [(2*x0-x, 2*y0-y) for (x, y) in positions]
                positions_after_bomb = set(survivable[1]).intersection(positions_against)

                if positions_after_bomb:
                    print("Bomb to kick", enemy, constants.Action.Bomb)
                    return constants.Action.Bomb.value
                """

        # kick
        if len(kickable) > 0:

            while kickable:
                # then consider what happens if I kick a bomb
                next_position = kickable.pop()

                # do not kick a bomb if it will break enemies
                if info["moving_direction"][next_position] is None:
                    # if it is a static bomb
                    if self._can_break(info["list_boards_no_move"][0],
                                       next_position, my_blast_strength,
                                       my_enemies):
                        continue

                my_action = self._get_direction(my_position, next_position)
                list_boards_with_kick, next_position \
                    = self._board_sequence(obs["board"],
                                           info["curr_bombs"],
                                           info["curr_flames"],
                                           self._search_range,
                                           my_position,
                                           my_action=my_action,
                                           can_kick=True,
                                           enemy_mobility=3)
                survivable_with_kick, prev_kick \
                    = self._search_time_expanded_network(list_boards_with_kick[1:],
                                                         next_position)
                if next_position in survivable_with_kick[0]:
                    print("Kicking", my_action)
                    return my_action.value

        # if on a bomb, consider where to kick in the following step
        if obs["bomb_life"][my_position] > 0:
            # For each survivable move in the next step,
            # check what happens if we kick in the following step.
            # If the bomb is kicked into a fog, plan to kick.
            # If the bomb is kicked toward an enemy, plan to kick.
            # Otherwise, do not plan to kick.
            for action in [
                    constants.Action.Up, constants.Action.Down,
                    constants.Action.Left, constants.Action.Right
            ]:
                if not is_survivable[action]:
                    continue

                if action == constants.Action.Up:
                    # kick direction is down
                    dx = 1
                    dy = 0
                elif action == constants.Action.Down:
                    # kick direction is up
                    dx = -1
                    dy = 0
                elif action == constants.Action.Left:
                    # kick direction is right
                    dx = 0
                    dy = 1
                elif action == constants.Action.Right:
                    # kick direction is left
                    dx = 0
                    dy = -1
                else:
                    raise ValueError()

                _next_position = (my_position[0] + dx, my_position[1] + dy)
                if not self._on_board(_next_position):
                    continue
                else:
                    next_position = _next_position

                # Find where the bomb stops if kicked
                for t in range(int(obs["bomb_life"][my_position]) - 1):
                    if not utility.position_is_passage(board, next_position):
                        break
                    _next_position = (next_position[0] + dx,
                                      next_position[1] + dy)
                    if not self._on_board(_next_position):
                        break
                    else:
                        next_position = _next_position
                if utility.position_is_fog(board, next_position):
                    print("Moving to kick into fog", action)
                    return action.value
                elif utility.position_is_enemy(list_boards[t + 2],
                                               next_position, my_enemies):
                    print("Moving to kick towards enemy", action)

        # Move towards an enemy
        good_time_positions = set()
        for enemy in my_enemies:
            good_time_positions = good_time_positions.union(
                next_to_items[enemy])

        if len(good_time_positions) > 0:
            action = self._find_distance_minimizer(my_position,
                                                   good_time_positions, prev,
                                                   is_survivable)

            if action is not None:
                print("Moving toward enemy", action)
                return action.value

        #
        # Random action
        #
        action = random.choice(survivable_actions)
        print("Random action", action)
        return action.value
Example #10
0
    def act(self, obs, action_space, info):

        #
        # Definitions
        #

        board = obs['board']
        my_position = obs["position"]  # tuple([x,y]): my position
        my_kick = obs["can_kick"]  # whether I can kick
        my_enemies = [constants.Item(e) for e in obs['enemies']]
        my_teammate = obs["teammate"]
        my_ammo = obs['ammo']  # int: the number of bombs I have
        my_blast_strength = obs['blast_strength']

        enemy_position = dict()
        for enemy in my_enemies:
            positions = np.argwhere(board == enemy.value)
            if len(positions) == 0:
                continue
            enemy_position[enemy] = tuple(positions[0])

        survivable_steps = defaultdict(int)

        #
        # survivable tree in standard case
        #

        list_boards_no_kick = deepcopy(info["list_boards_no_move"])

        # remove myself
        if obs["bomb_blast_strength"][my_position]:
            for b in list_boards_no_kick:
                if utility.position_is_agent(b, my_position):
                    b[my_position] = constants.Item.Bomb.value
        else:
            for b in list_boards_no_kick:
                if utility.position_is_agent(b, my_position):
                    b[my_position] = constants.Item.Passage.value

        my_survivable, my_prev, my_succ, my_survivable_with_enemy \
            = self._get_survivable_with_enemy(list_boards_no_kick, my_position, enemy_position)

        life = defaultdict(int)
        for t in range(self._search_range, 0, -1):
            for position in my_survivable_with_enemy[t]:
                if not life[(t, ) + position]:
                    life[(t, ) + position] = t
                for prev_position in my_prev[t][position]:
                    life[(t - 1, ) + prev_position] = max([
                        life[(t - 1, ) + prev_position], life[(t, ) + position]
                    ])

        for next_position in my_survivable[1]:
            my_action = self._get_direction(my_position, next_position)
            survivable_steps[my_action] = life[(1, ) + next_position]

        #
        # survivable tree if I lay bomb
        #

        if all([obs["ammo"] > 0, obs["bomb_life"][my_position] == 0]):
            # if I can lay a bomb

            board_with_bomb = deepcopy(obs["board"])
            curr_bombs_with_bomb = deepcopy(info["curr_bombs"])
            # lay a bomb
            board_with_bomb[my_position] = constants.Item.Bomb.value
            bomb = characters.Bomb(
                characters.Bomber(),  # dummy owner of the bomb
                my_position,
                constants.DEFAULT_BOMB_LIFE,
                my_blast_strength,
                None)
            curr_bombs_with_bomb.append(bomb)
            list_boards_with_bomb, _ \
                = self._board_sequence(board_with_bomb,
                                       curr_bombs_with_bomb,
                                       info["curr_flames"],
                                       self._search_range,
                                       my_position,
                                       enemy_mobility=0)

            my_survivable_with_bomb, my_prev_with_bomb, my_succ_with_bomb, my_survivable_with_bomb_enemy \
                = self._get_survivable_with_enemy(list_boards_with_bomb, my_position, enemy_position)

            life = defaultdict(int)
            for t in range(self._search_range, 0, -1):
                for position in my_survivable_with_bomb_enemy[t]:
                    if not life[(t, ) + position]:
                        life[(t, ) + position] = t
                    for prev_position in my_prev_with_bomb[t][position]:
                        life[(t - 1, ) + prev_position] = max([
                            life[(t - 1, ) + prev_position],
                            life[(t, ) + position]
                        ])

            survivable_steps[constants.Action.Bomb] = life[(1, ) + my_position]

        print("survivable steps")
        print(survivable_steps)

        if survivable_steps:
            values = np.array(list(survivable_steps.values()))
            print(values)
            best_index = np.where(values == np.max(values))
            best_actions = np.array(list(survivable_steps.keys()))[best_index]

            best_action = random.choice(best_actions)
            print("Most survivable action", best_action)

            return best_action.value

        else:
            print("No actions: stop")
            return constants.Action.Stop.value

        #
        # survivable tree if I kick
        #

        if my_kick:
            # Positions where I kick a bomb if I move to
            kickable, more_kickable = self._kickable_positions(
                obs, info["moving_direction"])

            for next_position in set.union(*[kickable, more_kickable]):
                # consider what happens if I kick a bomb
                my_action = self._get_direction(my_position, next_position)

                list_boards_with_kick, next_position \
                    = self._board_sequence(obs["board"],
                                           info["curr_bombs"],
                                           info["curr_flames"],
                                           self._search_range,
                                           my_position,
                                           my_action=my_action,
                                           can_kick=True,
                                           enemy_mobility=0)

                my_survivable_with_kick[next_position], my_prev_with_kick[next_position], my_succ_with_bomb[next_position], my_survivable_with_kick_enemy[next_position] \
                    = self._get_survivable_with_enemy(list_boards_with_kick[1:], next_position, enemy_position)

                survivable_with_kick, prev_kick, succ_kick, _ \
                    = self._search_time_expanded_network(list_boards_with_kick[1:],
                                                         next_position)

        # Survivable actions
        is_survivable, survivable_with_bomb \
            = self._get_survivable_actions(my_survivable,
                                           obs,
                                           info["curr_bombs"],
                                           info["curr_flames"],
                                           enemy_mobility=0)

        survivable_actions = [a for a in is_survivable if is_survivable[a]]

        n_survivable = dict()
        kick_actions = list()
        if my_kick:
            # Positions where we kick a bomb if we move to
            kickable = self._kickable_positions(obs, info["moving_direction"])
            for next_position in kickable:
                # consider what happens if I kick a bomb
                my_action = self._get_direction(my_position, next_position)

                list_boards_with_kick, next_position \
                    = self._board_sequence(obs["board"],
                                           info["curr_bombs"],
                                           info["curr_flames"],
                                           self._search_range,
                                           my_position,
                                           my_action=my_action,
                                           can_kick=True,
                                           enemy_mobility=0)
                #print(list_boards_with_kick)
                survivable_with_kick, prev_kick, succ_kick, _ \
                    = self._search_time_expanded_network(list_boards_with_kick[1:],
                                                         next_position)
                if next_position in survivable_with_kick[0]:
                    survivable_actions.append(my_action)
                    is_survivable[my_action] = True
                    n_survivable[my_action] = [1] + [
                        len(s) for s in survivable_with_kick[1:]
                    ]
                    kick_actions.append(my_action)
        else:
            kickable = set()

        x, y = my_position
        for action in survivable_actions:
            # for each survivable action, check the survivability
            if action == constants.Action.Bomb:
                n_survivable[action] = [
                    len(s) for s in survivable_with_bomb[1:]
                ]
                continue

            if action == constants.Action.Up:
                dx = -1
                dy = 0
            elif action == constants.Action.Down:
                dx = 1
                dy = 0
            elif action == constants.Action.Left:
                dx = 0
                dy = -1
            elif action == constants.Action.Right:
                dx = 0
                dy = 1
            elif action == constants.Action.Stop:
                dx = 0
                dy = 0
            else:
                raise ValueError()
            next_position = (x + dx, y + dy)
            n_survivable[action], _info = self._count_survivable(
                my_succ, 1, next_position)

        most_survivable_action = None
        if survivable_actions:
            survivable_score = dict()
            for action in n_survivable:
                #survivable_score[action] = sum([-n**(-5) for n in n_survivable[action]])
                survivable_score[action] = sum(
                    [n for n in n_survivable[action]])
                if verbose:
                    print(action, survivable_score[action],
                          n_survivable[action])
            best_survivable_score = max(survivable_score.values())

            random.shuffle(survivable_actions)
            for action in survivable_actions:
                if survivable_score[action] == best_survivable_score:
                    most_survivable_action = action
                    break

        if most_survivable_action is not None:
            print("Most survivable action", most_survivable_action)
            return most_survivable_action.value

        # kick if possible
        if my_kick:
            kickable = self._kickable_positions(obs, info["moving_direction"])
        else:
            kickable = set()
        print("Kickable", my_kick, kickable)
        while kickable:
            next_position = kickable.pop()
            action = self._get_direction(my_position, next_position)
            print("Must kick to survive", action)
            return action.value

        # move towards a teammate if she is blocking
        for action in [
                constants.Action.Right, constants.Action.Left,
                constants.Action.Down, constants.Action.Up
        ]:
            next_position = utility.get_next_position(my_position, action)
            if not self._on_board(next_position):
                continue
            if utility._position_is_item(board, next_position, my_teammate):
                print("Must move to teammate to survive", action)
                return action.value

        # move towards an enemy
        for action in [
                constants.Action.Right, constants.Action.Left,
                constants.Action.Down, constants.Action.Up
        ]:
            next_position = utility.get_next_position(my_position, action)
            if not self._on_board(next_position):
                continue
            if utility.position_is_enemy(board, next_position, my_enemies):
                print("Must move to enemy to survive", action)
                return action.value

        # move towards anywhere besides ridid
        for action in [
                constants.Action.Right, constants.Action.Left,
                constants.Action.Down, constants.Action.Up
        ]:
            next_position = utility.get_next_position(my_position, action)
            if not self._on_board(next_position):
                continue
            if utility.position_is_rigid(board, next_position):
                continue
            if utility.position_is_wood(board, next_position):
                continue
            if utility.position_is_bomb(info["curr_bombs"], next_position):
                continue
            print("Try moving to survive", action)
            return action.value

        action = constants.Action.Stop
        print("Must die", action)
        return action