Ejemplo n.º 1
0
    def _can_escape_old(board, my_position, blast_strength):

        for row, col in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            for d in range(1, blast_strength + 1):
                new_pos = (my_position[0] + row * d, my_position[1] + col * d)

                if TestSimpleAgent._out_of_board(new_pos):
                    continue

                if not utility.position_is_passage(board, new_pos):
                    break

                if d == blast_strength:
                    return True

                if row == 0:
                    for row2, col2 in [(-1, 0), (1, 0)]:
                        new_pos2 = (new_pos[0] + row2, new_pos[1] + col2)

                        if TestSimpleAgent._out_of_board(new_pos2):
                            continue

                        if utility.position_is_passage(board, new_pos2):
                            return True
                else:
                    for row2, col2 in [(0, -1), (0, 1)]:
                        new_pos2 = (new_pos[0] + row2, new_pos[1] + col2)

                        if TestSimpleAgent._out_of_board(new_pos2):
                            continue

                        if utility.position_is_passage(board, new_pos2):
                            return True

        return False
Ejemplo n.º 2
0
def me_to_enemy_all_corridor(board, pos1, pos2):
    assert (pos1[0] == pos2[0] or pos1[1] == pos2[1])
    if pos1[0] == pos2[0]:
        if pos1[1] < pos2[1]:
            direction = constants.Action.Right
        else:
            direction = constants.Action.Left
    else:
        if pos1[0] < pos2[0]:
            direction = constants.Action.Down
        else:
            direction = constants.Action.Up
    p_dirs = perpendicular_directions(direction)
    pos2_next = utility.get_next_position(pos2, direction)
    next_is_impasse = (not utility.position_on_board(
        board, pos2_next)) or utility.position_is_wall(board, pos2_next)
    if utility.position_on_board(board, pos2_next) and utility.position_is_fog(
            board, pos2_next):
        next_is_impasse = False
    if not (position_is_in_corridor(board, pos2, p_dirs) and next_is_impasse):
        # pos2:enempy must be in impasse
        return False
    all_corridor_flag = True
    pos = utility.get_next_position(pos1, direction)
    while pos != pos2:
        if not (utility.position_is_passage(board, pos)):
            all_corridor_flag = False
            break
        if not position_is_in_corridor(board, pos, p_dirs):
            all_corridor_flag = False
            break
        pos = utility.get_next_position(pos, direction)
    return all_corridor_flag
Ejemplo n.º 3
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
Ejemplo n.º 4
0
def _kick_test(board, blast_st, bomb_life, my_position, direction):
    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
    next_position=utility.get_next_position(my_position, direction)
    assert(utility.position_in_items(board, next_position, [constants.Item.Bomb]))
    life_value=int(bomb_life[next_position])
    strength=int(blast_st[next_position])
    dist=0
    pos=utility.get_next_position(next_position, direction)
    perpendicular_dirs=[constants.Action.Left, constants.Action.Right] 
    if direction == constants.Action.Left or direction == constants.Action.Right:
        perpendicular_dirs=[constants.Action.Down, constants.Action.Up]
    for i in range(life_value): 
        if utility.position_on_board(board, pos) and utility.position_is_passage(board, pos):
            #do a check if this position happens to be in flame when the moving bomb arrives!
            if not (moving_bomb_check(pos, perpendicular_dirs[0], i) and moving_bomb_check(pos, perpendicular_dirs[1], i)):
                break
            dist +=1 
        else:
            break
        pos=utility.get_next_position(pos, direction)
        #can kick and kick direction is valid
    return dist > strength
Ejemplo n.º 5
0
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
Ejemplo n.º 6
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)
    ])
Ejemplo n.º 7
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)
    ])
Ejemplo n.º 8
0
 def is_moving_direction(bomb_pos, direction):
     rev_d = _opposite_direction(direction)
     rev_pos = utility.get_next_position(bomb_pos, rev_d)
     if not utility.position_on_board(prev_obs['board'], rev_pos):
         return False
     if prev_obs['bomb_life'][rev_pos] - 1 == obs['bomb_life'][bomb_pos] \
             and prev_obs['bomb_blast_strength'][rev_pos] == obs['bomb_blast_strength'][bomb_pos] \
             and utility.position_is_passage(prev_obs['board'], bomb_pos):
         return True
     return False
Ejemplo n.º 9
0
 def is_moving_direction(bomb_pos, direction):  # 炸弹是否在移动
     rev_d = _opposite_direction(direction)  # 返回 bomb 移动方向的反向
     rev_pos = utility.get_next_position(bomb_pos, rev_d)  # 上一帧 bomb 的位置
     if not utility.position_on_board(
             prev_obs['board'], rev_pos):  # 如果上一帧位置不在 board 上, 返回 False
         return False
     if prev_obs['bomb_life'][rev_pos] - 1 == obs['bomb_life'][bomb_pos] \
             and prev_obs['bomb_blast_strength'][rev_pos] == obs['bomb_blast_strength'][bomb_pos] \
             and utility.position_is_passage(prev_obs['board'], bomb_pos):
         return True  # 与上一帧是同一个bomb 并且当前位置是一个过道0 返回 True
     return False
