Skip to content

Commit

Permalink
Added gen and format information to AbstractBattle (hsahovic#558)
Browse files Browse the repository at this point in the history
* Added gen and format information to AbstractBattle

* Left a print message in

---------

Co-authored-by: Cayman Simpson <[email protected]>
  • Loading branch information
caymansimpson and caymansimpson authored Jun 10, 2024
1 parent 6d00fdd commit aa39726
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 4 deletions.
8 changes: 7 additions & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def raw_team_data():
def example_request():
with open(os.path.join(FIXTURE_DIR, "example_request.json")) as f:
return orjson.loads(f.read())


@fixture
def force_switch_example_request():
Expand All @@ -51,3 +51,9 @@ def force_switch_example_request():
def example_doubles_request():
with open(os.path.join(FIXTURE_DIR, "example_doubles_request.json")) as f:
return orjson.loads(f.read())


@fixture
def example_doubles_logs():
with open(os.path.join(FIXTURE_DIR, "example_doubles_logs.txt")) as f:
return list(map(lambda x: x.split("|"), orjson.loads(f.read())))
161 changes: 161 additions & 0 deletions fixture_data/example_doubles_logs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
[
"|j|\u2606test-player-b",
"|j|\u2606test-player-a",
"|player|p1|test-player-b|265",
"|player|p2|test-player-a|1",
"|teamsize|p1|6",
"|teamsize|p2|6",
"|gametype|doubles",
"|gen|6",
"|tier|[Gen 6] Doubles OU",
"|rule|Species Clause: Limit one of each Pok\u00e9mon",
"|rule|OHKO Clause: OHKO moves are banned",
"|rule|Moody Clause: Moody is banned",
"|rule|Evasion Abilities Clause: Evasion abilities are banned",
"|rule|Evasion Moves Clause: Evasion moves are banned",
"|rule|Endless Battle Clause: Forcing endless battles is banned",
"|rule|HP Percentage Mod: HP is shown in percentages",
"|rule|Swagger Clause: Swagger is banned",
"|clearpoke",
"|poke|p1|Charizard, M|item",
"|poke|p1|Rhyperior, M|item",
"|poke|p1|Keldeo-Resolute|item",
"|poke|p1|Aegislash, M|item",
"|poke|p1|Kyurem-Black|item",
"|poke|p1|Shaymin|item",
"|poke|p2|Amoonguss, M|item",
"|poke|p2|Diancie|item",
"|poke|p2|Cresselia, F|item",
"|poke|p2|Camerupt, M|item",
"|poke|p2|Rotom-Wash|item",
"|poke|p2|Scrafty, M|item",
"|teampreview",
"|start",
"|switch|p1a: Keldeo|Keldeo-Resolute|100/100",
"|switch|p1b: Aegislash|Aegislash, M|100/100",
"|switch|p2a: Amoonguss|Amoonguss, M|100/100",
"|switch|p2b: Cresselia|Cresselia, F|100/100",
"|turn|1",
"|move|p2a: Amoonguss|Rage Powder|p2a: Amoonguss",
"|-singleturn|p2a: Amoonguss|move: Rage Powder",
"|move|p1a: Keldeo|Icy Wind|p2a: Amoonguss|[spread] p2a: Amoonguss,p2b: Cresselia",
"|-supereffective|p2a: Amoonguss",
"|-damage|p2a: Amoonguss|74/100",
"|-damage|p2b: Cresselia|90/100",
"|-unboost|p2a: Amoonguss|spe|1",
"|-unboost|p2b: Cresselia|spe|1",
"|-damage|p1a: Keldeo|91/100|[from] item: Life Orb",
"|-formechange|p1b: Aegislash|Aegislash-Blade||[from] ability: Stance Change",
"|move|p1b: Aegislash|Shadow Ball|p2a: Amoonguss",
"|-damage|p2a: Amoonguss|25/100",
"|-damage|p1b: Aegislash|91/100|[from] item: Life Orb",
"|move|p2b: Cresselia|Calm Mind|p2b: Cresselia",
"|-boost|p2b: Cresselia|spa|1",
"|-boost|p2b: Cresselia|spd|1",
"|upkeep",
"|turn|2",
"|move|p1a: Keldeo|Scald|p2b: Cresselia",
"|-damage|p2b: Cresselia|69/100",
"|-damage|p1a: Keldeo|81/100|[from] item: Life Orb",
"|move|p1b: Aegislash|Flash Cannon|p2a: Amoonguss",
"|-crit|p2a: Amoonguss",
"|-damage|p2a: Amoonguss|0 fnt",
"|-damage|p1b: Aegislash|81/100|[from] item: Life Orb",
"|faint|p2a: Amoonguss",
"|move|p2b: Cresselia|Psychic|p1a: Keldeo",
"|-supereffective|p1a: Keldeo",
"|-damage|p1a: Keldeo|0 fnt",
"|faint|p1a: Keldeo",
"|upkeep",
"|switch|p1a: Charizard|Charizard, M|100/100",
"|switch|p2a: Camerupt|Camerupt, M|100/100",
"|turn|3",
"|detailschange|p1a: Charizard|Charizard-Mega-Y, M",
"|-mega|p1a: Charizard|Charizard|Charizardite Y",
"|-weather|SunnyDay|[from] ability: Drought|[of] p1a: Charizard",
"|move|p1a: Charizard|Solar Beam||[still]",
"|-prepare|p1a: Charizard|Solar Beam|p2b: Cresselia",
"|-anim|p1a: Charizard|Solar Beam|p2b: Cresselia",
"|-damage|p2b: Cresselia|47/100",
"|move|p1b: Aegislash|Shadow Ball|p2b: Cresselia",
"|-supereffective|p2b: Cresselia",
"|-damage|p2b: Cresselia|0 fnt",
"|-damage|p1b: Aegislash|71/100|[from] item: Life Orb",
"|faint|p2b: Cresselia",
"|move|p2a: Camerupt|Heat Wave|p1b: Aegislash|[spread] p1a: Charizard",
"|-miss|p2a: Camerupt|p1b: Aegislash",
"|-resisted|p1a: Charizard",
"|-damage|p1a: Charizard|72/100",
"|-weather|SunnyDay|[upkeep]",
"|upkeep",
"|switch|p2b: Rotom|Rotom-Wash|100/100",
"|turn|4",
"|detailschange|p2a: Camerupt|Camerupt-Mega, M",
"|-mega|p2a: Camerupt|Camerupt|Cameruptite",
"|move|p1b: Aegislash|Shadow Sneak|p2a: Camerupt",
"|-damage|p2a: Camerupt|74/100",
"|-damage|p1b: Aegislash|62/100|[from] item: Life Orb",
"|move|p1a: Charizard|Solar Beam||[still]",
"|-prepare|p1a: Charizard|Solar Beam|p2b: Rotom",
"|-anim|p1a: Charizard|Solar Beam|p2b: Rotom",
"|-supereffective|p2b: Rotom",
"|-damage|p2b: Rotom|0 fnt",
"|faint|p2b: Rotom",
"|move|p2a: Camerupt|Heat Wave|p1a: Charizard|[spread] p1a: Charizard,p1b: Aegislash",
"|-resisted|p1a: Charizard",
"|-supereffective|p1b: Aegislash",
"|-damage|p1a: Charizard|26/100",
"|-damage|p1b: Aegislash|0 fnt",
"|faint|p1b: Aegislash",
"|-weather|SunnyDay|[upkeep]",
"|upkeep",
"|switch|p1b: Rhyperior|Rhyperior, M|100/100",
"|switch|p2b: Diancie|Diancie|100/100",
"|turn|5",
"|move|p1a: Charizard|Solar Beam||[still]",
"|-prepare|p1a: Charizard|Solar Beam|p2b: Diancie",
"|-anim|p1a: Charizard|Solar Beam|p2b: Diancie",
"|-supereffective|p2b: Diancie",
"|-damage|p2b: Diancie|8/100",
"|-enditem|p2b: Diancie|Weakness Policy",
"|-boost|p2b: Diancie|atk|2",
"|-boost|p2b: Diancie|spa|2",
"|move|p1b: Rhyperior|Earthquake|p2b: Diancie|[spread] p2a: Camerupt,p2b: Diancie",
"|-immune|p1a: Charizard",
"|-supereffective|p2a: Camerupt",
"|-supereffective|p2b: Diancie",
"|-damage|p2a: Camerupt|0 fnt",
"|-damage|p2b: Diancie|0 fnt",
"|faint|p2a: Camerupt",
"|faint|p2b: Diancie",
"|-weather|SunnyDay|[upkeep]",
"|upkeep",
"|switch|p2a: Scrafty|Scrafty, M|100/100",
"|-ability|p2a: Scrafty|Intimidate|boost",
"|-unboost|p1a: Charizard|atk|1",
"|-unboost|p1b: Rhyperior|atk|1",
"|turn|6",
"|switch|p1b: Kyurem|Kyurem-Black|100/100",
"|-ability|p1b: Kyurem|Teravolt",
"|move|p1a: Charizard|Overheat|p1b: Kyurem|[miss]",
"|-miss|p1a: Charizard|p1b: Kyurem",
"|move|p2a: Scrafty|Drain Punch|p1b: Kyurem",
"|-supereffective|p1b: Kyurem",
"|-damage|p1b: Kyurem|13/100",
"|-damage|p2a: Scrafty|91/100|[from] item: Life Orb",
"|-weather|SunnyDay|[upkeep]",
"|upkeep",
"|turn|7",
"|move|p1b: Kyurem|Ice Beam|p2a: Scrafty",
"|-damage|p2a: Scrafty|57/100",
"|move|p1a: Charizard|Solar Beam||[still]",
"|-prepare|p1a: Charizard|Solar Beam|p2a: Scrafty",
"|-anim|p1a: Charizard|Solar Beam|p2a: Scrafty",
"|-damage|p2a: Scrafty|8/100",
"|move|p2a: Scrafty|Knock Off|p1a: Charizard",
"|-damage|p1a: Charizard|0 fnt",
"|-damage|p2a: Scrafty|0 fnt|[from] item: Life Orb",
"|faint|p1a: Charizard",
"|faint|p2a: Scrafty",
"|win|test-player-b"
]
28 changes: 25 additions & 3 deletions src/poke_env/environment/abstract_battle.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import re
from abc import ABC, abstractmethod
from logging import Logger
from typing import Any, Dict, List, Optional, Set, Tuple, Union
Expand Down Expand Up @@ -44,7 +45,6 @@ class AbstractBattle(ABC):
"debug",
"deinit",
"gametype",
"gen",
"html",
"immune",
"init",
Expand All @@ -59,7 +59,6 @@ class AbstractBattle(ABC):
"split",
"supereffective",
"teampreview",
"tier",
"upkeep",
"uhtml",
"zbroken",
Expand All @@ -81,6 +80,7 @@ class AbstractBattle(ABC):
"_finished",
"_force_switch",
"_format",
"_gen",
"in_team_preview",
"_max_team_size",
"_maybe_trapped",
Expand Down Expand Up @@ -131,6 +131,7 @@ def __init__(

# Utils attributes
self._battle_tag: str = battle_tag
self._gen: int = gen
self._format: Optional[str] = None
self._max_team_size: Optional[int] = None
self._opponent_username: Optional[str] = None
Expand Down Expand Up @@ -717,7 +718,11 @@ def parse_message(self, split_message: List[str]):
for mon in self.team.values():
mon.clear_active()
elif split_message[1] == "gen":
self._format = split_message[2]
if self._gen != int(split_message[2]):
err = f"Battle Initiated with gen {self._gen} but got: {split_message}"
raise RuntimeError(err)
elif split_message[1] == "tier":
self._format = re.sub("[^a-z0-9]+", "", split_message[2].lower())
elif split_message[1] == "inactive":
if "disconnected" in split_message[2]:
self._anybody_inactive = True
Expand Down Expand Up @@ -964,6 +969,23 @@ def finished(self) -> bool:
def force_switch(self) -> Any:
pass

@property
def format(self) -> Optional[str]:
"""
:return: The format of the battle, in accordance with Showdown protocol
:rtype: Optional[str]
"""
return self._format

@property
def gen(self) -> int:
"""
:return: The generation of the battle; will be the parameter with which the
the battle was initiated
:rtype: int
"""
return self._gen

@property
def lost(self) -> Optional[bool]:
"""
Expand Down
31 changes: 31 additions & 0 deletions unit_tests/environment/test_double_battle.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from unittest.mock import MagicMock

import pytest

from poke_env.environment import DoubleBattle, Pokemon


Expand Down Expand Up @@ -276,3 +278,32 @@ def test_one_mon_left_in_double_battles_results_in_available_move_in_the_correct
assert [m.id for m in battle.available_moves[1]] == ["recover", "haze"]
assert battle.active_pokemon[0] is None
assert battle.active_pokemon[1].species == "milotic"


def test_gen_and_format(example_doubles_logs):
battle = DoubleBattle("tag", "username", MagicMock(), gen=8)
battle.player_role = "p1"

with pytest.raises(RuntimeError):
for split_message in example_doubles_logs:
if split_message[1] == "win":
battle.won_by(split_message[2])
elif split_message[1] == "tie":
battle.tied()
else:
battle.parse_message(split_message)

battle = DoubleBattle("tag", "username", MagicMock(), gen=6)
battle.player_role = "p1"

for split_message in example_doubles_logs:
if split_message[1] == "win":
battle.won_by(split_message[2])
elif split_message[1] == "tie":
battle.tied()
else:
battle.parse_message(split_message)

assert battle.gen == 6
assert battle.battle_tag == "tag"
assert battle.format == "gen6doublesou"

0 comments on commit aa39726

Please sign in to comment.