コード例 #1
0
def _compute_min_evade_step(obs, parent_pos_list, pos, bomb_real_life):
    flag_cover, min_cover_value, max_cover_value = _position_covered_by_bomb(obs, pos, bomb_real_life)
    if not flag_cover:
        return 0
    elif len(parent_pos_list) >= max_cover_value:
        if len(parent_pos_list) > max_cover_value + FLAME_LIFE:
            return 0
        else:
            return INT_MAX
    elif len(parent_pos_list) >= min_cover_value:
        if len(parent_pos_list) > min_cover_value + FLAME_LIFE:
            return 0
        else:
            return INT_MAX
    else:
        board = obs['board']
        dirs = _all_directions(exclude_stop=True)
        min_step = INT_MAX
        for d in dirs:
            next_pos = utility.get_next_position(pos, d)
            if not utility.position_on_board(board, next_pos):
                continue
            if not (utility.position_is_passage(board, next_pos) or \
                    utility.position_is_powerup(board, next_pos)):
                continue
            if next_pos in parent_pos_list:
                continue
            x = _compute_min_evade_step(obs, parent_pos_list + [next_pos], next_pos, bomb_real_life)
            min_step = min(min_step, x + 1)
        return min_step
コード例 #2
0
ファイル: filter_action.py プロジェクト: b-kartal/playground
def position_can_be_bomb_through(board, position):
    if utility.position_is_flames(board, position):
        return True
    if utility.position_is_passage(board, position):
        return True
    if utility.position_is_powerup(board, position):
        return True
    return False
コード例 #3
0
def position_is_bombable(board, position, bombs):
    return any([
        utility.position_is_agent(board, position),
        utility.position_is_powerup(board, position),
        utility.position_is_passage(board, position),
        position_is_flame(board, position),
        position_is_bomb(bombs, position)
    ])
コード例 #4
0
def get_power_up(obs):
    res = [0] * 6
    my_position = obs['position']
    board = obs['board']
    for act in dirs:
        next_pos = util.get_next_position(my_position, act)
        if util.position_on_board(
                board, next_pos) and util.position_is_powerup(board, next_pos):
            res[act.value] = 1
    return res
コード例 #5
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)
    ])
コード例 #6
0
 def moving_bomb_check(moving_bomb_pos, p_dir, time_elapsed):
     pos2 = utility.get_next_position(moving_bomb_pos, p_dir)
     dist = 0
     for i in range(10):
         dist += 1
         if not utility.position_on_board(board, pos2):
             break
         if not (utility.position_is_powerup(board, pos2) or utility.position_is_passage(board, pos2)):
             break
         life_now = bomb_life[pos2] - time_elapsed
         if bomb_life[pos2] > 0 and life_now >= -2 and life_now <= 0 and dist < blast_st[pos2]:
             return False
         pos2 = utility.get_next_position(pos2, p_dir)
     return True
コード例 #7
0
def _all_bomb_real_life(board, bomb_life, bomb_blast_st):
    def get_bomb_real_life(bomb_position, bomb_real_life):
        """One bomb's real life is the minimum life of its adjacent bomb.
           Not that this could be chained, so please call it on each bomb mulitple times until
           converge
        """
        dirs = _all_directions(exclude_stop=True)
        min_life = bomb_real_life[bomb_position]
        for d in dirs:
            pos = bomb_position
            last_pos = bomb_position
            while True:
                pos = utility.get_next_position(pos, d)
                if _stop_condition(board, pos):
                    break
                if bomb_real_life[pos] > 0:
                    if bomb_real_life[pos] < min_life and \
                            _manhattan_distance(pos, last_pos) <= bomb_blast_st[pos] - 1:
                        min_life = bomb_real_life[pos]
                        last_pos = pos
                    else:
                        break
        return min_life

    bomb_real_life_map = np.copy(bomb_life)
    sz = len(board)
    while True:
        no_change = []
        for i in range(sz):
            for j in range(sz):
                if utility.position_is_wall(board, (i, j)) or utility.position_is_powerup(board, (i, j)) \
                        or utility.position_is_fog(board, (i, j)):
                    continue
                if bomb_life[i, j] < 0 + EPSILON:
                    continue
                real_life = get_bomb_real_life((i, j), bomb_real_life_map)
                no_change.append(bomb_real_life_map[i, j] == real_life)
                bomb_real_life_map[i, j] = real_life
        if all(no_change):
            break
    return bomb_real_life_map
