Example #1
0
def pick_safest_move_using_dynamic_search_depth(battles):
    """
    Dynamically decides how far to look into the game.

    This requires a strong computer to be able to search 3/4 turns ahead.
    Using a pypy interpreter will also result in better performance.

    """
    all_scores = dict()
    num_battles = len(battles)

    if num_battles > 1:
        search_depth = 2

        for i, b in enumerate(battles):
            state = b.create_state()
            mutator = StateMutator(state)
            user_options, opponent_options = b.get_all_options()
            logger.debug("Searching through the state: {}".format(mutator.state))
            scores = get_payoff_matrix(mutator, user_options, opponent_options, depth=search_depth, prune=True)
            prefixed_scores = prefix_opponent_move(scores, str(i))
            all_scores = {**all_scores, **prefixed_scores}

    elif num_battles == 1:
        search_depth = 3

        b = battles[0]
        state = b.create_state()
        mutator = StateMutator(state)
        user_options, opponent_options = b.get_all_options()

        num_user_options = len(user_options)
        num_opponent_options = len(opponent_options)
        options_product = num_user_options * num_opponent_options
        if options_product < 20 and num_user_options > 1 and num_opponent_options > 1:
            logger.debug("Low options product, looking an additional depth")
            search_depth += 1

        logger.debug("Searching through the state: {}".format(mutator.state))
        logger.debug("Options Product: {}".format(options_product))
        logger.debug("My Options: {}".format(user_options))
        logger.debug("Opponent Options: {}".format(opponent_options))
        logger.debug("Search depth: {}".format(search_depth))
        all_scores = get_payoff_matrix(mutator, user_options, opponent_options, depth=search_depth, prune=True)

    else:
        raise ValueError("less than 1 battle?: {}".format(battles))

    decision, payoff = pick_safest(all_scores, remove_guaranteed=True)
    bot_choice = decision[0]
    logger.debug("Safest: {}, {}".format(bot_choice, payoff))
    logger.debug("Depth: {}".format(search_depth))
    return bot_choice
Example #2
0
    def find_best_move(self):
        battles = self.prepare_battles()
        if len(battles) > 7:
            logger.debug(
                "Not enough is known about the opponent's active pokemon - falling back to safest decision making"
            )
            battles = self.prepare_battles(join_moves_together=True)
            decision = pick_safest_move_from_battles(battles)
        else:
            list_of_payoffs = list()
            for b in battles:
                state = b.create_state()
                mutator = StateMutator(state)
                logger.debug("Attempting to find best move from: {}".format(
                    mutator.state))
                user_options, opponent_options = b.get_all_options()
                scores = get_payoff_matrix(mutator,
                                           user_options,
                                           opponent_options,
                                           prune=False)
                list_of_payoffs.append(scores)

            decision = pick_move_in_equilibrium_from_multiple_score_lookups(
                list_of_payoffs)

        return format_decision(self, decision)
 def setUp(self):
     self.state = State(
         Side(
             Pokemon.from_state_pokemon_dict(StatePokemon("pikachu", 100).to_dict()),
             {
                 "rattata": Pokemon.from_state_pokemon_dict(StatePokemon("rattata", 100).to_dict()),
                 "charmander": Pokemon.from_state_pokemon_dict(StatePokemon("charmander", 100).to_dict()),
                 "squirtle": Pokemon.from_state_pokemon_dict(StatePokemon("squirtle", 100).to_dict()),
                 "bulbasaur": Pokemon.from_state_pokemon_dict(StatePokemon("bulbasaur", 100).to_dict()),
                 "pidgey": Pokemon.from_state_pokemon_dict(StatePokemon("pidgey", 100).to_dict())
             },
             (0, 0),
             defaultdict(lambda: 0)
         ),
         Side(
             Pokemon.from_state_pokemon_dict(StatePokemon("pikachu", 100).to_dict()),
             {
                 "rattata": Pokemon.from_state_pokemon_dict(StatePokemon("rattata", 100).to_dict()),
                 "charmander": Pokemon.from_state_pokemon_dict(StatePokemon("charmander", 100).to_dict()),
                 "squirtle": Pokemon.from_state_pokemon_dict(StatePokemon("squirtle", 100).to_dict()),
                 "bulbasaur": Pokemon.from_state_pokemon_dict(StatePokemon("bulbasaur", 100).to_dict()),
                 "pidgey": Pokemon.from_state_pokemon_dict(StatePokemon("pidgey", 100).to_dict())
             },
             (0, 0),
             defaultdict(lambda: 0)
         ),
         None,
         None,
         False
     )
     self.mutator = StateMutator(self.state)
