Beispiel #1
0
    def get_affected_targets(battle, order) -> List[int]:
        if not order.is_move: return None

        potentials = []
        if order.move_target == DoubleBattle.EMPTY_TARGET_POSITION:

            # Add all pokemon who could be affected for moves like Surf or Earthquake
            if order.order.deduced_target == 'allAdjacent':
                for i, potential_mon in enumerate(battle.active_pokemon):
                    if potential_mon is not None and order.actor != potential_mon:
                        potentials.append(
                            DoubleBattle.active_pokemon_to_showdown_target(
                                i, opp=False))

                for i, potential_mon in enumerate(
                        battle.opponent_active_pokemon):
                    if potential_mon is not None:
                        potentials.append(
                            DoubleBattle.active_pokemon_to_showdown_target(
                                i, opp=True))

            # For moves like Heatwave that affect all opponents, ensure that we list all potential affected opponents
            elif order.order.deduced_target in ['foeSide', 'allAdjacentFoes']:
                for i, potential_mon in enumerate(
                        battle.opponent_active_pokemon):
                    if potential_mon:
                        potentials.append(
                            DoubleBattle.active_pokemon_to_showdown_target(
                                i, opp=True))

            # For moves that affect our side of the field
            elif order.order.deduced_target in [
                    'allies', 'allySide', 'allyTeam'
            ]:
                for i, potential_mon in enumerate(battle.active_pokemon):
                    if potential_mon and mon != potential_mon:
                        potentials.append(
                            DoubleBattle.active_pokemon_to_showdown_target(
                                i, opp=True))

            # For moves that don't have targets (like self-moves)
            else:
                return None

        else:
            # If this is a one-target move, and there is one pokemon left, technically both opponent targets work in Showdown, since there's only one valid
            # target. For our purposes, we only want to return the right target (where the mon is) so that we can retrieve the mon later without hassle
            if battle.showdown_target_to_mon(order.move_target):
                potentials.append(order.move_target)
            elif order.move_target < 0:
                raise (
                    "get_affected_targets has been given an invalid order where we're targeting an ally... but there's no ally...?"
                )
            else:
                raise (
                    "targeting an empty slot with a one mon move... though its on the opponents side"
                )

        return potentials
Beispiel #2
0
def test_choose_random_move_doubles(pseudo_random, example_doubles_request):
    logger = MagicMock()
    battle = DoubleBattle("tag", "username", logger)
    player = RandomPlayer()
    battle._parse_request(example_doubles_request)
    battle._switch("p2a: Tyranitar", "Tyranitar, L50, M", "48/48")

    pseudo_random.side_effect = lambda: 0
    choice = player.choose_random_move(battle)
    assert choice.message == "/choose move psychic -2, move geargrind -1"

    pseudo_random.side_effect = lambda: 0.5
    choice = player.choose_random_move(battle)
    assert (choice.message ==
            "/choose switch zamazentacrowned, move geargrind dynamax -1")

    pseudo_random.side_effect = lambda: 0.999
    choice = player.choose_random_move(battle)
    assert choice.message == "/choose move slackoff dynamax, switch thundurus"

    battle._switch("p2b: Excadrill", "Excadrill, L50, M", "48/48")

    pseudo_random.side_effect = lambda: 0
    choice = player.choose_random_move(battle)
    assert choice.message == "/choose move psychic -2, move geargrind -1"

    pseudo_random.side_effect = lambda: 0.5
    choice = player.choose_random_move(battle)
    assert choice.message == "/choose move slackoff, move wildcharge dynamax 2"

    pseudo_random.side_effect = lambda: 0.999
    choice = player.choose_random_move(battle)
    assert choice.message == "/choose move slackoff dynamax, switch thundurus"