Ejemplo n.º 10
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
Ejemplo n.º 11
0
def move_moving_bombs_to_next_position(prev_obs, obs):
    def is_moving_direction(bomb_pos, direction):  # 炸弹是否在移动
        rev_d = _opposite_direction(direction)  # 返回 bomb 移动方向的反向
        rev_pos = utility.get_next_position(bomb_pos, rev_d)  # 上一帧 bomb 的位置
        if not utility.position_on_board(
                prev_obs['board'], rev_pos):  # 如果上一帧位置不在 board 上, 返回 False
            return False
        if prev_obs['bomb_life'][rev_pos] - 1 == obs['bomb_life'][bomb_pos] \
                and prev_obs['bomb_blast_strength'][rev_pos] == obs['bomb_blast_strength'][bomb_pos] \
                and utility.position_is_passage(prev_obs['board'], bomb_pos):
            return True  # 与上一帧是同一个bomb 并且当前位置是一个过道0 返回 True
        return False

    bombs = zip(*np.where(obs['bomb_life'] > 1))
    moving_bombs = []
    for bomb_pos in bombs:
        moving_dir = None
        for d in [constants.Action.Left, constants.Action.Right, \
                  constants.Action.Up, constants.Action.Down]:
            if is_moving_direction(bomb_pos, d):
                moving_dir = d
                break
        if moving_dir is not None:
            moving_bombs.append((bomb_pos, moving_dir))
    board = obs['board']
    bomb_life = obs['bomb_life']
    bomb_blast_strength = obs['bomb_blast_strength']
    for bomb_pos, moving_dir in moving_bombs:
        next_pos = utility.get_next_position(bomb_pos, moving_dir)
        if not utility.position_on_board(obs['board'], next_pos):
            continue
        if utility.position_is_passage(obs['board'], next_pos):
            board[next_pos] = board[bomb_pos]
            bomb_life[next_pos] = bomb_life[bomb_pos]
            bomb_blast_strength[next_pos] = bomb_blast_strength[bomb_pos]
            board[bomb_pos] = constants.Item.Passage.value
            bomb_life[bomb_pos] = 0
            bomb_blast_strength[bomb_pos] = 0
    return obs
Ejemplo n.º 12
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
Ejemplo n.º 13
0
    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] == constants.Item.Rigid.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])
        
        # 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 utility.position_is_passage(_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"])

            # 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

        consider_bomb = True
        if not is_survivable[constants.Action.Bomb]:
            consider_bomb = False

        #
        # 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"])

        # 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
        _, _, next_to_items \
            = self._find_reachable_items(list_boards,
                                         my_position,
                                         survivable)

        #
        # 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
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)
Ejemplo n.º 15
0
    def _kickable_positions(self, obs, moving_direction):

        """
        Parameters
        ----------
        obs : dict
            pommerman observation
        """

        if not obs["can_kick"]:
            return set()

        kickable = set()
        x, y = obs["position"]

        # Find neigoboring positions on board
        on_board_next_positions = list()
        for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            next_position = (x + dx, y + dy)
            if self._on_board(next_position):
                on_board_next_positions.append(next_position)

        # Check if can kick a static bomb
        for next_position in on_board_next_positions:
            if obs["board"][next_position] != constants.Item.Bomb.value:
                # not a bomb
                continue
            if moving_direction[next_position] is not None:
                # moving
                continue
            if obs["bomb_life"][next_position] <= 1:
                # kick and die
                continue
            following_position = (2 * next_position[0] - x,
                                  2 * next_position[1] - y)
            if not self._on_board(following_position):
                # cannot kick to that direction
                continue
            if not utility.position_is_passage(obs["board"], following_position):
                # cannot kick to that direction
                continue
            kickable.add(next_position)

        # Check if can kick a moving bomb
        for next_position in on_board_next_positions:
            if next_position in kickable:
                # can kick a static bomb
                continue
            x, y = next_position
            for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
                coming_position = (x + dx, y + dy)
                if coming_position == obs["position"]:
                    # cannot come from my position
                    continue
                if not self._on_board(coming_position):
                    # cannot come from out of board
                    continue
                if obs["bomb_life"][coming_position] <= 1:
                    # kick and die
                    continue
                if all([moving_direction[coming_position] == constants.Action.Up,
                        dx == 0,
                        dy == 1]):
                    # coming from below
                    kickable.add(next_position)
                    break
                if all([moving_direction[coming_position] == constants.Action.Down,
                        dx == 0,
                        dy == -1]):
                    # coming from above
                    kickable.add(next_position)
                    break
                if all([moving_direction[coming_position] == constants.Action.Right,
                        dx == -1,
                        dy == 0]):
                    # coming from left
                    kickable.add(next_position)
                    break
                if all([moving_direction[coming_position] == constants.Action.Left,
                        dx == 1,
                        dy == 0]):
                    # coming from right
                    kickable.add(next_position)
                    break

        return kickable