Example #4
0
    def pick_bfs_move(self, battle):

        state = battle.create_state()
        mutator = StateMutator(state)
        user_options, opponent_options = battle.get_all_options()
        logger.debug("Attempting to find best move from: {}".format(mutator.state))

        is_winning = self.is_winning(state)

        # Builds a tree to search for opponent's moves, assume opponent picks safest
        scores = get_payoff_matrix(mutator, user_options, opponent_options, is_winning, depth=3, prune=True)

        logger.debug(f"\nScores: {scores}")

        move_string = "Aggresive"

        if is_winning:
            decision, payoff = self.pick_safest(scores)
            move_string = "Safest"
        else:
            decision, payoff = self.pick_aggresive(scores)

        bot_choice = decision[0]
        logger.debug(f"{move_string}: {bot_choice}, {payoff}")
        return bot_choice
Example #5
0
def calculate_value(state, transition, depth):
    """
    Takes in the current state, a specific transition (pair of our move and opponent move), 
    and estimates the value associated with applying this transition at current search depth, 
    taking into account the probability of this transition occuring
    """
    state_instructions = get_all_state_instructions(StateMutator(state),
                                                    transition[0],
                                                    transition[1])

    total_value = 0

    for instruction in state_instructions:
        mutator = StateMutator(copy.deepcopy(state))
        mutator.apply(instruction.instructions)
        value = expectiminimax(mutator.state, depth)
        total_value += value * instruction.percentage

    return total_value
Example #6
0
 def generate_next_child(self, chosen_transition):
     """
     Generates a child node by choosing the most likely mutation instructions
     (instructions are potential results of a transition) of the given transition.
     Params:
         - chosen_transition: the pair of (our move : opponent move) to apply
     """
     mutator = StateMutator(copy.deepcopy(self.state))
     state_instructions = get_all_state_instructions(
         mutator, chosen_transition[0], chosen_transition[1])
     choice = max(state_instructions,
                  key=lambda i: i.percentage).instructions
     mutator.apply(choice)
     return MonteCarloTree(mutator.state)
Example #7
0
def pick_safest_move_from_battles(battles):
    all_scores = dict()
    for i, b in enumerate(battles):
        state = b.create_state()
        mutator = StateMutator(state)
        user_options, opponent_options = b.get_all_options()
        logger.debug("Searching through the state: {}".format(mutator.state))
        scores = get_payoff_matrix(mutator, user_options, opponent_options, depth=config.search_depth, prune=True)

        prefixed_scores = prefix_opponent_move(scores, str(i))
        all_scores = {**all_scores, **prefixed_scores}

    decision, payoff = pick_safest(all_scores, remove_guaranteed=True)
    bot_choice = decision[0]
    logger.debug("Safest: {}, {}".format(bot_choice, payoff))
    return bot_choice
Example #8
0
def pick_safest_move_from_battles(battles):
    all_scores = dict()
    for i, b in enumerate(battles):
        state = b.create_state()
        mutator = StateMutator(state)
        user_options, opponent_options = b.get_all_options()
        logger.debug("Attempting to find best move from: {}".format(
            mutator.state))
        scores = get_payoff_matrix(mutator,
                                   user_options,
                                   opponent_options,
                                   prune=True)
        prefixed_scores = prefix_opponent_move(scores, str(i))
        all_scores = {**all_scores, **prefixed_scores}

    decision, payoff = pick_safest(all_scores)
    bot_choice = decision[0]
    logger.debug("Safest: {}, {}".format(bot_choice, payoff))
    return bot_choice
