Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed Move SideConditions and corrected protect classifications #557

Merged
merged 1 commit into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 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 Down
14 changes: 10 additions & 4 deletions src/poke_env/environment/move.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from poke_env.environment.field import Field
from poke_env.environment.move_category import MoveCategory
from poke_env.environment.pokemon_type import PokemonType
from poke_env.environment.side_condition import SideCondition
from poke_env.environment.status import Status
from poke_env.environment.target import Target
from poke_env.environment.weather import Weather
Expand All @@ -20,11 +21,13 @@
"spikyshield",
"kingsshield",
"banefulbunker",
"burningbulwark",
"obstruct",
"maxguard",
"silktrap",
}
_SIDE_PROTECT_MOVES = {"wideguard", "quickguard", "matblock"}
_PROTECT_COUNTER_MOVES = _PROTECT_MOVES | _SIDE_PROTECT_MOVES
_PROTECT_COUNTER_MOVES = _PROTECT_MOVES | {"wideguard", "quickguard", "endure"}


class Move:
Expand Down Expand Up @@ -587,12 +590,15 @@ def self_switch(self) -> Union[str, bool]:
return self.entry.get("selfSwitch", False)

@property
def side_condition(self) -> Optional[str]:
def side_condition(self) -> Optional[SideCondition]:
"""
:return: Side condition inflicted by the move.
:rtype: str | None
:rtype: SideCondition | None
"""
return self.entry.get("sideCondition", None)
sc = self.entry.get("sideCondition", None)
if sc is not None:
sc = SideCondition.from_data(sc)
return sc

@property
def sleep_usable(self) -> bool:
Expand Down
58 changes: 58 additions & 0 deletions src/poke_env/environment/side_condition.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import logging
from enum import Enum, auto, unique
from typing import Dict


@unique
Expand All @@ -12,6 +13,7 @@ class SideCondition(Enum):

UNKNOWN = auto()
AURORA_VEIL = auto()
CRAFTY_SHIELD = auto()
FIRE_PLEDGE = auto()
G_MAX_CANNONADE = auto()
G_MAX_STEELSURGE = auto()
Expand All @@ -21,7 +23,9 @@ class SideCondition(Enum):
GRASS_PLEDGE = auto()
LIGHT_SCREEN = auto()
LUCKY_CHANT = auto()
MATBLOCK = auto()
MIST = auto()
QUICK_GUARD = auto()
REFLECT = auto()
SAFEGUARD = auto()
SPIKES = auto()
Expand All @@ -30,6 +34,7 @@ class SideCondition(Enum):
TAILWIND = auto()
TOXIC_SPIKES = auto()
WATER_PLEDGE = auto()
WIDE_GUARD = auto()

def __str__(self) -> str:
return f"{self.name} (side condition) object"
Expand Down Expand Up @@ -59,6 +64,59 @@ def from_showdown_message(message: str):
)
return SideCondition.UNKNOWN

@staticmethod
def from_data(message: str):
"""Returns the SideCondition object corresponding to the string in static data.

:param message: The message to convert.
:type message: str
:return: The corresponding SideCondition object.
:rtype: SideCondition
"""
message = message.replace("_", "")
message = message.replace(" ", "")
message = message.replace("-", "")
message = message.upper()

try:
return _FROM_DATA[message]
except KeyError:
logging.getLogger("poke-env").warning(
"Unexpected SideCondition '%s' received. SideCondition.UNKNOWN will be used "
"instead. If this is unexpected, please open an issue at "
"https://github.com/hsahovic/poke-env/issues/ along with this error "
"message and a description of your program.",
message,
)
return SideCondition.UNKNOWN


# SideCondition -> Max useful stack level
STACKABLE_CONDITIONS = {SideCondition.SPIKES: 3, SideCondition.TOXIC_SPIKES: 2}

