Example #1
0
def noop_board_sequence(obs, length):

    """
    Simulate the sequence of boards, assuming agents stay unmoved
    """

    model = ForwardModel()

    # Dummy objects
    actions = [constants.Action.Stop.value] * 4  # agents stay unmoved
    curr_agents = list()  # empty list of Bombers
    curr_items = dict()  # we never know hidden items

    # Prepare initial state
    curr_board = obs["board"]
    
    curr_bombs = list()
    rows, cols = np.where(obs["bomb_life"] > 0)
    for row, col in zip(rows, cols):
        bomber = characters.Bomber()  # dummy owner of the bomb
        position = (row, col)
        life = int(obs["bomb_life"][row][col])
        blast_strength = int(obs["bomb_blast_strength"][row][col])
        moving_direction = None  # TODO: this may be known
        bomb = characters.Bomb(bomber,
                               position,
                               life,
                               blast_strength,
                               moving_direction)
        curr_bombs.append(bomb)
        # overwrite bomb over agent if they overlap
        curr_board[position] = constants.Item.Bomb.value
    
    curr_flames = list()
    rows, cols = np.where(obs["board"] == constants.Item.Flames.value)
    for row, col in zip(rows, cols):
        position = (row, col)
        life = None  # TODO: this may be known
        if life is not None:
            flame = characters.Flame(position, life)
        else:
            flame = characters.Flame(position)
        curr_flames.append(flame)

    # Simulate
    list_boards = [curr_board.copy()]
    for _ in range(length):
        curr_board, _, curr_bombs, _, curr_flames = model.step(actions,
                                                               curr_board,
                                                               curr_agents,
                                                               curr_bombs,
                                                               curr_items,
                                                               curr_flames)
        list_boards.append(curr_board.copy())

    return list_boards
Example #2
0
    def make_bomb_items_two(self, ret):
        bomb_obj_list = []
        for i in ret:
            this_variable_is_useless_id = i['agent']
            for j, agent in enumerate(self.curr_agents):
                if this_variable_is_useless_id == agent.agent_id:
                    this_variable_is_useless = agent
                    break
            bomb_obj_list.append(
                characters.Bomb(agent, i['position'], i['bomb_life'],
                                i['blast_strength'], i['moving_direction']))

        return bomb_obj_list
Example #3
0
    def make_bomb_items(self, ret):
        bomb_obj_list = []

        #FIX THIS LINE OF CODE BELOW
        #IT SEEMS LIKE THE THE VARIABLE IS DECLARED NOT INSTANTIATED
        # this_variable_is_useless = agents.AggressiveAgent()
        this_variable_is_useless = agents.DummyAgent()
        for i in ret:
            bomb_obj_list.append(
                characters.Bomb(this_variable_is_useless, i['position'],
                                i['bomb_life'], i['blast_strength'],
                                i['moving_direction']))

        return bomb_obj_list
Example #4
0
    def set_json_info(self):
        """Sets the game state as the init_game_state."""
        board_size = int(self._init_game_state['board_size'])
        self._board_size = board_size
        self._step_count = int(self._init_game_state['step_count'])

        board_array = json.loads(self._init_game_state['board'])
        self._board = np.ones((board_size, board_size)).astype(np.uint8)
        self._board *= constants.Item.Passage.value
        for x in range(self._board_size):
            for y in range(self._board_size):
                self._board[x, y] = board_array[x][y]

        self._items = {}
        item_array = json.loads(self._init_game_state['items'])
        for i in item_array:
            self._items[tuple(i[0])] = i[1]

        agent_array = json.loads(self._init_game_state['agents'])
        for a in agent_array:
            agent = next(x for x in self._agents \
                         if x.agent_id == a['agent_id'])
            agent.set_start_position((a['position'][0], a['position'][1]))
            agent.reset(int(a['ammo']), bool(a['is_alive']),
                        int(a['blast_strength']), bool(a['can_kick']))

        self._bombs = []
        bomb_array = json.loads(self._init_game_state['bombs'])
        for b in bomb_array:
            bomber = next(x for x in self._agents \
                          if x.agent_id == b['bomber_id'])
            moving_direction = b['moving_direction']
            if moving_direction is not None:
                moving_direction = constants.Action(moving_direction)
            self._bombs.append(
                characters.Bomb(bomber, tuple(b['position']), int(b['life']),
                                int(b['blast_strength']), moving_direction))

        self._flames = []
        flame_array = json.loads(self._init_game_state['flames'])
        for f in flame_array:
            self._flames.append(
                characters.Flame(tuple(f['position']), f['life']))