コード例 #8
0
def _compute_safe_actions(obs, exclude_kicking=False, prev_two_obs=(None, None)):
    dirs = _all_directions(exclude_stop=True)
    ret = set()
    my_position, board, blast_st, bomb_life, can_kick = obs['position'], obs['board'], obs['bomb_blast_strength'], obs[
        'bomb_life'], obs['can_kick']
    kick_dir = None
    bomb_real_life_map = _all_bomb_real_life(board, bomb_life, blast_st)
    flag_cover_passages = []
    for direction in dirs:
        position = utility.get_next_position(my_position, direction)
        if not utility.position_on_board(board, position):
            continue
        if (not exclude_kicking) and utility.position_in_items(board, position, [constants.Item.Bomb]) and can_kick:
            # filter kick if kick is unsafe
            if _kick_test(board, blast_st, bomb_real_life_map, my_position, direction):
                ret.add(direction.value)
                kick_dir = direction.value
        gone_flame_pos = None
        if (prev_two_obs[0] != None and prev_two_obs[1] != None) and _check_if_flame_will_gone(obs, prev_two_obs,
                                                                                               position):
            # three consecutive flames means next step this position must be good
            # make this a candidate
            obs['board'][position] = constants.Item.Passage.value
            gone_flame_pos = position

        if utility.position_is_passage(board, position) or utility.position_is_powerup(board, position):
            my_id = obs['board'][my_position]
            obs['board'][my_position] = constants.Item.Bomb.value if bomb_life[
                                                                         my_position] > 0 else constants.Item.Passage.value
            flag_cover, min_cover_value, max_cover_value = _position_covered_by_bomb(obs, position, bomb_real_life_map)
            flag_cover_passages.append(flag_cover)
            if not flag_cover:
                ret.add(direction.value)
            else:
                min_escape_step = _compute_min_evade_step(obs, [position], position, bomb_real_life_map)
                assert (min_escape_step > 0)
                if min_escape_step < min_cover_value:
                    ret.add(direction.value)
            obs['board'][my_position] = my_id
        if gone_flame_pos is not None:
            obs['board'][gone_flame_pos] = constants.Item.Flames.value

    # Test Stop action only when agent is covered by bomb,
    # otherwise Stop is always an viable option
    my_id = obs['board'][my_position]
    obs['board'][my_position] = constants.Item.Bomb.value if bomb_life[
                                                                 my_position] > 0 else constants.Item.Passage.value
    # REMEMBER: before compute min evade step, modify board accordingly first..
    flag_cover, min_cover_value, max_cover_value = _position_covered_by_bomb(obs, my_position, bomb_real_life_map)
    if flag_cover:
        min_escape_step = _compute_min_evade_step(obs, [None, my_position], my_position, bomb_real_life_map)
        if min_escape_step < min_cover_value:
            ret.add(constants.Action.Stop.value)
    else:
        ret.add(constants.Action.Stop.value)
    obs['board'][my_position] = my_id
    # REMEBER: change the board back

    # Now test bomb action
    if not (obs['ammo'] <= 0 or obs['bomb_life'][obs['position']] > 0):
        # place bomb might be possible
        assert (BOMBING_TEST in ['simple', 'simple_adjacent', 'lookahead'])
        if BOMBING_TEST == 'simple':
            if not flag_cover:
                ret.add(constants.Action.Bomb.value)
        elif BOMBING_TEST == 'simple_adjacent':
            if (not flag_cover) and (not any(flag_cover_passages)):
                ret.add(constants.Action.Bomb.value)
        else:  # lookahead
            if (constants.Action.Stop.value in ret) and len(ret) > 1 and (kick_dir is None):
                obs2 = copy.deepcopy(obs)
                my_pos = obs2['position']
                obs2['board'][my_pos] = constants.Item.Bomb.value
                obs2['bomb_life'][my_pos] = min_cover_value if flag_cover else 10
                obs2['bomb_blast_strength'][my_pos] = obs2['blast_strength']
                bomb_life2, bomb_blast_st2, board2 = obs2['bomb_life'], obs2['bomb_blast_strength'], obs2['board']
                bomb_real_life_map = _all_bomb_real_life(board2, bomb_life2, bomb_blast_st2)
                min_evade_step = _compute_min_evade_step(obs2, [None, my_position], my_pos, bomb_real_life_map)
                current_cover_value = obs2['bomb_life'][my_pos]
                if min_evade_step < current_cover_value:
                    ret.add(constants.Action.Bomb.value)
    return ret