Ejemplo n.º 16
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
Ejemplo n.º 17
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
Ejemplo n.º 18
0
    def _can_break_wood(cls, board, my_position, blast_strength):

        """
        Whether one cay break a wood 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 can break a wood 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_wood(board, position):
                return True
            elif 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_wood(board, position):
                return True
            elif 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_wood(board, position):
                return True
            elif 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_wood(board, position):
                return True
            elif not utility.position_is_passage(board, position):
                # stop searching this direction
                break
        return False
Ejemplo n.º 19
0
    def _kickable_positions(self, obs, moving_direction, consider_agents=True):
        """
        Parameters
        ----------
        obs : dict
            pommerman observation
        """

        if not obs["can_kick"]:
            return set()

        kickable = set()
        # my position
        x, y = obs["position"]

        # Find neigoboring positions around me
        on_board_next_positions = list()
        for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            next_position = (x + dx, y + dy)
            if self._on_board(next_position):
                on_board_next_positions.append(next_position)

        # Check if can kick a static bomb
        for next_position in on_board_next_positions:
            if obs["board"][next_position] != constants.Item.Bomb.value:
                # not a bomb
                continue
            if moving_direction[next_position] is not None:
                # moving
                continue
            if obs["bomb_life"][next_position] <= 1:
                # kick and die
                continue
            following_position = (2 * next_position[0] - x,
                                  2 * next_position[1] - y)
            if not self._on_board(following_position):
                # cannot kick to that direction
                continue
            if not utility.position_is_passage(obs["board"],
                                               following_position):
                # cannot kick to that direction
                continue
            might_blocked = False
            if consider_agents:
                # neighboring agent might block (or change the direction) immediately
                for dx, dy in [(-1, -1), (1, -1), (-1, 1), (1, 1)]:
                    neighboring_position = (x + dx, y + dy)
                    if not self._on_board(neighboring_position):
                        continue
                    if np.sum(
                            np.abs(
                                np.array(neighboring_position) -
                                np.array(next_position))) != 1:
                        continue
                    if utility.position_is_agent(obs["board"],
                                                 neighboring_position):
                        print("agent is blocking at", neighboring_position)
                        might_blocked = True
                        break
                if might_blocked:
                    continue
                for dx, dy in [(-1, -1), (1, -1), (-1, 1), (1, 1)]:
                    neighboring_position = (next_position[0] + dx,
                                            next_position[1] + dy)
                    if not self._on_board(neighboring_position):
                        continue
                    if np.sum(
                            np.abs(
                                np.array(neighboring_position) -
                                np.array(following_position))) != 1:
                        continue
                    if utility.position_is_agent(obs["board"],
                                                 neighboring_position):
                        print("agent is blocking at", neighboring_position)
                        might_blocked = True
                        break
                if might_blocked:
                    continue
            print("can kick a static bomb at", next_position)
            kickable.add(next_position)

        # Check if can kick a moving bomb
        for next_position in on_board_next_positions:
            if next_position in kickable:
                # can kick a static bomb
                continue
            x, y = next_position
            for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
                coming_position = (x + dx, y + dy)
                if coming_position == obs["position"]:
                    # cannot come from my position
                    continue
                if not self._on_board(coming_position):
                    # cannot come from out of board
                    continue
                #if obs["bomb_life"][coming_position] <= 1:
                #    # kick and die
                #    continue
                if all([
                        moving_direction[coming_position] ==
                        constants.Action.Up, dx == 1, dy == 0
                ]):
                    # coming from below
                    print("can kick a moving bomb coming from below at",
                          next_position)
                    kickable.add(next_position)
                    break
                if all([
                        moving_direction[coming_position] ==
                        constants.Action.Down, dx == -1, dy == 0
                ]):
                    # coming from above
                    print("can kick a moving bomb coming from",
                          coming_position, "above to", next_position)
                    kickable.add(next_position)
                    break
                if all([
                        moving_direction[coming_position] ==
                        constants.Action.Right, dx == 0, dy == -1
                ]):
                    # coming from left
                    print("can kick a moving bomb coming from left at",
                          next_position)
                    kickable.add(next_position)
                    break
                if all([
                        moving_direction[coming_position] ==
                        constants.Action.Left, dx == 0, dy == 1
                ]):
                    # coming from right
                    print("can kick a moving bomb coming from right at",
                          next_position)
                    break

        return kickable