Пример #1
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)
Пример #2
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
Пример #3
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
Пример #4
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
class TestStatemutator(unittest.TestCase):
    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())
                    }, 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())
                    }, defaultdict(lambda: 0)), None, None, False)
        self.mutator = StateMutator(self.state)

    def test_switch_instruction_replaces_active(self):
        instruction = (constants.MUTATOR_SWITCH, constants.SELF, "pikachu",
                       "rattata")

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual("rattata", self.state.self.active.id)

    def test_switch_instruction_replaces_active_for_opponent(self):
        instruction = (constants.MUTATOR_SWITCH, constants.OPPONENT, "pikachu",
                       "rattata")

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual("rattata", self.state.opponent.active.id)

    def test_switch_instruction_places_active_into_reserve(self):
        instruction = (constants.MUTATOR_SWITCH, constants.SELF, "pikachu",
                       "rattata")

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        try:
            self.state.self.reserve["pikachu"]
        except KeyError:
            self.fail("`pikachu` is not in `self.reserve`")

    def test_reverse_switch_instruction_replaces_active(self):
        instruction = (constants.MUTATOR_SWITCH, constants.SELF, "rattata",
                       "pikachu")

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual("rattata", self.state.self.active.id)

    def test_apply_volatile_status_properly_applies_status(self):
        instruction = (constants.MUTATOR_APPLY_VOLATILE_STATUS, constants.SELF,
                       "leechseed")

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertIn("leechseed", self.state.self.active.volatile_status)

    def test_reverse_volatile_status_properly_removes_status(self):
        self.state.self.active.volatile_status.add("leechseed")
        instruction = (constants.MUTATOR_APPLY_VOLATILE_STATUS, constants.SELF,
                       "leechseed")

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertNotIn("leechseed", self.state.self.active.volatile_status)

    def test_damage_is_properly_applied(self):
        instruction = (constants.MUTATOR_DAMAGE, constants.SELF, 50)

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        damage_taken = self.state.self.active.maxhp - self.state.self.active.hp

        self.assertEqual(50, damage_taken)

    def test_damage_is_properly_reversed(self):
        self.state.self.active.hp -= 50
        instruction = (constants.MUTATOR_DAMAGE, constants.SELF, 50)

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        damage_taken = self.state.self.active.maxhp - self.state.self.active.hp

        self.assertEqual(0, damage_taken)

    def test_healing_is_properly_applied(self):
        self.state.self.active.hp -= 50
        instruction = (constants.MUTATOR_HEAL, constants.SELF, 50)

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        damage_taken = self.state.self.active.maxhp - self.state.self.active.hp

        self.assertEqual(0, damage_taken)

    def test_healing_is_properly_reversed(self):
        instruction = (constants.MUTATOR_HEAL, constants.SELF, 50)

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        damage_taken = self.state.self.active.maxhp - self.state.self.active.hp

        self.assertEqual(50, damage_taken)

    def test_boost_is_properly_applied(self):
        instruction = (constants.MUTATOR_BOOST, constants.SELF,
                       constants.ATTACK, 1)

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual(1, self.state.self.active.attack_boost)

    def test_boost_is_properly_reversed(self):
        self.state.self.active.attack_boost = 1
        instruction = (constants.MUTATOR_BOOST, constants.SELF,
                       constants.ATTACK, 1)

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(0, self.state.self.active.attack_boost)

    def test_boost_is_properly_reversed_when_a_boost_previously_existed(self):
        # the pokemon had attack_boost=2 before
        # it boosted to 4, and now it is being reversed
        self.state.self.active.attack_boost = 4
        instruction = (constants.MUTATOR_BOOST, constants.SELF,
                       constants.ATTACK, 2)

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(2, self.state.self.active.attack_boost)

    def test_unboost_is_properly_applied(self):
        instruction = (constants.MUTATOR_UNBOOST, constants.SELF,
                       constants.ATTACK, 1)

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual(-1, self.state.self.active.attack_boost)

    def test_unboost_is_properly_reversed(self):
        self.state.self.active.attack_boost = -1
        instruction = (constants.MUTATOR_UNBOOST, constants.SELF,
                       constants.ATTACK, 1)

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(0, self.state.self.active.attack_boost)

    def test_apply_status_properly_applies_status(self):
        instruction = (constants.MUTATOR_APPLY_STATUS, constants.SELF,
                       constants.BURN)

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual(constants.BURN, self.state.self.active.status)

    def test_apply_status_is_properly_reversed(self):
        self.state.self.active.status = constants.BURN
        instruction = (constants.MUTATOR_APPLY_STATUS, constants.SELF,
                       constants.BURN)

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(None, self.state.self.active.status)

    def test_remove_status_properly_removes_status(self):
        self.state.self.active.status = constants.BURN
        instruction = (constants.MUTATOR_REMOVE_STATUS, constants.SELF,
                       constants.BURN)

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual(None, self.state.self.active.status)

    def test_remove_status_is_properly_reversed(self):
        instruction = (constants.MUTATOR_REMOVE_STATUS, constants.SELF,
                       constants.BURN)

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(constants.BURN, self.state.self.active.status)

    def test_side_start_is_properly_applied(self):
        instruction = (constants.MUTATOR_SIDE_START, constants.SELF,
                       constants.STEALTH_ROCK, 1)

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual(
            1, self.state.self.side_conditions[constants.STEALTH_ROCK])

    def test_side_start_is_properly_reversed(self):
        self.state.self.side_conditions[constants.STEALTH_ROCK] = 1
        instruction = (constants.MUTATOR_SIDE_START, constants.SELF,
                       constants.STEALTH_ROCK, 1)

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(
            0, self.state.self.side_conditions[constants.STEALTH_ROCK])

    def test_side_end_is_properly_applied(self):
        self.state.self.side_conditions[constants.STEALTH_ROCK] = 2
        instruction = (constants.MUTATOR_SIDE_END, constants.SELF,
                       constants.STEALTH_ROCK, 2)

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual(
            0, self.state.self.side_conditions[constants.STEALTH_ROCK])

    def test_side_end_is_properly_reversed(self):
        instruction = (constants.MUTATOR_SIDE_END, constants.SELF,
                       constants.STEALTH_ROCK, 2)

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(
            2, self.state.self.side_conditions[constants.STEALTH_ROCK])

    def test_disable_move(self):
        move = {'id': 'return', 'disabled': False, 'current_pp': 16}
        self.state.self.active.moves = [move]
        instruction = (
            constants.MUTATOR_DISABLE_MOVE,
            constants.SELF,
            "return",
        )

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertTrue(move[constants.DISABLED])

    def test_reverse_disable_move(self):
        move = {'id': 'return', 'disabled': True, 'current_pp': 16}
        self.state.self.active.moves = [move]
        instruction = (
            constants.MUTATOR_DISABLE_MOVE,
            constants.SELF,
            "return",
        )

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertFalse(move[constants.DISABLED])

    def test_enable_move(self):
        move = {'id': 'return', 'disabled': True, 'current_pp': 16}
        self.state.self.active.moves = [move]
        instruction = (
            constants.MUTATOR_ENABLE_MOVE,
            constants.SELF,
            "return",
        )

        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertFalse(move[constants.DISABLED])

    def test_reverse_enable_move(self):
        move = {'id': 'return', 'disabled': False, 'current_pp': 16}
        self.state.self.active.moves = [move]
        instruction = (
            constants.MUTATOR_ENABLE_MOVE,
            constants.SELF,
            "return",
        )

        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertTrue(move[constants.DISABLED])

    def test_setting_weather(self):
        self.state.weather = None
        instruction = (constants.MUTATOR_WEATHER_START, constants.SUN, None)
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual(constants.SUN, self.state.weather)

    def test_setting_weather_when_previous_weather_exists(self):
        self.state.weather = constants.RAIN
        instruction = (constants.MUTATOR_WEATHER_START, constants.SUN,
                       constants.RAIN)
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual(constants.SUN, self.state.weather)

    def test_reversing_weather_when_previous_weather_exists(self):
        self.state.weather = constants.SUN
        instruction = (constants.MUTATOR_WEATHER_START, constants.SUN,
                       constants.RAIN)
        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(constants.RAIN, self.state.weather)

    def test_reverse_setting_weather(self):
        self.state.weather = constants.SUN
        instruction = (constants.MUTATOR_WEATHER_START, constants.SUN, None)
        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(None, self.state.weather)

    def test_apply_and_reverse_setting_weather_works(self):
        self.state.weather = None
        instruction = (constants.MUTATOR_WEATHER_START, constants.SUN, None)
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)
        if not self.state.weather == constants.SUN:
            self.fail("Sun was not set")

        self.mutator.reverse(list_of_instructions)

        self.assertEqual(None, self.state.weather)

    def test_apply_and_reverse_setting_weather_works_with_weather_previously_existing(
            self):
        self.state.weather = constants.RAIN
        instruction = (constants.MUTATOR_WEATHER_START, constants.SUN,
                       constants.RAIN)
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)
        if not self.state.weather == constants.SUN:
            self.fail("Sun was not set")

        self.mutator.reverse(list_of_instructions)

        self.assertEqual(constants.RAIN, self.state.weather)

    def test_setting_field(self):
        self.state.field = None
        instruction = (constants.MUTATOR_FIELD_START,
                       constants.PSYCHIC_TERRAIN, None)
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual(constants.PSYCHIC_TERRAIN, self.state.field)

    def test_reverse_setting_field(self):
        self.state.field = constants.PSYCHIC_TERRAIN
        instruction = (constants.MUTATOR_FIELD_START,
                       constants.PSYCHIC_TERRAIN, None)
        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(None, self.state.field)

    def test_apply_and_reverse_field(self):
        self.state.field = None
        instruction = (constants.MUTATOR_FIELD_START,
                       constants.PSYCHIC_TERRAIN, None)
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)
        if self.state.field != constants.PSYCHIC_TERRAIN:
            self.fail("Terrain was not set")
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(None, self.state.field)

    def test_apply_and_reverse_field_when_previous_field_exists(self):
        self.state.field = constants.GRASSY_TERRAIN
        instruction = (constants.MUTATOR_FIELD_START,
                       constants.PSYCHIC_TERRAIN, constants.GRASSY_TERRAIN)
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)
        if self.state.field != constants.PSYCHIC_TERRAIN:
            self.fail("Terrain was not set")
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(constants.GRASSY_TERRAIN, self.state.field)

    def test_end_active_field(self):
        self.state.field = constants.GRASSY_TERRAIN
        instruction = (constants.MUTATOR_FIELD_END, constants.GRASSY_TERRAIN)
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)
        if self.state.field is not None:
            self.fail("Terrain was not removed")
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(constants.GRASSY_TERRAIN, self.state.field)

    def test_reversing_end_active_field(self):
        self.state.field = None
        instruction = (constants.MUTATOR_FIELD_END, constants.GRASSY_TERRAIN)
        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)
        if self.state.field != constants.GRASSY_TERRAIN:
            self.fail("Terrain was not reset")
        self.mutator.apply(list_of_instructions)

        self.assertEqual(None, self.state.field)

    def test_toggle_trickroom_sets_trickroom(self):
        self.state.trick_room = False
        instruction = (constants.MUTATOR_TOGGLE_TRICKROOM, )
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertTrue(self.state.trick_room)

    def test_reverse_instruction_unsets_trickroom(self):
        self.state.trick_room = True
        instruction = (constants.MUTATOR_TOGGLE_TRICKROOM, )
        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertFalse(self.state.trick_room)

    def test_reverse_instruction_sets_trickroom(self):
        self.state.trick_room = False
        instruction = (constants.MUTATOR_TOGGLE_TRICKROOM, )
        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertTrue(self.state.trick_room)

    def test_toggle_trickroom_unsets_trickroom(self):
        self.state.trick_room = True
        instruction = (constants.MUTATOR_TOGGLE_TRICKROOM, )
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertFalse(self.state.trick_room)

    def test_apply_and_reverse_trickroom(self):
        self.state.trick_room = False
        instruction = (constants.MUTATOR_TOGGLE_TRICKROOM, )
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)
        if not self.state.trick_room:
            self.fail("Trickroom was not set")
        self.mutator.reverse(list_of_instructions)

        self.assertFalse(self.state.trick_room)

    def test_change_types_properly_changes_types(self):
        self.state.self.active.types = ['normal']
        instruction = (constants.MUTATOR_CHANGE_TYPE, constants.SELF,
                       ['water'], self.state.self.active.types)
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)

        self.assertEqual(['water'], self.state.self.active.types)

    def test_reverse_change_types(self):
        self.state.self.active.types = ['water']
        instruction = (constants.MUTATOR_CHANGE_TYPE, constants.SELF,
                       ['water'], ['normal'])
        list_of_instructions = [instruction]
        self.mutator.reverse(list_of_instructions)

        self.assertEqual(['normal'], self.state.self.active.types)

    def test_apply_and_reverse_change_types(self):
        self.state.self.active.types = ['normal']
        instruction = (constants.MUTATOR_CHANGE_TYPE, constants.SELF,
                       ['water', 'grass'], self.state.self.active.types)
        list_of_instructions = [instruction]
        self.mutator.apply(list_of_instructions)
        if self.state.self.active.types != ['water', 'grass']:
            self.fail('types were not changed')

        self.mutator.reverse(list_of_instructions)
        self.assertEqual(['normal'], self.state.self.active.types)