Example #9
0
def make_a_choice(battles):
    # Battles is a list of possible states the opponent's team might be in
    # The list is based on guesses done by the framework, one battle per guess
    # There's always at least one battle
    # The probability of each battle/state can be assumed to be equal

    # Below a battle is transformed into a StateMutator
    # We can apply choices to the StateMutator in order to create new states
    a_battle = battles[0]
    a_state = a_battle.to_object()
    a_mutator = StateMutator(a_state)

    # Fetch possible options for you and your opponent by calling get_all_options on a StateMutator
    # user_options includes using one of your four moves or switching to a remaining Pokémon
    # opponent_options is based on assumptions about what the opponent might be able to do
    user_options, opponent_options = get_all_options(a_mutator)

    # We can evaluate a state using the pre-defined evaluate method
    # The method is already fine-tuned in order to save us some time
    # But you can play around with it by checking out evaluate.py
    a_score = evaluate(a_mutator.state)

    # By picking an option and assuming the opponent's option, we can generate a list of low-level state instructions
    # Because certain moves can lead to several different states (because of randomness), the list of possible instructions might be long
    # Applying one of the possible instructions to the StateMutator mutates the state
    # After evaluating the score of the new state, we might want to reverse the changes and try something else
    all_possible_instructions = get_all_state_instructions(
        a_mutator, user_options[0], opponent_options[0])
    a_mutator.apply(all_possible_instructions[0].instructions)
    a_mutator.reverse(all_possible_instructions[0].instructions)

    # Logging data might be handy
    logger.debug("User's options: {}".format(user_options))
    logger.debug("Opponent's options: {}".format(opponent_options))
    logger.debug("Current state's score: {}".format(a_score))

    # For now, let's just return a random choice
    a_random_choice = random.choice(user_options)
    logger.debug("Move chosen: {}".format(a_random_choice))
    return a_random_choice
Example #10
0
    def random_playout(self, initial_position, depth):
        """
        Random playout of from this node. If max depth is reached then
        the evaluation function of the state is compared against initial_position.
        If the evaluation of the state is better than the initial position, it is
        counted as win, since the bot position was improved.
        """
        self.total += 1

        mutator = StateMutator(copy.deepcopy(self.state))
        while True:
            if depth == MAX_DEPTH:
                if evaluate(mutator.state) >= initial_position:
                    self.wins += 1
                    return True
                else:
                    return False

            winner = mutator.state.battle_is_finished()
            if winner:
                if winner == 1:
                    self.wins += 1
                    return True
                else:
                    return False

            transition = random.choice(get_transitions(mutator.state))
            state_instructions = get_all_state_instructions(
                mutator, transition[0], transition[1])
            possible_instrucitons = [
                i.instructions for i in state_instructions
            ]
            weights = [i.percentage for i in state_instructions]
            choice = random.choices(possible_instrucitons, weights=weights)[0]
            mutator.apply(choice)

            depth += 1