Example #5
0
def get_gamedata(gamestate, game_type):
    game_data = env_simulator.GameData()
    game_data.board_size = gamestate['board_size']
    game_data.step_count = gamestate['step_count'] - 1
    game_data.max_steps = 800
    game_data.game_type = game_type
    game_data.simulation_bomb_life = None

    # board
    game_data.board = gamestate['board']
    # items
    game_data.items = {}
    # agents
    game_data.agents = []
    for a in gamestate['agents']:
        id = a['agent_id']
        board_id = id + 10
        agent = characters.Bomber(id, game_data.game_type)
        agent.set_start_position(get_position(game_data.board, board_id, True))
        agent.reset(a['ammo'], a['is_alive'], a['blast_strength'],
                    a['can_kick'])
        game_data.agents.append(agent)

    # bombs
    game_data.bombs = []
    for b in gamestate['bombs']:
        bomb = characters.Bomb(**b)
        game_data.bombs.append(bomb)

    # flames
    game_data.flames = []
    for f in gamestate['flames']:
        flame = characters.Flame(**f)
        game_data.flames.append(flame)

    # done
    game_data.done = forward_model.ForwardModel.get_done(
        game_data.agents, game_data.step_count, game_data.max_steps,
        game_data.game_type, None)

    return game_data
Example #6
0
    def _get_survivable_actions(self, survivable, obs, curr_bombs, curr_flames):

        my_position = obs["position"]
        my_blast_strength = obs["blast_strength"]

        # is_survivable[action]: whether survivable with action
        is_survivable = defaultdict(bool)
        x, y = my_position

        if (x + 1, y) in survivable[1]:
            is_survivable[constants.Action.Down] = True

        if (x - 1, y) in survivable[1]:
            is_survivable[constants.Action.Up] = True

        if (x, y + 1) in survivable[1]:
            is_survivable[constants.Action.Right] = True

        if (x, y - 1) in survivable[1]:
            is_survivable[constants.Action.Left] = True

        if (x, y) in survivable[1]:
            is_survivable[constants.Action.Stop] = True

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

        # If I have at least one bomb, no bomb in my position,
        # and the position is safe
        # then consider what happens if I lay a bomb
        if all([obs["ammo"] > 0,
                obs["bomb_life"][my_position] == 0,
                is_survivable[constants.Action.Stop],
                sum(is_survivable.values()) > 1]):

            board_with_bomb = deepcopy(obs["board"])
            curr_bombs_with_bomb = deepcopy(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,
                                       curr_flames,
                                       self._search_range,
                                       my_position)
            survivable_with_bomb, prev_bomb \
                = self._search_time_expanded_network(list_boards_with_bomb,
                                                     my_position)

            if my_position in survivable_with_bomb[1]:
                is_survivable[constants.Action.Bomb] = True
        else:
            survivable_with_bomb = None
            list_boards_with_bomb = None

        return is_survivable, survivable_with_bomb
Example #7
0
    def _get_bombs(self, obs, prev_bomb_life):

        """
        Summarize information about bombs

        Parameters
        ----------
        obs : dict
            pommerman observation
        prev_bomb_life : array
            remaining life of bombs at the previous step

        Return
        ------
        curr_bombs : list
            list of bombs
        moving_direction : array
            array of moving direction of bombs
            moving_direction[position] : direction of bomb at position
        bomb_life : array
            Copy the remaining life of bombs for the next step
        """

        # Prepare information about moving bombs

        # diff = 0 if no bomb -> no bomb
        # diff = 1 if the remaining life of a bomb is decremented
        # diff = -9 if no bomb -> bomb
        diff = prev_bomb_life - obs["bomb_life"]

        moving = (diff != 0) * (diff != 1) * (diff != -9)

        # move_from: previous positions of moving bombs
        rows, cols = np.where(moving * (diff > 0))
        move_from = [position for position in zip(rows, cols)]

        # move_to: current positions of moving bombs
        rows, cols = np.where(moving * (diff < 0))
        move_to = [position for position in zip(rows, cols)]

        curr_bombs = list()
        rows, cols = np.where(obs["bomb_life"] > 0)
        moving_direction = np.full(self.board_shape, None)
        for position in zip(rows, cols):
            this_bomb_life = obs["bomb_life"][position]
            if position in move_to:
                # then the bomb is moving, so find the moving direction
                for prev_position in move_from:
                    if prev_bomb_life[prev_position] != this_bomb_life + 1:
                        # the previous life of the bomb at the previous position
                        # must be +1 of the life of this bomb
                        continue
                    dx = position[0] - prev_position[0]
                    dy = position[1] - prev_position[1]
                    if abs(dx) + abs(dy) != 1:
                        # the previous position must be 1 manhattan distance
                        # from this position
                        continue
                    moving_direction[position] = self._get_direction(prev_position,
                                                                     position)
                    # TODO: there might be multiple possibilities of
                    # where the bomb came from
                    break
            bomb = characters.Bomb(characters.Bomber(),  # dummy owner of the bomb
                                   position,
                                   this_bomb_life,
                                   int(obs["bomb_blast_strength"][position]),
                                   moving_direction[position])
            curr_bombs.append(bomb)

        return curr_bombs, moving_direction, obs["bomb_life"].copy()