_FROM_DATA: Dict[str, SideCondition] = {
"UNKNOWN": SideCondition.UNKNOWN,
"AURORAVEIL": SideCondition.AURORA_VEIL,
"CRAFTYSHIELD": SideCondition.CRAFTY_SHIELD,
"FIREPLEDGE": SideCondition.FIRE_PLEDGE,
"GMAXCANNONADE": SideCondition.G_MAX_CANNONADE,
"GMAXSTEELSURGE": SideCondition.G_MAX_STEELSURGE,
"GMAXVINELASH": SideCondition.G_MAX_VINE_LASH,
"GMAXVOLCALITH": SideCondition.G_MAX_VOLCALITH,
"GMAXWILDFIRE": SideCondition.G_MAX_WILDFIRE,
"GRASSPLEDGE": SideCondition.GRASS_PLEDGE,
"LIGHTSCREEN": SideCondition.LIGHT_SCREEN,
"LUCKYCHANT": SideCondition.LUCKY_CHANT,
"MATBLOCK": SideCondition.MATBLOCK,
"MIST": SideCondition.MIST,
"QUICKGUARD": SideCondition.QUICK_GUARD,
"REFLECT": SideCondition.REFLECT,
"SAFEGUARD": SideCondition.SAFEGUARD,
"SPIKES": SideCondition.SPIKES,
"STEALTHROCK": SideCondition.STEALTH_ROCK,
"STICKYWEB": SideCondition.STICKY_WEB,
"TAILWIND": SideCondition.TAILWIND,
"TOXICSPIKES": SideCondition.TOXIC_SPIKES,
"WATERPLEDGE": SideCondition.WATER_PLEDGE,
"WIDEGUARD": SideCondition.WIDE_GUARD,
}
43 changes: 36 additions & 7 deletions unit_tests/environment/test_move.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import copy
import itertools

from poke_env.data import GenData
from poke_env.environment import (
Expand All @@ -8,16 +9,17 @@
Move,
MoveCategory,
PokemonType,
SideCondition,
Status,
Target,
Weather,
)


def move_generator():
for move in GenData.from_gen(8).moves:
yield Move(move, gen=8)
yield Move("z" + move, gen=8)
def move_generator(gen=8):
for move in GenData.from_gen(gen).moves:
yield Move(move, gen=gen)
yield Move("z" + move, gen=gen)


def test_accuracy():
Expand Down Expand Up @@ -390,11 +392,38 @@ def test_side_condition():
flame_thrower = Move("flamethrower", gen=8)
quick_guard = Move("quickguard", gen=8)

assert quick_guard.side_condition == "quickguard"
assert quick_guard.side_condition == SideCondition.QUICK_GUARD
assert flame_thrower.side_condition is None

for move in move_generator():
assert isinstance(move.side_condition, str) or move.side_condition is None
assert SideCondition.from_data("i dont know") == SideCondition.UNKNOWN
assert SideCondition.from_showdown_message("i dont know") == SideCondition.UNKNOWN

# Make sure we know every move that has a SideCondition is one we know
side_conditions = set()
for move in itertools.chain(move_generator(8), move_generator(9)):
if move.side_condition:
assert move.side_condition != SideCondition.UNKNOWN
side_conditions.add(move.side_condition)

# SideConditions that don't exist in moves data
to_exclude = set(
[
SideCondition.FIRE_PLEDGE,
SideCondition.WATER_PLEDGE,
SideCondition.GRASS_PLEDGE,
SideCondition.UNKNOWN,
SideCondition.G_MAX_WILDFIRE,
SideCondition.G_MAX_VOLCALITH,
SideCondition.G_MAX_VINE_LASH,
SideCondition.G_MAX_STEELSURGE,
SideCondition.G_MAX_CANNONADE,
]
)

# Make sure we don't have any SideConditions that don't exist in moves data
assert side_conditions == set(
list(filter(lambda x: x not in to_exclude, SideCondition))
)


def test_sleep_usable():
Expand Down