Beispiel #3
0
def test_choose_random_move_doubles(example_doubles_request):
    logger = MagicMock()
    battle = DoubleBattle("tag", "username", logger)
    battle._parse_request(example_doubles_request)
    battle._switch("p2a: Tyranitar", "Tyranitar, L50, M", "48/48")

    player = RandomPlayer()
    active_pokemon_1, active_pokemon_2 = battle.active_pokemon
    choice_1 = player.choose_random_move(battle)
    assert (any([move in choice_1 for move in active_pokemon_1.moves])
            or "/choose switch" in choice_1)
    assert (any([move in choice_1 for move in active_pokemon_2.moves])
            or ",switch" in choice_1)

    choices_100 = [player.choose_random_move(battle) for _ in range(100)]
    assert not any([" 2" in choice for choice in choices_100])
    assert any(["1" in choice for choice in choices_100])
    assert any(["-1" in choice for choice in choices_100])
    assert any(["-2" in choice for choice in choices_100])
    assert any(["dynamax" in choice for choice in choices_100])
    assert not any([choice.count("dynamax") == 2 for choice in choices_100])
    assert any([choice.count("switch") == 2 for choice in choices_100])

    battle._switch("p2b: Charizard", "Charizard, L50, M", "48/48")
    choices_100 = [player.choose_random_move(battle) for _ in range(100)]
    assert any([" 2" in choice for choice in choices_100])
Beispiel #4
0
    def choose_random_doubles_move(self, battle: DoubleBattle) -> BattleOrder:
        active_orders = [[], []]

        for (
                idx,
            (orders, mon, switches, moves, can_mega, can_z_move, can_dynamax),
        ) in enumerate(
                zip(
                    active_orders,
                    battle.active_pokemon,
                    battle.available_switches,
                    battle.available_moves,
                    battle.can_mega_evolve,
                    battle.can_z_move,
                    battle.can_dynamax,
                )):
            if mon:
                targets = {
                    move: battle.get_possible_showdown_targets(move, mon)
                    for move in moves
                }
                orders.extend([
                    BattleOrder(move, move_target=target) for move in moves
                    for target in targets[move]
                ])
                orders.extend([BattleOrder(switch) for switch in switches])

                if can_mega:
                    orders.extend([
                        BattleOrder(move, move_target=target, mega=True)
                        for move in moves for target in targets[move]
                    ])
                if can_z_move:
                    available_z_moves = set(mon.available_z_moves)
                    orders.extend([
                        BattleOrder(move, move_target=target, z_move=True)
                        for move in moves for target in targets[move]
                        if move in available_z_moves
                    ])

                if can_dynamax:
                    orders.extend([
                        BattleOrder(move, move_target=target, dynamax=True)
                        for move in moves for target in targets[move]
                    ])

                if sum(battle.force_switch) == 1:
                    if orders:
                        return orders[int(random.random() * len(orders))]
                    return self.choose_default_move()

        orders = DoubleBattleOrder.join_orders(*active_orders)

        if orders:
            return orders[int(random.random() * len(orders))]
        else:
            return DefaultBattleOrder()
def test_battle_request_parsing(example_doubles_request):
    logger = MagicMock()
    battle = DoubleBattle("tag", "username", logger)

    battle._parse_request(example_doubles_request)
    assert len(battle.team) == 6

    pokemon_names = set(
        map(lambda pokemon: pokemon.species, battle.team.values()))
    assert "thundurus" in pokemon_names
    assert "raichualola" in pokemon_names
    assert "maractus" in pokemon_names
    assert "zamazentacrowned" in pokemon_names

    zamazenta = battle.get_pokemon("p1: Zamazenta")
    zamazenta_moves = zamazenta.moves
    assert (len(zamazenta_moves) == 4 and "closecombat" in zamazenta_moves
            and "crunch" in zamazenta_moves
            and "psychicfangs" in zamazenta_moves
            and "behemothbash" in zamazenta_moves)