コード例 #9
0
    def _board_sequence(self, board, bombs, flames, length, my_position,
                        my_action=None, can_kick=False, enemy_mobility=3):
        """
        Simulate the sequence of boards, assuming agents stay unmoved

        Parameters
        ----------
        board : array
            initial board
        bombs : list
            list of initial bombs
        flames : list
            list of initial flames
        length : int
            length of the board sequence to simulate
        my_position : tuple
            position of my agent
        my_action : Action, optional
            my action at the first step
        can_kick : boolean, optional
            whether I can kick
        enemy_mobility : int, optional
            number of steps where enemies move nondeterministically

        Return
        ------
        list_boards : list
            list of boards
        """

        # Forward model to simulate
        model = ForwardModel()

        # Prepare initial state
        _board = board.copy()
        _bombs = deepcopy(bombs)
        _flames = deepcopy(flames)
        _items = dict()  # we never know hidden items
        _actions = [constants.Action.Stop.value] * 4
        if my_action is not None:
            agent = characters.Bomber()
            agent.agent_id = board[my_position] - 10
            agent.position = my_position
            agent.can_kick = can_kick
            _agents = [agent]
            _actions[agent.agent_id] = my_action
        else:
            _agents = list()

        my_next_position = None

        # Get enemy positions to take into account their mobility
        rows, cols = np.where(_board > constants.Item.AgentDummy.value)
        enemy_positions = [position for position in zip(rows, cols)
                           if position != my_position]

        # List of enemies
        enemies = list()
        for position in enemy_positions:
            agent = characters.Bomber()
            agent.agent_id = board[position] - 10
            agent.position = position
            enemies.append(agent)

        _agents = _agents + enemies

        # Overwrite bomb over agent if they overlap
        for bomb in _bombs:
            _board[bomb.position] = constants.Item.Bomb.value

        # Simulate
        list_boards = [_board.copy()]
        for t in range(length):
            # Standard simulation step            
            _board, _agents, _bombs, _, _flames \
                = model.step(_actions,
                             _board,
                             _agents,
                             _bombs,
                             _items,
                             _flames)

            # Overwrite passage over my agent when it has moved to a passage
            if t == 0 and len(_agents) > 0:
                agent = _agents[0]
                my_next_position = agent.position
                if all([agent.position != my_position,
                        _board[agent.position] != constants.Item.Flames.value,
                        _board[agent.position] != constants.Item.Bomb.value]):   
                    # I did not die and did not stay on a bomb
                    _board[agent.position] = constants.Item.Passage.value

            # Overwrite bomb over agent if they overlap
            for bomb in _bombs:
                _board[bomb.position] = constants.Item.Bomb.value

            # Take into account the nondeterministic mobility of enemies
            if t < enemy_mobility:
                _enemy_positions = set()
                for x, y in enemy_positions:
                    # for each enemy position in the previous step
                    for dx, dy in [(0, 0), (1, 0), (-1, 0), (0, 1), (0, -1)]:
                        # consider the next possible position
                        next_position = (x + dx, y + dy)
                        if not self._on_board(next_position):
                            # ignore if out of board
                            continue
                        if any([utility.position_is_passage(_board, next_position),
                                utility.position_is_powerup(_board, next_position),
                                (next_position == my_position
                                 and utility.position_is_agent(_board, next_position)
                                )]):
                            # possible as a next position
                            # TODO : what to do with my position
                            _enemy_positions.add(next_position)
                            _board[next_position] = constants.Item.AgentDummy.value
                enemy_positions = _enemy_positions

            _actions = [constants.Action.Stop.value] * 4
            _agents = enemies
            list_boards.append(_board.copy())

        return list_boards, my_next_position
コード例 #10
0
def position_is_passable(board, pos, enemies=[]):
    #hard code the smallest agent id on board
    if board[pos] >= 10:
        return False
    return utility.position_is_powerup(
        board, pos) or utility.position_is_passage(board, pos)