Example #11
0
                    'id': 'dragondance',
                    'disabled': False,
                    'current_pp': 32
                }, {
                    'id': 'earthquake',
                    'disabled': False,
                    'current_pp': 16
                }, {
                    'id': 'bounce',
                    'disabled': False,
                    'current_pp': 8
                }],
                'types': ['water', 'flying'],
                'canMegaEvo':
                False
            }
        },
        'side_conditions': {
            'toxic_count': 0
        },
        'trapped': False
    },
    'weather': None,
    'field': None,
    'trickroom': False,
    'forceSwitch': False,
    'wait': False
})
mutator = StateMutator(state)
state_instructions = get_payoff_matrix(mutator, depth=3)
    def setUp(self):
        self.state = State(
            Side(
                Pokemon.from_state_pokemon_dict(
                    StatePokemon("raichu", 73).to_dict()), {
                        "xatu":
                        Pokemon.from_state_pokemon_dict(
                            StatePokemon("xatu", 81).to_dict()),
                        "starmie":
                        Pokemon.from_state_pokemon_dict(
                            StatePokemon("starmie", 81).to_dict()),
                        "gyarados":
                        Pokemon.from_state_pokemon_dict(
                            StatePokemon("gyarados", 81).to_dict()),
                        "dragonite":
                        Pokemon.from_state_pokemon_dict(
                            StatePokemon("dragonite", 81).to_dict()),
                        "hitmonlee":
                        Pokemon.from_state_pokemon_dict(
                            StatePokemon("hitmonlee", 81).to_dict()),
                    }, defaultdict(lambda: 0), False),
            Side(
                Pokemon.from_state_pokemon_dict(
                    StatePokemon("aromatisse", 81).to_dict()), {
                        "yveltal":
                        Pokemon.from_state_pokemon_dict(
                            StatePokemon("yveltal", 73).to_dict()),
                        "slurpuff":
                        Pokemon.from_state_pokemon_dict(
                            StatePokemon("slurpuff", 73).to_dict()),
                        "victini":
                        Pokemon.from_state_pokemon_dict(
                            StatePokemon("victini", 73).to_dict()),
                        "toxapex":
                        Pokemon.from_state_pokemon_dict(
                            StatePokemon("toxapex", 73).to_dict()),
                        "bronzong":
                        Pokemon.from_state_pokemon_dict(
                            StatePokemon("bronzong", 73).to_dict()),
                    }, defaultdict(lambda: 0), False), None, None, False,
            False, False)

        self.mutator = StateMutator(self.state)

        self.state.self.active.moves = [
            {
                constants.ID: 'tackle',
                constants.DISABLED: False
            },
            {
                constants.ID: 'charm',
                constants.DISABLED: False
            },
            {
                constants.ID: 'growl',
                constants.DISABLED: False
            },
            {
                constants.ID: 'stringshot',
                constants.DISABLED: False
            },
        ]
        self.state.opponent.active.moves = [
            {
                constants.ID: 'tackle',
                constants.DISABLED: False
            },
            {
                constants.ID: 'charm',
                constants.DISABLED: False
            },
            {
                constants.ID: 'growl',
                constants.DISABLED: False
            },
            {
                constants.ID: 'stringshot',
                constants.DISABLED: False
            },
        ]