Beispiel #6
0
    async def _create_battle(self, split_message: List[str]) -> AbstractBattle:
        """Returns battle object corresponding to received message.

        :param split_message: The battle initialisation message.
        :type split_message: List[str]
        :return: The corresponding battle object.
        :rtype: AbstractBattle
        """
        # We check that the battle has the correct format
        if split_message[1] == self._format and len(split_message) >= 2:
            # Battle initialisation
            battle_tag = "-".join(split_message)[1:]

            if battle_tag in self._battles:
                return self._battles[battle_tag]
            else:
                if self.format_is_doubles:
                    battle = DoubleBattle(
                        battle_tag=battle_tag,
                        username=self.username,
                        logger=self.logger,
                        save_replays=self._save_replays,
                    )
                else:
                    battle = Battle.from_format(
                        format_=self._format,
                        battle_tag=battle_tag,
                        username=self.username,
                        logger=self.logger,
                        save_replays=self._save_replays,
                    )
                await self._battle_count_queue.put(None)
                if battle_tag in self._battles:
                    self._battle_count_queue.get()
                    return self._battles[battle_tag]
                async with self._battle_start_condition:
                    self._battle_semaphore.release()
                    self._battle_start_condition.notify_all()
                    self._battles[battle_tag] = battle

                if self._start_timer_on_battle_start:
                    await self._send_message("/timer on", battle.battle_tag)

                return battle

            return self._battles[battle_tag]
        else:
            self.logger.critical(
                "Unmanaged battle initialisation message received: %s", split_message
            )
            raise ShowdownException()
def test_choose_random_move_doubles(pseudo_random, example_doubles_request):
    # possible_choices_memo = (
    #     []
    # )  # this needs to be reset at each start of Player.choose_random_move

    # def count_substrings(substring: str, in_: List[str]) -> int:
    #     return sum(map(lambda el: substring in el, in_))

    # def choose_non_dynamax(first_orders,) -> str:
    #     joined = DoubleBattleOrder.join_orders(possible_choices)
    #     possible_choices_memo.append(possible_choices.copy())
    #     for possible_choice in possible_choices:
    #         if " dynamax" not in possible_choice:
    #             return possible_choice
    #     raise ValueError(f"Only max moves are available in {possible_choices}")

    logger = MagicMock()
    battle = DoubleBattle("tag", "username", logger)
    player = RandomPlayer()
    battle._parse_request(example_doubles_request)
    battle._switch("p2a: Tyranitar", "Tyranitar, L50, M", "48/48")

    pseudo_random.side_effect = lambda: 0
    choice = player.choose_random_move(battle)
    assert choice.message == "/choose move psychic -2, move geargrind -1"

    pseudo_random.side_effect = lambda: 0.5
    choice = player.choose_random_move(battle)
    assert (choice.message ==
            "/choose switch zamazentacrowned, move geargrind dynamax -1")

    pseudo_random.side_effect = lambda: 0.999
    choice = player.choose_random_move(battle)
    assert choice.message == "/choose move slackoff dynamax, switch thundurus"

    battle._switch("p2b: Excadrill", "Excadrill, L50, M", "48/48")

    pseudo_random.side_effect = lambda: 0
    choice = player.choose_random_move(battle)
    assert choice.message == "/choose move psychic -2, move geargrind -1"

    pseudo_random.side_effect = lambda: 0.5
    choice = player.choose_random_move(battle)
    assert choice.message == "/choose move slackoff, move wildcharge dynamax 2"

    pseudo_random.side_effect = lambda: 0.999
    choice = player.choose_random_move(battle)
    assert choice.message == "/choose move slackoff dynamax, switch thundurus"
Beispiel #8
0
def test_battle_request_parsing_and_interactions(example_doubles_request):
    logger = MagicMock()
    battle = DoubleBattle("tag", "username", logger)

    battle._parse_request(example_doubles_request)
    mr_rime, klinklang = battle.active_pokemon
    assert isinstance(mr_rime, Pokemon)
    assert isinstance(klinklang, Pokemon)
    assert battle.get_pokemon("p1: Mr. Rime") == mr_rime
    assert battle.get_pokemon("p1: Klinklang") == klinklang

    assert set(battle.available_moves[0]) == set(
        battle.active_pokemon[0].moves.values()
    )
    assert set(battle.available_moves[1]) == set(
        battle.active_pokemon[1].moves.values()
    )

    assert len(battle.available_switches) == 2
    assert all(battle.can_dynamax)
    assert not any(battle.can_z_move)
    assert not any(battle.can_mega_evolve)
    assert not any(battle.trapped)
    assert not any(battle.force_switch)
    assert not any(battle.maybe_trapped)

    mr_rime._boosts = {
        "accuracy": -2,
        "atk": 1,
        "def": -6,
        "evasion": 4,
        "spa": -4,
        "spd": 2,
        "spe": 3,
    }
    klinklang._boosts = {
        "accuracy": -6,
        "atk": 6,
        "def": -1,
        "evasion": 1,
        "spa": 4,
        "spd": -3,
        "spe": 2,
    }

    battle._clear_all_boosts()

    cleared_boosts = {
        "accuracy": 0,
        "atk": 0,
        "def": 0,
        "evasion": 0,
        "spa": 0,
        "spd": 0,
        "spe": 0,
    }

    assert mr_rime.boosts == cleared_boosts
    assert klinklang.boosts == cleared_boosts

    assert battle.active_pokemon == [mr_rime, klinklang]
    battle._parse_message(["", "swap", "p1b: Klinklang", ""])
    assert battle.active_pokemon == [klinklang, mr_rime]

    battle._switch("p2a: Milotic", "Milotic, L50, F", "48/48")
    battle._switch("p2b: Tyranitar", "Tyranitar, L50, M", "48/48")

    milotic, tyranitar = battle.opponent_active_pokemon
    assert milotic.species == "milotic"
    assert tyranitar.species == "tyranitar"

    assert all(battle.opponent_can_dynamax)