コード例 #11
0
ファイル: generic_agent.py プロジェクト: takahasixxx/GGG
    def act(self, obs, action_space, info):

        #
        # Definitions
        #

        board = obs['board']
        recently_seen_positions = (info["since_last_seen"] < 3)
        board[recently_seen_positions] = info["last_seen"][recently_seen_positions]
        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'] if e != constants.Item.AgentDummy]
        if obs["teammate"] != constants.Item.AgentDummy:
            my_teammate = obs["teammate"]
        else:
            my_teammate = None
        my_kick = obs["can_kick"]  # whether I can kick

        if verbose:
            print("my position", my_position, "ammo", my_ammo, "blast", my_blast_strength, "kick", my_kick, end="\t")

        my_next_position = {constants.Action.Stop: my_position,
                            constants.Action.Bomb: my_position}
        for action in [constants.Action.Up, constants.Action.Down,
                       constants.Action.Left, constants.Action.Right]:
            next_position = self._get_next_position(my_position, action)
            if self._on_board(next_position):
                if board[next_position] in [constants.Item.Rigid.value, constants.Item.Wood.value]:
                    my_next_position[action] = None
                else:
                    my_next_position[action] = next_position
            else:
                my_next_position[action] = None

        #
        # Understand current situation
        #

        if all([info["prev_action"] not in [constants.Action.Stop, constants.Action.Bomb],
                info["prev_position"] == my_position]):
            # if previously blocked, do not reapeat with some probability
            self._inv_tmp *= self._backoff
        else:
            self._inv_tmp = self._inv_tmp_init

        
        # enemy positions
        enemy_positions = list()
        for enemy in my_enemies:
            rows, cols = np.where(board==enemy.value)
            if len(rows) == 0:
                continue
            enemy_positions.append((rows[0], cols[0]))

        # teammate position
        teammate_position = None
        if my_teammate is not None:
            rows, cols = np.where(board==my_teammate.value)
            if len(rows):
                teammate_position = (rows[0], cols[0])
        
        # where to place bombs to break wood
        digging, bomb_target = self._get_digging_positions(board, my_position, info)                

        if digging is None:
            bomb_target, n_breakable \
                = self._get_bomb_target(info["list_boards_no_move"][-1],
                                        my_position,
                                        my_blast_strength,
                                        constants.Item.Wood)

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

        # positions that might be blocked
        if teammate_position is None:
            agent_positions = enemy_positions
        else:
            agent_positions = enemy_positions + [teammate_position]
        might_blocked = self._get_might_blocked(board, my_position, agent_positions, might_kickable)

        # enemy positions over time
        # these might be dissappeared due to extra flames
        if len(enemy_positions):
            rows = [p[0] for p in enemy_positions]
            cols = [p[1] for p in enemy_positions]
            list_enemy_positions = [(rows, cols)]
            _enemy_positions = list()
            for t in range(self._enemy_mobility):
                rows, cols = list_enemy_positions[-1]
                for x, y in zip(rows, cols):
                    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
                        next_position = (x + dx, y + dy)
                        if not self._on_board(next_position):
                            continue
                        _board = info["list_boards_no_move"][t]
                        if any([utility.position_is_passage(_board, next_position),
                                utility.position_is_powerup(_board, next_position)]):
                            _enemy_positions.append(next_position)
            _enemy_positions = set(_enemy_positions)
            rows = [p[0] for p in _enemy_positions]
            cols = [p[1] for p in _enemy_positions]
            list_enemy_positions.append((rows, cols))
        else:
            list_enemy_positions = []
            
        
        # survivable actions
        is_survivable = dict()
        for a in self._get_all_actions():
            is_survivable[a] = False
        n_survivable = dict()
        list_boards = dict()
        for my_action in self._get_all_actions():

            next_position = my_next_position[my_action]

            if next_position is None:
                continue

            if my_action == constants.Action.Bomb:
                if any([my_ammo == 0,
                        obs["bomb_blast_strength"][next_position] > 0]):
                    continue
            
            if all([utility.position_is_flames(board, next_position),
                    info["flame_life"][next_position] > 1]):
                continue

            if all([my_action != constants.Action.Stop,
                    obs["bomb_blast_strength"][next_position] > 0,
                    next_position not in set.union(kickable, might_kickable)]):
                continue

            if next_position in set.union(kickable, might_kickable):
                # 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 of boards from next steps
            list_boards[my_action], _ \
                = self._board_sequence(obs["board"],
                                       info["curr_bombs"],
                                       info["curr_flames"],
                                       self._search_range,
                                       my_position,
                                       my_blast_strength=my_blast_strength,
                                       my_action=my_action,
                                       can_kick=my_kick,
                                       enemy_mobility=self._enemy_mobility,
                                       enemy_bomb=self._enemy_bomb,
                                       agent_blast_strength=info["agent_blast_strength"])

            # wood might be disappeared, because of overestimated bombs
            for t in range(len(list_boards[my_action])):
                wood_positions = np.where(info["list_boards_no_move"][t] == constants.Item.Wood.value)
                list_boards[my_action][t][wood_positions] = constants.Item.Wood.value                       

            # agents might be disappeared, because of overestimated bombs
            for t, positions in enumerate(list_enemy_positions):
                list_boards[my_action][t][positions] = constants.Item.AgentDummy.value
            
            # some bombs may explode with extra bombs, leading to under estimation
            for t in range(len(list_boards[my_action])):
                flame_positions = np.where(info["list_boards_no_move"][t] == constants.Item.Flames.value)
                list_boards[my_action][t][flame_positions] = constants.Item.Flames.value
                
        """
        processed = Parallel(n_jobs=-1, verbose=0)(
            [delayed(search_time_expanded_network)(list_boards[action][1:], my_next_position[action], action)
             for action in list_boards]
        )
        for survivable, my_action in processed:
            if my_next_position[my_action] in survivable[0]:
                is_survivable[my_action] = True
                n_survivable[my_action] = [1] + [len(s) for s in survivable[1:]]
        """
        
        for my_action in list_boards:
            survivable = search_time_expanded_network(list_boards[my_action][1:],
                                                      my_next_position[my_action])
            if my_next_position[my_action] in survivable[0]:
                is_survivable[my_action] = True
                n_survivable[my_action] = [1] + [len(s) for s in survivable[1:]]
        
        survivable_actions = list()
        for a in is_survivable:
            if not is_survivable[a]:
                continue
            if might_blocked[a] and not is_survivable[constants.Action.Stop]:
                continue
            if n_survivable[a][-1] <= 1:
                is_survivable[a] = False
                continue
            survivable_actions.append(a)

        #
        # Choose action
        #
                
        if len(survivable_actions) == 0:

            #
            # return None, if no survivable actions
            #
        
            return None

        elif len(survivable_actions) == 1:

            #
            # Choose the survivable action, if it is the only choice
            #
            
            action = survivable_actions[0]
            if verbose:
                print("The only survivable action", action)
            return action.value


        #
        # Bomb at a target
        #

        # fraction of blocked node in the survival trees of enemies
        _list_boards = deepcopy(info["list_boards_no_move"])
        if obs["bomb_blast_strength"][my_position]:
            for b in _list_boards:
                if utility.position_is_agent(b, my_position):
                    b[my_position] = constants.Item.Bomb.value
        else:
            for b in _list_boards:
                if utility.position_is_agent(b, my_position):
                    b[my_position] = constants.Item.Passage.value

        total_frac_blocked, n_survivable_nodes, blocked_time_positions \
            = self._get_frac_blocked(_list_boards, my_enemies, board, obs["bomb_life"])
    
        if teammate_position is not None:
            total_frac_blocked_teammate, n_survivable_nodes_teammate, blocked_time_positions_teammate \
                = self._get_frac_blocked(_list_boards, [my_teammate], board, obs["bomb_life"])

            """
            np.set_printoptions(precision=3)
            print("enemy")
            print(total_frac_blocked)
            print("teammate")
            print(total_frac_blocked_teammate)
            print("product")
            prod = total_frac_blocked * (1 - total_frac_blocked_teammate)
            print(prod[:5,:5])
            """

        p_survivable = defaultdict(float)
        for action in n_survivable:
            p_survivable[action] = sum(n_survivable[action]) / self._my_survivability_threshold
            if p_survivable[action] > 1:
                p_survivable[action] = 1

        block = defaultdict(float)
        for action in [constants.Action.Stop,
                       constants.Action.Up, constants.Action.Down,
                       constants.Action.Left, constants.Action.Right]:
            next_position = my_next_position[action]
            if next_position is None:
                continue
            if next_position in set.union(kickable, might_kickable):
                # kick will be considered later
                continue
            if all([utility.position_is_flames(board, next_position),
                    info["flame_life"][next_position] > 1,
                    is_survivable[constants.Action.Stop]]):
                # if the next position is flames,
                # I want to stop to wait, which must be feasible
                block[action] = total_frac_blocked[next_position] * p_survivable[constants.Action.Stop]
                if teammate_position is not None:
                    block[action] *= (1 - total_frac_blocked_teammate[next_position])
                block[action] *= self._inv_tmp
                block[action] -=  np.log(-np.log(self.random.uniform()))
                continue
            elif not is_survivable[action]:
                continue
            if all([might_blocked[action],
                    not is_survivable[constants.Action.Stop]]):
                continue

            block[action] = total_frac_blocked[next_position] * p_survivable[action]
            if teammate_position is not None:
                block[action] *= (1 - total_frac_blocked_teammate[next_position])
            block[action] *= self._inv_tmp            
            block[action] -=  np.log(-np.log(self.random.uniform()))
            if might_blocked[action]:
                block[action] = (total_frac_blocked[my_position] * p_survivable[constants.Action.Stop]
                                 + total_frac_blocked[next_position] * p_survivable[action]) / 2
                if teammate_position is not None:                    
                    block[action] *= (1 - total_frac_blocked_teammate[next_position])
                block[action] *= self._inv_tmp                
                block[action] -=  np.log(-np.log(self.random.uniform()))

        if is_survivable[constants.Action.Bomb]:
            list_boards_with_bomb, _ \
                = self._board_sequence(board,
                                       info["curr_bombs"],
                                       info["curr_flames"],
                                       self._search_range,
                                       my_position,
                                       my_blast_strength=my_blast_strength,
                                       my_action=constants.Action.Bomb)

            n_survivable_nodes_with_bomb = defaultdict(int)
            for enemy in my_enemies:
                # get survivable tree of the enemy
                rows, cols = np.where(board==enemy.value)
                if len(rows) == 0:
                    continue
                enemy_position = (rows[0], cols[0])
                _survivable = search_time_expanded_network(list_boards_with_bomb,
                                                           enemy_position)
                n_survivable_nodes_with_bomb[enemy] = sum([len(positions) for positions in _survivable])

            n_with_bomb = sum([n_survivable_nodes_with_bomb[enemy] for enemy in my_enemies])
            n_with_none = sum([n_survivable_nodes[enemy] for enemy in my_enemies])
            if n_with_none == 0:
                total_frac_blocked_with_bomb = 0

                # place more bombs, so the stacked enemy cannot kick
                x, y = my_position
                for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
                    next_position = (x + dx, y + dy)
                    following_position = (x + 2 * dx, y + 2 * dy)
                    if not self._on_board(following_position):
                        continue
                    if all([obs["bomb_life"][next_position] > 0,
                            board[following_position] > constants.Item.AgentDummy.value]):
                        total_frac_blocked_with_bomb = 1
            else:
                total_frac_blocked_with_bomb = 1 - n_with_bomb / n_with_none

            if teammate_position is not None:
                # get survivable tree of the teammate
                _survivable = search_time_expanded_network(list_boards_with_bomb, teammate_position)
                n_survivable_nodes_with_bomb_teammate = sum([len(positions) for positions in _survivable])

                n_with_bomb = n_survivable_nodes_with_bomb_teammate
                n_with_none = n_survivable_nodes_teammate[my_teammate]
                if n_with_none == 0:
                    total_frac_blocked_with_bomb_teammate = 0
                else:
                    total_frac_blocked_with_bomb_teammate = 1 - n_with_bomb / n_with_none

            action = constants.Action.Bomb
            block[action] = total_frac_blocked_with_bomb * p_survivable[action]
            if teammate_position is not None:
                block[action] *= (1 - total_frac_blocked_with_bomb_teammate)
            block[action] *= self._inv_tmp
            block[action] -=  np.log(-np.log(self.random.uniform()))

        for next_position in kickable:

            action = self._get_direction(my_position, next_position)
            if not is_survivable[action]:
                continue

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

            n_survivable_nodes_with_kick = defaultdict(int)
            for enemy in my_enemies:
                # get survivable tree of the enemy
                rows, cols = np.where(board==enemy.value)
                if len(rows) == 0:
                    continue
                enemy_position = (rows[0], cols[0])
                _survivable = search_time_expanded_network(list_boards_with_kick,
                                                           enemy_position)
                n_survivable_nodes_with_kick[enemy] = sum([len(positions) for positions in _survivable])

                n_with_kick = sum([n_survivable_nodes_with_kick[enemy] for enemy in my_enemies])
                n_with_none = sum([n_survivable_nodes[enemy] for enemy in my_enemies])
                if n_with_none == 0:
                    total_frac_blocked[next_position] = 0
                else:
                    total_frac_blocked[next_position] = 1 - n_with_kick / n_with_none

            if teammate_position is not None:
                # get survivable tree of the teammate
                _survivable = search_time_expanded_network(list_boards_with_kick, teammate_position)
                n_survivable_nodes_with_kick_teammate = sum([len(positions) for positions in _survivable])

                n_with_kick = n_survivable_nodes_with_kick_teammate
                n_with_none = n_survivable_nodes_teammate[my_teammate]
                if n_with_none == 0:
                    total_frac_blocked_teammate[next_position] = 0
                else:
                    total_frac_blocked_teammate[next_position] = 1 - n_with_kick / n_with_none
            
            block[action] = total_frac_blocked[next_position] * p_survivable[action]
            if teammate_position is not None:
                block[action] *= (1 - total_frac_blocked_teammate[next_position])
            block[action] *= self._inv_tmp
            block[action] -=  np.log(-np.log(self.random.uniform()))

        max_block = -np.inf
        best_action = None
        for action in block:
            if block[action] > max_block:
                max_block = block[action]
                best_action = action

        if block[constants.Action.Bomb] > self._bomb_threshold * self._inv_tmp:
            if teammate_position is not None:
                teammate_safety = total_frac_blocked_with_bomb_teammate * n_survivable_nodes_with_bomb_teammate
                if any([teammate_safety > self._teammate_survivability_threshold,
                        total_frac_blocked_with_bomb_teammate < self._interfere_threshold,
                        total_frac_blocked_with_bomb_teammate < total_frac_blocked_teammate[my_position]]):
                    teammate_ok = True
                else:
                    teammate_ok = False
            else:
                teammate_ok = True

            if teammate_ok:
                if best_action == constants.Action.Bomb:                    
                    if verbose:
                        print("Bomb is best", constants.Action.Bomb)
                    return constants.Action.Bomb.value

                if best_action == constants.Action.Stop:
                    if verbose:
                        print("Place a bomb at a locally optimal position", constants.Action.Bomb)
                    return constants.Action.Bomb.value

        #
        # Move towards where to bomb
        #

        if best_action not in [None, constants.Action.Bomb]:
            next_position = my_next_position[best_action]

            should_chase = (total_frac_blocked[next_position] > self._chase_threshold)

            if teammate_position is not None:
                teammate_safety = total_frac_blocked_teammate[next_position] * n_survivable_nodes_teammate[my_teammate]
                if any([teammate_safety > self._teammate_survivability_threshold,
                        total_frac_blocked_teammate[next_position] < self._interfere_threshold,
                        total_frac_blocked_teammate[next_position] < total_frac_blocked_teammate[my_position]]):
                    teammate_ok = True
                else:
                    teammate_ok = False
            else:
                teammate_ok = True

            if should_chase and teammate_ok:
                if all([utility.position_is_flames(board, next_position),
                        info["flame_life"][next_position] > 1,
                        is_survivable[constants.Action.Stop]]):
                    action = constants.Action.Stop
                    if verbose:
                        print("Wait flames life", action)
                    return action.value
                else:
                    if verbose:
                        print("Move towards better place to bomb", best_action)
                    return best_action.value                

        # Exclude the action representing stop to wait
        max_block = -np.inf
        best_action = None
        for action in survivable_actions:
            if block[action] > max_block:
                max_block = block[action]
                best_action = action
                
        #
        # Do not take risky actions
        #

        most_survivable_action = self._action_most_survivable(n_survivable)

        # ignore actions with low survivability
        _survivable_actions = list()
        for action in n_survivable:
            n = sum(n_survivable[action])
            if not is_survivable[action]:
                continue
            elif n > self._my_survivability_threshold:
                _survivable_actions.append(action)
            else:
                print("RISKY", action)
                is_survivable[action] = False

        if len(_survivable_actions) > 1:
            survivable_actions = _survivable_actions
        elif best_action is not None:
            if verbose:
                print("Take the best action in danger", best_action)
            return best_action.value
        else:
            # Take the most survivable action
            if verbose:
                print("Take the most survivable action", most_survivable_action)
            return most_survivable_action.value

        #
        # Do not interfere with teammate
        #

        if all([teammate_position is not None,
                len(enemy_positions) > 0 or len(info["curr_bombs"]) > 0]):
            # ignore actions that interfere with teammate
            min_interfere = np.inf
            least_interfere_action = None
            _survivable_actions = list()
            for action in survivable_actions:
                if action == constants.Action.Bomb:
                    frac = total_frac_blocked_with_bomb_teammate
                else:
                    next_position = my_next_position[action]
                    frac = total_frac_blocked_teammate[next_position]
                if frac < min_interfere:
                    min_interfere = frac
                    least_interfere_action = action
                if frac < self._interfere_threshold:
                    _survivable_actions.append(action)
                else:
                    print("INTERFERE", action)
                    is_survivable[action] = False

            if len(_survivable_actions) > 1:
                survivable_actions = _survivable_actions
            elif best_action is not None:
                # Take the least interfering action
                if verbose:
                    print("Take the best action in intereference", best_action)
                return best_action.value
            else:
                if verbose:
                    print("Take the least interfering action", least_interfere_action)
                return least_interfere_action.value

        #
        # Bomb to break wood
        #

        consider_bomb = True
        if not is_survivable[constants.Action.Bomb]:
            consider_bomb = False
        elif self._might_break_powerup(info["list_boards_no_move"][-1],
                                       my_position,
                                       my_blast_strength,
                                       info["might_powerup"]):
            # if might break an item, do not bomb
            consider_bomb = False

        if consider_bomb and bomb_target[my_position]:
            # place bomb if I am at a bomb target
            if verbose:
                print("Bomb at a bomb target", constants.Action.Bomb)
            return constants.Action.Bomb.value

        #
        # Find reachable items
        #

        # List of boards simulated
        list_boards, _ = self._board_sequence(board,
                                              info["curr_bombs"],
                                              info["curr_flames"],
                                              self._search_range,
                                              my_position,
                                              enemy_mobility=self._enemy_mobility,
                                              enemy_bomb=self._enemy_bomb,
                                              agent_blast_strength=info["agent_blast_strength"])
        # wood might be disappeared, because of overestimated bombs
        for t in range(len(list_boards)):
            wood_positions = np.where(info["list_boards_no_move"][t] == constants.Item.Wood.value)
            list_boards[t][wood_positions] = constants.Item.Wood.value                       

        # some bombs may explode with extra bombs, leading to under estimation
        for t in range(len(list_boards)):
            flame_positions = np.where(info["list_boards_no_move"][t] == constants.Item.Flames.value)
            list_boards[t][flame_positions] = constants.Item.Flames.value
        
        # 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:
            survivable = [set() for _ in range(len(survivable))]

        # Items and bomb target that can be reached in a survivable manner
        reachable_items, reached, next_to_items \
            = self._find_reachable_items(list_boards,
                                         my_position,
                                         survivable,
                                         bomb_target,
                                         info["might_powerup"])

        #
        # Move to dig
        #

        action_to_target = self._action_to_target(my_position, reachable_items, prev, is_survivable)

        if all([digging is not None,
                action_to_target is not None]):
            time_to_reach = reachable_items["target"][0][0]
            if any([my_ammo and board[digging] in [constants.Item.Passage.value,
                                                   constants.Item.ExtraBomb.value,
                                                   constants.Item.IncrRange.value,
                                                   constants.Item.Kick.value],
                    info["flame_life"][digging] <= time_to_reach
                    and utility.position_is_flames(board, digging)]):
                if verbose:
                    print("Move to dig", action_to_target)
                return action_to_target.value        

        #
        # Move towards good items
        #

        action = self._action_to_powerup(my_position, reachable_items, prev, is_survivable)
        if action is not None:
            if verbose:
                print("Moving toward good item", action)
            return action.value

        #
        # Move towards where to bomb to break wood
        #

        if action_to_target is not None:
            if verbose:
                print("Moving toward where to bomb", action_to_target)
            return action_to_target.value

        #
        # Move toward might powerups
        #

        action = self._action_to_might_powerup(my_position, reachable_items, prev, is_survivable)
        if action is not None:
            if verbose:
                print("Moving toward might-powerups", action)
            return action.value

        #
        # If I have seen an enemy recently and cannot see him now, them move to the last seen position
        #

        action = self._action_to_enemy(my_position, next_to_items[constants.Item.Fog], prev, is_survivable, info,
                                       my_enemies)
        if action is not None:
            if verbose:
                print("Moving toward last seen enemy", action)
            return action.value            
        
        #
        # If I have seen a teammate recently, them move away from the last seen position
        #

        action = self._action_away_from_teammate(my_position,
                                                 next_to_items[constants.Item.Fog],
                                                 prev,
                                                 is_survivable,
                                                 info,
                                                 my_teammate)
        if action is not None:
            if verbose:
                print("Moving away from last seen teammate", action)
            return action.value            
        
        #
        # Move towards a fog where we have not seen longest
        #
        
        action = self._action_to_fog(my_position, next_to_items[constants.Item.Fog], prev, is_survivable, info)

        if action is not None:
            #if True:
            if self.random.uniform() < 0.8:
                if verbose:
                    print("Moving toward oldest fog", action)
                return action.value            

        #
        # Choose most survivable action
        #

        max_block = -np.inf
        best_action = None
        for action in survivable_actions:
            if action == constants.Action.Bomb:
                continue
            if block[action] > max_block:
                max_block = block[action]
                best_action = action

        if verbose:
            print("Take the best action among safe actions (nothing else to do)", best_action)

        if best_action is None:
            # this should not be the case
            return None
        else:
            return best_action.value