Example #8
0
    def act(self, obs, action_space, info):

        #
        # Definitions
        #

        self._search_range = 10

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

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

        #
        # Understand current situation
        #

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

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

        # Simulation assuming enemies move

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

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

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

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

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

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

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

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

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

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

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

        if len(survivable_actions) == 0:

            print("Must die")
            return None

        elif len(survivable_actions) == 1:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # kick
        if len(kickable) > 0:

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

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

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

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

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

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

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

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

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

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

        #
        # Random action
        #
        action = random.choice(survivable_actions)
        print("Random action", action)
        return action.value
Example #9
0
    def _get_bombs(self, board, bomb_blast_strength, prev_bomb_blast_strength,
                   bomb_life, prev_bomb_life):
        """
        Summarize information about bombs

        Parameters
        ----------
        board : array
        bomb_blast_strength : array
        bomb_life : array
        prev_bomb_life : array
            remaining life of bombs at the previous step

        Return
        ------
        curr_bombs : list
            list of bombs
        moving_direction : array
            array of moving direction of bombs
            moving_direction[position] : direction of bomb at position
        bomb_life : array
            Copy the remaining life of bombs for the next step
        """

        # Keep bombs under fog
        bomb_positions_under_fog = np.where(
            (prev_bomb_life > 1) * (board == constants.Item.Fog.value))
        bomb_life[bomb_positions_under_fog] = prev_bomb_life[
            bomb_positions_under_fog] - 1
        bomb_blast_strength[
            bomb_positions_under_fog] = prev_bomb_blast_strength[
                bomb_positions_under_fog]

        # Prepare information about moving bombs

        # diff = 0 if no bomb -> no bomb
        # diff = 1 if the remaining life of a bomb is decremented
        # diff = -9 if no bomb -> new bomb
        diff = prev_bomb_life - bomb_life

        moving = (diff != 0) * (diff != 1) * (diff != -9)

        # move_from: previous positions of moving bombs
        rows, cols = np.where(moving * (diff > 0))
        move_from = [position for position in zip(rows, cols)]

        # move_to: current positions of moving bombs
        rows, cols = np.where(moving * (diff < 0))
        move_to = [position for position in zip(rows, cols)]

        # TODO : Consider bombs moving into fog
        matched_move_from = [False] * len(move_from)

        curr_bombs = list()
        rows, cols = np.where(bomb_life > 0)
        moving_direction = np.full(self.board_shape, None)
        for position in zip(rows, cols):
            this_bomb_life = bomb_life[position]
            if position in move_to:
                # then the bomb is moving, so find the moving direction
                for i, prev_position in enumerate(move_from):
                    if prev_bomb_life[prev_position] != this_bomb_life + 1:
                        # the previous life of the bomb at the previous position
                        # must be +1 of the life of this bomb
                        continue
                    dx = position[0] - prev_position[0]
                    dy = position[1] - prev_position[1]
                    if abs(dx) + abs(dy) == 2:
                        # this can be a moving bomb whose direction is changed by kick
                        agent_position = (prev_position[0] + dx,
                                          prev_position[1])
                        if utility.position_is_agent(board, agent_position):
                            # the agent must have kicked
                            print("agent must have kicked at", agent_position)
                            moving_direction[position] = self._get_direction(
                                agent_position, position)
                            break
                        agent_position = (prev_position[0],
                                          prev_position[1] + dy)
                        if utility.position_is_agent(board, agent_position):
                            # the agent must have kicked
                            print("agent must have kicked at", agent_position)
                            moving_direction[position] = self._get_direction(
                                agent_position, position)
                            break
                    if abs(dx) + abs(dy) != 1:
                        # the previous position must be 1 manhattan distance
                        # from this position
                        continue
                    moving_direction[position] = self._get_direction(
                        prev_position, position)
                    # TODO: there might be multiple possibilities of
                    # where the bomb came from
                    matched_move_from[i] = True
                    break
            bomb = characters.Bomb(
                characters.Bomber(),  # dummy owner of the bomb
                position,
                this_bomb_life,
                int(bomb_blast_strength[position]),
                moving_direction[position])
            curr_bombs.append(bomb)

        return curr_bombs, moving_direction
Example #10
0
    def act(self, obs, action_space, info):

        #
        # Definitions
        #

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

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

        survivable_steps = defaultdict(int)

        #
        # survivable tree in standard case
        #

        list_boards_no_kick = deepcopy(info["list_boards_no_move"])

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

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

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

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

        #
        # survivable tree if I lay bomb
        #

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

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

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

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

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

        print("survivable steps")
        print(survivable_steps)

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

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

            return best_action.value

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

        #
        # survivable tree if I kick
        #

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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