Beispiel #9
0
def test_end_illusion():
    logger = MagicMock()
    battle = DoubleBattle("tag", "username", logger)
    battle._player_role = "p2"

    battle._switch("p2a: Celebi", "Celebi", "100/100")
    battle._switch("p2b: Ferrothorn", "Ferrothorn, M", "100/100")
    battle._switch("p1a: Pelipper", "Pelipper, F", "100/100")
    battle._switch("p1b: Kingdra", "Kingdra, F", "100/100")

    battle._end_illusion("p2a: Zoroark", "Zoroark, M")
    zoroark = battle.team["p2: Zoroark"]
    celebi = battle.team["p2: Celebi"]
    ferrothorn = battle.team["p2: Ferrothorn"]
    assert zoroark in battle.active_pokemon
    assert ferrothorn in battle.active_pokemon
    assert celebi not in battle.active_pokemon
Beispiel #10
0
def test_get_possible_showdown_targets(example_doubles_request):
    logger = MagicMock()
    battle = DoubleBattle("tag", "username", logger)

    battle._parse_request(example_doubles_request)
    mr_rime, klinklang = battle.active_pokemon
    psychic = mr_rime.moves["psychic"]
    slackoff = mr_rime.moves["slackoff"]

    battle._switch("p2b: Tyranitar", "Tyranitar, L50, M", "48/48")
    assert battle.get_possible_showdown_targets(psychic, mr_rime) == [-2, 2]

    battle._switch("p2a: Milotic", "Milotic, L50, F", "48/48")
    assert battle.get_possible_showdown_targets(psychic, mr_rime) == [-2, 1, 2]
    assert battle.get_possible_showdown_targets(slackoff, mr_rime) == [0]
    assert battle.get_possible_showdown_targets(psychic, mr_rime, dynamax=True) == [
        1,
        2,
    ]
    assert battle.get_possible_showdown_targets(slackoff, mr_rime, dynamax=True) == [0]