コード例 #12
0
    def _might_break_powerup(cls, board, my_position, blast_strength,
                             might_powerup):
        """
        Whether one might break a powerup by placing a bomb at my position

        Parameters
        ----------
        board : array
            board
        my_position : tuple
            where to place a bomb
        blast_strength : int
           strength of the bomb

        Return
        ------
        boolean
            True iff might break a powerup by placing a bomb
        """

        x, y = my_position
        # To up
        for dx in range(1, blast_strength):
            if x + dx >= len(board[0]):
                break
            position = (x + dx, y)
            if utility.position_is_powerup(
                    board, position) or might_powerup[position]:
                return True
            if not utility.position_is_passage(board, position):
                # stop searching this direction
                break
        # To down
        for dx in range(1, blast_strength):
            if x - dx < 0:
                break
            position = (x - dx, y)
            if utility.position_is_powerup(
                    board, position) or might_powerup[position]:
                return True
            if not utility.position_is_passage(board, position):
                # stop searching this direction
                break
        # To right
        for dy in range(1, blast_strength):
            if y + dy >= len(board):
                break
            position = (x, y + dy)
            if utility.position_is_powerup(
                    board, position) or might_powerup[position]:
                return True
            if not utility.position_is_passage(board, position):
                # stop searching this direction
                break
        # To left
        for dy in range(1, blast_strength):
            if y - dy < 0:
                break
            position = (x, y - dy)
            if utility.position_is_powerup(
                    board, position) or might_powerup[position]:
                return True
            if not utility.position_is_passage(board, position):
                # stop searching this direction
                break
        return False