示例#1
0
def get_move_combination_scores(mutator,
                                depth=2,
                                previous_moves=tuple(),
                                previous_instructions=()):
    """
    :param mutator: a StateMutator object representing the state of the battle
    :param depth: the remaining depth before the state is evaluated
    :param previous_moves: any previous moves that happened prior to this call
    :param previous_instructions: any previous instructions that were applied to the state before this call
    :return: a dictionary representing the potential move combinations and their associated scores
    """
    depth -= 1
    if battle_is_over(mutator.state):
        return {
            (constants.DO_NOTHING_MOVE, constants.DO_NOTHING_MOVE):
            evaluate(mutator.state)
        }

    user_options, opponent_options = get_all_options(mutator)

    # if the battle is not over, but the opponent has no moves - we want to return the user options as moves
    # this is a special case in a random battle where the opponent's pokemon has fainted, but the opponent still
    # has reserves left that are unseen
    if opponent_options == [constants.DO_NOTHING_MOVE
                            ] and mutator.state.opponent.active.hp == 0:
        return {(user_option, constants.DO_NOTHING_MOVE):
                evaluate(mutator.state)
                for user_option in user_options}

    state_scores = dict()
    for i, user_move in enumerate(user_options):
        for j, opponent_move in enumerate(opponent_options):
            score = 0
            state_instructions = get_all_state_instructions(
                mutator, user_move, opponent_move)
            if depth == 0:
                for instructions in state_instructions:
                    mutator.apply(instructions.instructions)
                    t_score = evaluate(mutator.state)
                    score += (t_score * instructions.percentage)
                    mutator.reverse(instructions.instructions)

            else:
                for instructions in state_instructions:
                    this_percentage = instructions.percentage
                    mutator.apply(instructions.instructions)
                    safest = pick_safest(
                        get_move_combination_scores(
                            mutator,
                            depth,
                            previous_moves=previous_moves +
                            (user_move, opponent_move),
                            previous_instructions=previous_instructions +
                            tuple(instructions.instructions)))
                    score += safest[1] * this_percentage
                    mutator.reverse(instructions.instructions)

            state_scores[(user_move, opponent_move)] = score

    return state_scores
def get_payoff_matrix(mutator, depth=2, forced_options=None, prune=None):
    """
    :param mutator: a StateMutator object representing the state of the battle
    :param depth: the remaining depth before the state is evaluated
    :param forced_options: options that can be forced instead of using `get_all_options`
    :param prune: specify whether or not to prune the tree
    :return: a dictionary representing the potential move combinations and their associated scores
    """
    if prune is None:
        prune = True

    winner = battle_is_over(mutator.state)
    if winner:
        return {
            (constants.DO_NOTHING_MOVE, constants.DO_NOTHING_MOVE):
            evaluate(mutator.state) + WON_BATTLE * depth * winner
        }

    depth -= 1
    if forced_options:
        user_options, opponent_options = forced_options
    else:
        user_options, opponent_options = get_all_options(mutator)

    # if the battle is not over, but the opponent has no moves - we want to return the user options as moves
    # this is a special case in a random battle where the opponent's pokemon has fainted, but the opponent still
    # has reserves left that are unseen
    if opponent_options == [constants.DO_NOTHING_MOVE
                            ] and mutator.state.opponent.active.hp == 0:
        return {(user_option, constants.DO_NOTHING_MOVE):
                evaluate(mutator.state)
                for user_option in user_options}

    state_scores = dict()

    best_score = float('-inf')
    for i, user_move in enumerate(user_options):
        worst_score_for_this_row = float('inf')
        skip = False

        # opponent_options can change during the loop
        # using opponent_options[:] makes a copy when iterating to ensure no funny-business
        for j, opponent_move in enumerate(opponent_options[:]):
            if skip:
                state_scores[(user_move, opponent_move)] = float('nan')
                continue

            score = 0
            state_instructions = get_all_state_instructions(
                mutator, user_move, opponent_move)
            if depth == 0:
                for instructions in state_instructions:
                    mutator.apply(instructions.instructions)
                    t_score = evaluate(mutator.state)
                    score += (t_score * instructions.percentage)
                    mutator.reverse(instructions.instructions)

            else:
                for instructions in state_instructions:
                    this_percentage = instructions.percentage
                    mutator.apply(instructions.instructions)
                    safest = pick_safest(
                        get_payoff_matrix(mutator, depth, prune=prune))
                    score += safest[1] * this_percentage
                    mutator.reverse(instructions.instructions)

            state_scores[(user_move, opponent_move)] = score

            if score < worst_score_for_this_row:
                worst_score_for_this_row = score

            if prune and score < best_score:
                skip = True

                # MOST of the time in pokemon, an opponent's move that causes a prune will cause a prune elsewhere
                # move this item to the front of the list to prune faster
                opponent_options = move_item_to_front_of_list(
                    opponent_options, opponent_move)

        if worst_score_for_this_row > best_score:
            best_score = worst_score_for_this_row

    return state_scores
示例#3
0
 def test_returns_false_when_only_reserve_are_dead_for_opponent(self):
     for pkmn in self.state.opponent.reserve.values():
         pkmn.hp = 0
     self.assertFalse(battle_is_over(self.state))
示例#4
0
 def test_returns_false_when_only_active_is_dead_for_opponent(self):
     self.state.opponent.active.hp = 0
     self.assertFalse(battle_is_over(self.state))
示例#5
0
 def test_returns_false_when_all_pokemon_are_alive_for_opponent(self):
     self.assertFalse(battle_is_over(self.state))
示例#6
0
    def test_returns_true_when_all_pokemon_for_opponent_are_dead(self):
        self.state.opponent.active.hp = 0
        for pkmn in self.state.opponent.reserve.values():
            pkmn.hp = 0

        self.assertTrue(battle_is_over(self.state))