Beispiel #11
0
    def choose_random_doubles_move(self, battle: DoubleBattle) -> str:
        available_orders = []
        available_z_moves = set()
        mega_selected = False
        zmove_selected = False
        dynamax_selected = False

        if any(battle.active_pokemon):
            pokemon_1, pokemon_2 = battle.active_pokemon

            if pokemon_1 and battle.can_z_move[0]:
                available_z_moves.update(pokemon_1.available_z_moves)
            if pokemon_2 and battle.can_z_move[1]:
                available_z_moves.update(pokemon_2.available_z_moves)

            pokemon_1_index = 0
            if pokemon_1 is None:
                pokemon_1, pokemon_2 = pokemon_2, pokemon_1
                pokemon_1_index = 1

            if pokemon_1 is not None:
                for move in battle.available_moves[pokemon_1_index]:
                    for target in battle.get_possible_showdown_targets(
                            move, pokemon_1):
                        available_orders.append(
                            self.create_order(move, move_target=target))
                        if battle.can_mega_evolve[pokemon_1_index]:
                            available_orders.append(
                                self.create_order(move,
                                                  mega=True,
                                                  move_target=target))
                        if (battle.can_z_move[pokemon_1_index]
                                and move in available_z_moves):
                            available_orders.append(
                                self.create_order(move,
                                                  z_move=True,
                                                  move_target=target))
                    if battle.can_dynamax[pokemon_1_index]:
                        for target in battle.get_possible_showdown_targets(
                                move, pokemon_1, dynamax=True):
                            available_orders.append(
                                self.create_order(move,
                                                  dynamax=True,
                                                  move_target=target))

            for pokemon in battle.available_switches[pokemon_1_index]:
                available_orders.append(self.create_order(pokemon))

            if available_orders:
                order = random.choice(available_orders)
                mega_selected = "mega" in order
                zmove_selected = "zmove" in order
                dynamax_selected = "dynamax" in order
            else:
                order = self.choose_default_move()

            if sum(battle.force_switch) == 1:
                return order

            if pokemon_2 is not None or sum(battle.force_switch) == 2:
                pokemon_2 = battle.active_pokemon[1]
                available_orders = []

                if pokemon_2 is not None:
                    available_z_moves = set()

                    if battle.can_z_move:
                        available_z_moves.update(pokemon_2.available_z_moves)

                    for move in battle.available_moves[1]:
                        for target in battle.get_possible_showdown_targets(
                                move, pokemon_2):
                            available_orders.append(
                                self.create_order(move, move_target=target))
                            if not mega_selected and battle.can_mega_evolve[1]:
                                available_orders.append(
                                    self.create_order(move,
                                                      mega=True,
                                                      move_target=target))
                            if (not zmove_selected and battle.can_z_move[1]
                                    and move in available_z_moves):
                                available_orders.append(
                                    self.create_order(move,
                                                      z_move=True,
                                                      move_target=target))
                        if not dynamax_selected and battle.can_dynamax[1]:
                            for target in battle.get_possible_showdown_targets(
                                    move, pokemon_2, dynamax=True):
                                available_orders.append(
                                    self.create_order(move,
                                                      dynamax=True,
                                                      move_target=target))

                for pokemon in battle.available_switches[1]:
                    if order != self.create_order(pokemon):
                        available_orders.append(self.create_order(pokemon))

                if available_orders:
                    order += random.choice(available_orders).replace(
                        "/choose ", ",")
                else:
                    order += ",default"
        else:
            return self.choose_default_move()

        return order
Beispiel #12
0
    def get_all_doubles_moves(self,
                              battle: DoubleBattle) -> List[DoubleBattleOrder]:
        active_orders = [[], []]

        for (
                idx,
            (orders, mon, switches, moves, can_mega, can_z_move, can_dynamax),
        ) in enumerate(
                zip(
                    active_orders,
                    battle.active_pokemon,
                    battle.available_switches,
                    battle.available_moves,
                    battle.can_mega_evolve,
                    battle.can_z_move,
                    battle.can_dynamax,
                )):
            if mon:
                targets = {
                    move: battle.get_possible_showdown_targets(move, mon)
                    for move in moves
                }
                orders.extend([
                    BattleOrder(move, actor=mon, move_target=target)
                    for move in moves for target in targets[move]
                ])
                orders.extend(
                    [BattleOrder(switch, actor=mon) for switch in switches])

                if can_mega:
                    orders.extend([
                        BattleOrder(move,
                                    actor=mon,
                                    move_target=target,
                                    mega=True) for move in moves
                        for target in targets[move]
                    ])
                if can_z_move:
                    available_z_moves = set(mon.available_z_moves)
                    orders.extend([
                        BattleOrder(move,
                                    actor=mon,
                                    move_target=target,
                                    z_move=True) for move in moves
                        for target in targets[move]
                        if move in available_z_moves
                    ])

                if can_dynamax:
                    orders.extend([
                        BattleOrder(move,
                                    actor=mon,
                                    move_target=target,
                                    dynamax=True) for move in moves
                        for target in battle.get_possible_showdown_targets(
                            move, mon, dynamax=True)
                    ])

                if sum(battle.force_switch) == 1:
                    if orders:
                        return list(
                            map(
                                lambda x: DoubleBattleOrder(first_order=x,
                                                            second_order=None),
                                orders))
                    return None

        return DoubleBattleOrder.join_orders(*active_orders)