Example #13
0
    def pick_move_from_battles(self, battles):
        # Only work on current battle
        # In practice the bot can play several at once, for now we simplified to one battle.
        battle = battles[0]
        root = Node("Root")

        state = battle.create_state()
        mutator = StateMutator(state)
        user_options, opponent_options = battle.get_all_options()
        logger.debug("Attempting to find best move from: {}".format(mutator.state))
        #get the scores from the "safest" algorithm provided by the starter code
        scores = get_payoff_matrix(mutator, user_options, opponent_options, depth=2, prune=False)

        # Create tree using payoff matrix from "Safest" algorithm
        checked_moves = {}
        for (myMove, opponentMove), score in scores.items():
            #checked moves keeps track of which nodes have been added to the tree, so we dont duplicate.
            if myMove not in checked_moves:
                child = Node(myMove, root)
                checked_moves[myMove] = child
            grandchild = Node(opponentMove, checked_moves[myMove])
            Node(score, grandchild)

        # a library function that prints our tree for readability.
        for pre, _, node in RenderTree(root):
            print("%s%s" % (pre, node.name))

        myTotalHP = 0.0 # max of 600, 100 points for full hp
        oppTotalHP = 0.0

        # calculate my total hp
        my_pokes = state.self
        # get active pokemon hp if it isn't dead
        if my_pokes.active.maxhp != 0:
            myTotalHP += my_pokes.active.hp / my_pokes.active.maxhp
        # get reserve pokmeons hps
        for p in my_pokes.reserve.values():
            if p.maxhp !=0:
                myTotalHP += p.hp / p.maxhp
        myTotalHP *= 100

        # calculate opp total hp
        opp_pokes = state.opponent
        # get active pokemon hp
        if opp_pokes.active.maxhp != 0:
            oppTotalHP += opp_pokes.active.hp / opp_pokes.active.maxhp
        # get reserve pokmeons hps
        for p in opp_pokes.reserve.values():
            if p.maxhp !=0:
                oppTotalHP += p.hp / p.maxhp
        
        #accounts for the pokemon of opponent that have not been revealed
        unseenPoke = 5-len(opp_pokes.reserve)
        oppTotalHP += unseenPoke
        oppTotalHP *=100

        possibleStatuses = {
            "psn" : .06,
            "frz" : .25,
            "tox" : .19,
            "par" : .16,
            "slp" : .16,
            "brn" : .20,
            None: 0,
        }

        statBuffs = {
            6 : .25,
            5 : .235,
            4 : .22,
            3 : .19,
            2 : .15,
            1 : .08,
            0 : 0,
            -1 : -.08,
            -2 : -.15,
            -3 : -.19,
            -4 : -.22,
            -5 : -.235,
            -6 : -.25,
        }

        # check how many status conditions we have
        myStatuses = 0
        # active pokemon
        myStatuses += possibleStatuses[my_pokes.active.status]
        # reserve pokemon
        for p in my_pokes.reserve.values():
            myStatuses += possibleStatuses[p.status]

        # check how many status conditions opponent has
        opponentStatuses = 0
        # active pokemon
        opponentStatuses += possibleStatuses[opp_pokes.active.status]
        # reserve pokemon
        for p in opp_pokes.reserve.values():
            opponentStatuses += possibleStatuses[p.status]

        status_aggression_multiplier = 1
        status_aggression_modifier = (opponentStatuses - myStatuses) * status_aggression_multiplier
        print(f"Status modifier:{status_aggression_modifier}")

        # Stat Buffs
        # check how many stat boosts/nerfs we have
        myBuffs = 0
        # active pokemon
        myBuffs += statBuffs[my_pokes.active.accuracy_boost]
        myBuffs += statBuffs[my_pokes.active.attack_boost]
        myBuffs += statBuffs[my_pokes.active.defense_boost]
        myBuffs += statBuffs[my_pokes.active.evasion_boost]
        myBuffs += statBuffs[my_pokes.active.special_attack_boost]
        myBuffs += statBuffs[my_pokes.active.special_defense_boost]
        myBuffs += statBuffs[my_pokes.active.speed_boost]
        
        # check how many stat boosts/nerfs opponent has
        oppBuffs = 0
        # active pokemon
        oppBuffs += statBuffs[opp_pokes.active.accuracy_boost]
        oppBuffs += statBuffs[opp_pokes.active.attack_boost]
        oppBuffs += statBuffs[opp_pokes.active.defense_boost]
        oppBuffs += statBuffs[opp_pokes.active.evasion_boost]
        oppBuffs += statBuffs[opp_pokes.active.special_attack_boost]
        oppBuffs += statBuffs[opp_pokes.active.special_defense_boost]
        oppBuffs += statBuffs[opp_pokes.active.speed_boost]

        buff_aggression_multiplier = 1
        buff_aggression_modifier = (myBuffs - oppBuffs) * buff_aggression_multiplier
        print(f"Buff modifier:{buff_aggression_modifier}")

        safety = (3 + status_aggression_modifier + buff_aggression_modifier) * myTotalHP/oppTotalHP
        if safety < 0:
            print("WARNING: safety constant is less than 0, changing to 0.1")
            safety = 0.1
        print(f"bot will play with safety constant of {safety}")
        bot_choice = self.aggressive_pick(root,safety)
        print(f"choice: {bot_choice}")
        print(f"the safest pick was {self.safest_pick(root)}")

        print("Choice: {}".format(bot_choice))
        return bot_choice