.\PokeLLMon\poke_env\concurrency.py
import asyncio
import atexit
import sys
from logging import CRITICAL, disable
from threading import Thread
from typing import Any, List
def __run_loop ( loop: asyncio. AbstractEventLoop) :
asyncio. set_event_loop( loop)
loop. run_forever( )
def __stop_loop ( loop: asyncio. AbstractEventLoop, thread: Thread) :
disable( CRITICAL)
tasks: List[ asyncio. Task[ Any] ] = [ ]
for task in asyncio. all_tasks( loop) :
task. cancel( )
tasks. append( task)
cancelled = False
shutdown = asyncio. run_coroutine_threadsafe( loop. shutdown_asyncgens( ) , loop)
shutdown. result( )
while not cancelled:
cancelled = True
for task in tasks:
if not task. done( ) :
cancelled = False
loop. call_soon_threadsafe( loop. stop)
thread. join( )
loop. call_soon_threadsafe( loop. close)
def __clear_loop ( ) :
__stop_loop( POKE_LOOP, _t)
async def _create_in_poke_loop_async ( cls_: Any, * args: Any, ** kwargs: Any) - > Any:
return cls_( * args, ** kwargs)
def create_in_poke_loop ( cls_: Any, * args: Any, ** kwargs: Any) - > Any:
try :
loop = asyncio. get_running_loop( )
except AttributeError:
loop = asyncio. get_event_loop( )
except RuntimeError:
loop = None
if loop == POKE_LOOP:
return cls_( * args, ** kwargs)
else :
return asyncio. run_coroutine_threadsafe(
_create_in_poke_loop_async( cls_, * args, ** kwargs) , POKE_LOOP
) . result( )
async def handle_threaded_coroutines ( coro: Any) :
task = asyncio. run_coroutine_threadsafe( coro, POKE_LOOP)
await asyncio. wrap_future( task)
return task. result( )
POKE_LOOP = asyncio. new_event_loop( )
py_ver = sys. version_info
_t = Thread( target= __run_loop, args= ( POKE_LOOP, ) , daemon= True )
_t. start( )
atexit. register( __clear_loop)
.\PokeLLMon\poke_env\data\gen_data.py
from __future__ import annotations
import os
from functools import lru_cache
from typing import Any, Dict, Optional, Union
import orjson
from poke_env. data. normalize import to_id_str
class GenData :
__slots__ = ( "gen" , "moves" , "natures" , "pokedex" , "type_chart" , "learnset" )
UNKNOWN_ITEM = "unknown_item"
_gen_data_per_gen: Dict[ int , GenData] = { }
def __init__ ( self, gen: int ) :
if gen in self. _gen_data_per_gen:
raise ValueError( f"GenData for gen { gen} already initialized." )
self. gen = gen
self. moves = self. load_moves( gen)
self. natures = self. load_natures( )
self. pokedex = self. load_pokedex( gen)
self. type_chart = self. load_type_chart( gen)
self. learnset = self. load_learnset( )
def __deepcopy__ ( self, memodict: Optional[ Dict[ int , Any] ] = None ) - > GenData:
return self
def load_moves ( self, gen: int ) - > Dict[ str , Any] :
with open (
os. path. join( self. _static_files_root, "moves" , f"gen { gen} moves.json" )
) as f:
return orjson. loads( f. read( ) )
def load_natures ( self) - > Dict[ str , Dict[ str , Union[ int , float ] ] ] :
with open ( os. path. join( self. _static_files_root, "natures.json" ) ) as f:
return orjson. loads( f. read( ) )
def load_learnset ( self) - > Dict[ str , Dict[ str , Union[ int , float ] ] ] :
with open ( os. path. join( self. _static_files_root, "learnset.json" ) ) as f:
return orjson. loads( f. read( ) )
def load_pokedex ( self, gen: int ) - > Dict[ str , Any] :
with open (
os. path. join( self. _static_files_root, "pokedex" , f"gen { gen} pokedex.json" )
) as f:
dex = orjson. loads( f. read( ) )
other_forms_dex: Dict[ str , Any] = { }
for value in dex. values( ) :
if "cosmeticFormes" in value:
for other_form in value[ "cosmeticFormes" ] :
other_forms_dex[ to_id_str( other_form) ] = value
for name, value in dex. items( ) :
if name. startswith( "pikachu" ) and name not in { "pikachu" , "pikachugmax" } :
other_forms_dex[ name + "gmax" ] = dex[ "pikachugmax" ]
dex. update( other_forms_dex)
for name, value in dex. items( ) :
if "baseSpecies" in value:
value[ "species" ] = value[ "baseSpecies" ]
else :
value[ "baseSpecies" ] = to_id_str( name)
return dex
def load_type_chart ( self, gen: int ) - > Dict[ str , Dict[ str , float ] ] :
with open (
os. path. join(
self. _static_files_root, "typechart" , f"gen { gen} typechart.json"
)
) as chart:
json_chart = orjson. loads( chart. read( ) )
types = [ str ( type_) . upper( ) for type_ in json_chart]
type_chart = { type_1: { type_2: 1.0 for type_2 in types} for type_1 in types}
for type_, data in json_chart. items( ) :
type_ = type_. upper( )
for other_type, damage_taken in data[ "damageTaken" ] . items( ) :
if other_type. upper( ) not in types:
continue
assert damage_taken in { 0 , 1 , 2 , 3 } , ( data[ "damageTaken" ] , type_)
if damage_taken == 0 :
type_chart[ type_] [ other_type. upper( ) ] = 1
elif damage_taken == 1 :
type_chart[ type_] [ other_type. upper( ) ] = 2
elif damage_taken == 2 :
type_chart[ type_] [ other_type. upper( ) ] = 0.5
elif damage_taken == 3 :
type_chart[ type_] [ other_type. upper( ) ] = 0
assert set ( types) . issubset( set ( type_chart) )
assert len ( type_chart) == len ( types)
for effectiveness in type_chart. values( ) :
assert len ( effectiveness) == len ( types)
return type_chart
@property
def _static_files_root ( self) - > str :
return os. path. join( os. path. dirname( os. path. realpath( __file__) ) , "static" )
@classmethod
@lru_cache ( None )
def from_gen ( cls, gen: int ) - > GenData:
gen_data = GenData( gen)
cls. _gen_data_per_gen[ gen] = gen_data
return gen_data
@classmethod
@lru_cache ( None )
def from_format ( cls, format : str ) - > GenData:
gen = int ( format [ 3 ] )
return cls. from_gen( gen)
.\PokeLLMon\poke_env\data\normalize.py
from functools import lru_cache
@lru_cache ( 2 ** 13 )
def to_id_str ( name: str ) - > str :
"""Converts a full-name to its corresponding id string.
:param name: The name to convert.
:type name: str
:return: The corresponding id string.
:rtype: str
"""
return "" . join( char for char in name if char. isalnum( ) ) . lower( )
.\PokeLLMon\poke_env\data\replay_template.py
import os
with open (
os. path. join(
os. path. dirname( os. path. realpath( __file__) ) , "static" , "replay_template.html"
)
) as f:
REPLAY_TEMPLATE = f. read( )
.\PokeLLMon\poke_env\data\static\abilities\construct_ability_json.py
import pandas as pd
X = pd. read_csv( "raw.txt" , "\t" )
name = list ( X. Name. values)
description = list ( X. Description. values)
name_new = list ( map ( lambda x: x. lower( ) . replace( " " , "" ) , name) )
ability_dict = { }
for i in range ( len ( name) ) :
ability_dict[ name_new[ i] ] = { "name" : name[ i] , "effect" : description[ i] }
print ( "pause" )
with open ( "ability_effect.json" , "w" ) as f:
json. dump( ability_dict, f, indent= 4 )
print ( "pause" )
.\PokeLLMon\poke_env\data\static\items\construct_item_json.py
import pandas as pd
import json
X = pd. read_csv( "raw.txt" , "\t" )
name = list ( X. Name. values)
effect = list ( X. Effect. values)
category = list ( X. Category. values)
item_dict = { }
for i in range ( len ( name) ) :
new_name = name[ i] . split( " icon " ) [ 0 ]
if str ( effect[ i] ) != "nan" :
item_dict[ new_name. lower( ) . replace( " " , "" ) ] = { "name" : new_name, "effect" : effect[ i] }
print ( "pause" )
with open ( "item_effect.json" , "w" ) as f:
json. dump( item_dict, f, indent= 4 )
print ( "pause" )
.\PokeLLMon\poke_env\data\static\moves\extract_gen8_moves.py
import json
import re
import json
move_name_list = [ ]
move_effect_list = [ ]
with open ( "gen8_raw.txt" , "r" ) as f:
idx = 0
for i in range ( 2184 ) :
data = f. readline( )
if idx % 3 == 0 :
move_name = data. split( " " ) [ 0 ]
move_name_list. append( move_name)
elif idx % 3 == 1 :
effect = data[ : - 1 ]
move_effect_list. append( effect)
idx += 1
move2effect = dict ( zip ( move_name_list, move_effect_list) )
with open ( "gen8moves.json" , "r" ) as f:
gen8moves = json. load( f)
move2effect_new = dict ( )
for move, info in gen8moves. items( ) :
try :
effect = move2effect[ info[ 'name' ] ]
move2effect_new[ move] = effect
except :
continue
with open ( "gen8moves_effect.json" , "w" ) as f:
json. dump( move2effect_new, f, indent= 4 )
.\PokeLLMon\poke_env\data\__init__.py
from poke_env. data. gen_data import GenData
from poke_env. data. normalize import to_id_str
from poke_env. data. replay_template import REPLAY_TEMPLATE
__all__ = [
"REPLAY_TEMPLATE" ,
"GenData" ,
"to_id_str" ,
]
.\PokeLLMon\poke_env\environment\abstract_battle.py
import os
from abc import ABC, abstractmethod
from logging import Logger
from typing import Any, Dict, List, Optional, Set, Tuple, Union
from poke_env. data import GenData, to_id_str
from poke_env. data. replay_template import REPLAY_TEMPLATE
from poke_env. environment. field import Field
from poke_env. environment. pokemon import Pokemon
from poke_env. environment. side_condition import STACKABLE_CONDITIONS, SideCondition
from poke_env. environment. weather import Weather
class AbstractBattle ( ABC) :
MESSAGES_TO_IGNORE = {
"-anim" ,
"-burst" ,
"-block" ,
"-center" ,
"-crit" ,
"-combine" ,
"-fail" ,
"-fieldactivate" ,
"-hint" ,
"-hitcount" ,
"-ohko" ,
"-miss" ,
"-notarget" ,
"-nothing" ,
"-resisted" ,
"-singlemove" ,
"-singleturn" ,
"-supereffective" ,
"-waiting" ,
"-zbroken" ,
"askreg" ,
"debug" ,
"chat" ,
"c" ,
"crit" ,
"deinit" ,
"gametype" ,
"gen" ,
"html" ,
"init" ,
"immune" ,
"join" ,
"j" ,
"J" ,
"leave" ,
"l" ,
"L" ,
"name" ,
"n" ,
"rated" ,
"resisted" ,
"split" ,
"supereffective" ,
"teampreview" ,
"tier" ,
"upkeep" ,
"zbroken" ,
}
__slots__ = (
"_anybody_inactive" ,
"_available_moves" ,
"_available_switches" ,
"_battle_tag" ,
"_can_dynamax" ,
"_can_mega_evolve" ,
"_can_tera" ,
"_can_z_move" ,
"_data" ,
"_dynamax_turn" ,
"_fields" ,
"_finished" ,
"_force_switch" ,
"_format" ,
"in_team_preview" ,
"_max_team_size" ,
"_maybe_trapped" ,
"_move_on_next_request" ,
"_opponent_can_dynamax" ,
"_opponent_can_mega_evolve" ,
"_opponent_can_terrastallize" ,
"_opponent_can_z_move" ,
"_opponent_dynamax_turn" ,
"_opponent_rating" ,
"_opponent_side_conditions" ,
"_opponent_team" ,
"_opponent_username" ,
"_player_role" ,
"_player_username" ,
"_players" ,
"_rating" ,
"_reconnected" ,
"_replay_data" ,
"_rqid" ,
"rules" ,
"_reviving" ,
"_save_replays" ,
"_side_conditions" ,
"_team_size" ,
"_team" ,
"_teampreview_opponent_team" ,
"_teampreview" ,
"_trapped" ,
"_turn" ,
"_wait" ,
"_weather" ,
"_won" ,
"logger" ,
)
def __init__ (
self,
battle_tag: str ,
username: str ,
logger: Logger,
save_replays: Union[ str , bool ] ,
gen: int ,
self. _data = GenData. from_gen( gen)
self. _battle_tag: str = battle_tag
self. _format: Optional[ str ] = None
self. _max_team_size: Optional[ int ] = None
self. _opponent_username: Optional[ str ] = None
self. _player_role: Optional[ str ] = None
self. _player_username: str = username
self. _players: List[ Dict[ str , str ] ] = [ ]
self. _replay_data: List[ List[ str ] ] = [ ]
self. _save_replays: Union[ str , bool ] = save_replays
self. _team_size: Dict[ str , int ] = { }
self. _teampreview: bool = False
self. _teampreview_opponent_team: Set[ Pokemon] = set ( )
self. _anybody_inactive: bool = False
self. _reconnected: bool = True
self. logger: Optional[ Logger] = logger
self. in_team_preview: bool = False
self. _move_on_next_request: bool = False
self. _wait: Optional[ bool ] = None
self. _dynamax_turn: Optional[ int ] = None
self. _finished: bool = False
self. _rqid = 0
self. rules: List[ str ] = [ ]
self. _turn: int = 0
self. _opponent_can_terrastallize: bool = True
self. _opponent_dynamax_turn: Optional[ int ] = None
self. _opponent_rating: Optional[ int ] = None
self. _rating: Optional[ int ] = None
self. _won: Optional[ bool ] = None
self. _weather: Dict[ Weather, int ] = { }
self. _fields: Dict[ Field, int ] = { }
self. _opponent_side_conditions: Dict[ SideCondition, int ] = { }
self. _side_conditions: Dict[ SideCondition, int ] = { }
self. _reviving: bool = False
self. _team: Dict[ str , Pokemon] = { }
self. _opponent_team: Dict[ str , Pokemon] = { }
def get_pokemon (
self,
identifier: str ,
force_self_team: bool = False ,
details: str = "" ,
request: Optional[ Dict[ str , Any] ] = None ,
@abstractmethod
def clear_all_boosts ( self) :
pass
def _check_damage_message_for_item ( self, split_message: List[ str ] ) :
if (
len ( split_message) == 6
and split_message[ 4 ] . startswith( "[from] item:" )
and split_message[ 5 ] . startswith( "[of]" )
) :
item = split_message[ 4 ] . split( "item:" ) [ - 1 ]
pkmn = split_message[ 5 ] . split( "[of]" ) [ - 1 ] . strip( )
self. get_pokemon( pkmn) . item = to_id_str( item)
elif len ( split_message) == 5 and split_message[ 4 ] . startswith( "[from] item:" ) :
item = split_message[ 4 ] . split( "item:" ) [ - 1 ]
pkmn = split_message[ 2 ]
self. get_pokemon( pkmn) . item = to_id_str( item)
def _check_damage_message_for_ability ( self, split_message: List[ str ] ) :
if (
len ( split_message) == 6
and split_message[ 4 ] . startswith( "[from] ability:" )
and split_message[ 5 ] . startswith( "[of]" )
) :
ability = split_message[ 4 ] . split( "ability:" ) [ - 1 ]
pkmn = split_message[ 5 ] . split( "[of]" ) [ - 1 ] . strip( )
self. get_pokemon( pkmn) . ability = to_id_str( ability)
def _check_heal_message_for_item ( self, split_message: List[ str ] ) :
if len ( split_message) == 5 and split_message[ 4 ] . startswith( "[from] item:" ) :
pkmn = split_message[ 2 ]
item = split_message[ 4 ] . split( "item:" ) [ - 1 ]
pkmn_object = self. get_pokemon( pkmn)
if pkmn_object. item is not None :
pkmn_object. item = to_id_str( item)
def _check_heal_message_for_ability ( self, split_message: List[ str ] ) :
if len ( split_message) == 6 and split_message[ 4 ] . startswith( "[from] ability:" ) :
ability = split_message[ 4 ] . split( "ability:" ) [ - 1 ]
pkmn = split_message[ 2 ]
self. get_pokemon( pkmn) . ability = to_id_str( ability)
@abstractmethod
def end_illusion ( self, pokemon_name: str , details: str ) :
pass
def _end_illusion_on (
self, illusionist: Optional[ str ] , illusioned: Optional[ Pokemon] , details: str
) :
if illusionist is None :
raise ValueError( "Cannot end illusion without an active pokemon." )
if illusioned is None :
raise ValueError( "Cannot end illusion without an illusioned pokemon." )
illusionist_mon = self. get_pokemon( illusionist, details= details)
if illusionist_mon is illusioned:
return illusionist_mon
illusionist_mon. switch_in( details= details)
illusionist_mon. status = (
illusioned. status. name if illusioned. status is not None else None
)
illusionist_mon. set_hp( f" { illusioned. current_hp} / { illusioned. max_hp} " )
illusioned. was_illusioned( )
return illusionist_mon
def _field_end ( self, field_str: str ) :
field = Field. from_showdown_message( field_str)
if field is not Field. UNKNOWN:
self. _fields. pop( field)
def field_start ( self, field_str: str ) :
field = Field. from_showdown_message( field_str)
if field. is_terrain:
self. _fields = {
field: turn
for field, turn in self. _fields. items( )
if not field. is_terrain
}
self. _fields[ field] = self. turn
def _finish_battle ( self) :
if self. _save_replays:
if self. _save_replays is True :
folder = "replays"
else :
folder = str ( self. _save_replays)
if not os. path. exists( folder) :
os. mkdir( folder)
with open (
os. path. join(
folder, f" { self. _player_username} - { self. battle_tag} .html"
) ,
"w+" ,
encoding= "utf-8" ,
) as f:
formatted_replay = REPLAY_TEMPLATE
formatted_replay = formatted_replay. replace(
"{BATTLE_TAG}" , f" { self. battle_tag} "
)
formatted_replay = formatted_replay. replace(
"{PLAYER_USERNAME}" , f" { self. _player_username} "
)
formatted_replay = formatted_replay. replace(
"{OPPONENT_USERNAME}" , f" { self. _opponent_username} "
)
replay_log = f"> { self. battle_tag} " + "\n" . join(
[ "|" . join( split_message) for split_message in self. _replay_data]
)
formatted_replay = formatted_replay. replace( "{REPLAY_LOG}" , replay_log)
f. write( formatted_replay)
self. _finished = True
@abstractmethod
def parse_request ( self, request: Dict[ str , Any] ) :
pass
def _register_teampreview_pokemon ( self, player: str , details: str ) :
if player != self. _player_role:
mon = Pokemon( details= details, gen= self. _data. gen)
self. _teampreview_opponent_team. add( mon)
def side_end ( self, side: str , condition_str: str ) :
if side[ : 2 ] == self. _player_role:
conditions = self. side_conditions
else :
conditions = self. opponent_side_conditions
condition = SideCondition. from_showdown_message( condition_str)
if condition is not SideCondition. UNKNOWN:
conditions. pop( condition)
def _side_start ( self, side: str , condition_str: str ) :
if side[ : 2 ] == self. _player_role:
conditions = self. side_conditions
else :
conditions = self. opponent_side_conditions
condition = SideCondition. from_showdown_message( condition_str)
if condition in STACKABLE_CONDITIONS:
conditions[ condition] = conditions. get( condition, 0 ) + 1
elif condition not in conditions:
conditions[ condition] = self. turn
def _swap ( self, pokemon_str: str , slot: str ) :
if self. logger is not None :
self. logger. warning( "swap method in Battle is not implemented" )
@abstractmethod
def switch ( self, pokemon_str: str , details: str , hp_status: str ) :
pass
def tied ( self) :
self. _finish_battle( )
def _update_team_from_request ( self, side: Dict[ str , Any] ) :
for pokemon in side[ "pokemon" ] :
if pokemon[ "ident" ] in self. _team:
self. _team[ pokemon[ "ident" ] ] . update_from_request( pokemon)
else :
self. get_pokemon(
pokemon[ "ident" ] , force_self_team= True , request= pokemon
)
def won_by ( self, player_name: str ) :
if player_name == self. _player_username:
self. _won = True
else :
self. _won = False
self. _finish_battle( )
def end_turn ( self, turn: int ) :
self. turn = turn
for mon in self. all_active_pokemons:
if mon:
mon. end_turn( )
@property
@abstractmethod
def active_pokemon ( self) - > Any:
pass
@property
@abstractmethod
def all_active_pokemons ( self) - > List[ Optional[ Pokemon] ] :
pass
@property
@abstractmethod
def available_moves ( self) - > Any:
pass
@property
@abstractmethod
def available_switches ( self) - > Any:
pass
@property
def battle_tag ( self) - > str :
"""
:return: The battle identifier.
:rtype: str
"""
return self. _battle_tag
@property
@abstractmethod
def can_dynamax ( self) - > Any:
pass
@property
@abstractmethod
def can_mega_evolve ( self) - > Any:
pass
@property
@abstractmethod
def can_z_move ( self) - > Any:
pass
@property
@abstractmethod
def can_tera ( self) - > Any:
pass
@property
def dynamax_turns_left ( self) - > Optional[ int ] :
"""
:return: How many turns of dynamax are left. None if dynamax is not active
:rtype: int, optional
"""
if self. _dynamax_turn is not None and any (
map ( lambda pokemon: pokemon. is_dynamaxed, self. _team. values( ) )
) :
return max ( 3 - ( self. turn - self. _dynamax_turn) , 0 )
@property
def fields ( self) - > Dict[ Field, int ] :
"""
:return: A Dict mapping fields to the turn they have been activated.
:rtype: Dict[Field, int]
"""
return self. _fields
@property
def finished ( self) - > bool :
"""
:return: A boolean indicating whether the battle is finished.
:rtype: Optional[bool]
"""
return self. _finished
@property
@abstractmethod
def force_switch ( self) - > Any:
pass
@property
def lost ( self) - > Optional[ bool ] :
"""
:return: If the battle is finished, a boolean indicating whether the battle is
lost. Otherwise None.
:rtype: Optional[bool]
"""
return None if self. _won is None else not self. _won
@property
def max_team_size ( self) - > Optional[ int ] :
return self. _max_team_size
@property
@abstractmethod
def maybe_trapped ( self) - > Any:
pass
@property
@abstractmethod
def opponent_active_pokemon ( self) - > Any:
pass
@property
@abstractmethod
def opponent_can_dynamax ( self) - > Any:
pass
@opponent_can_dynamax. setter
@abstractmethod
def opponent_can_dynamax ( self, value: bool ) - > Any:
pass
@property
def opponent_dynamax_turns_left ( self) - > Optional[ int ] :
if self. _opponent_dynamax_turn is not None and any (
map ( lambda pokemon: pokemon. is_dynamaxed, self. _opponent_team. values( ) )
) :
return max ( 3 - ( self. turn - self. _opponent_dynamax_turn) , 0 )
@property
def opponent_role ( self) - > Optional[ str ] :
if self. player_role == "p1" :
return "p2"
if self. player_role == "p2" :
return "p1"
@property
def opponent_side_conditions ( self) - > Dict[ SideCondition, int ] :
return self. _opponent_side_conditions
def opponent_team ( self) - > Dict[ str , Pokemon] :
"""
During teampreview, keys are not definitive: please rely on values.
:return: The opponent's team. Keys are identifiers, values are pokemon objects.
:rtype: Dict[str, Pokemon]
"""
if self. _opponent_team:
return self. _opponent_team
else :
return { mon. species: mon for mon in self. _teampreview_opponent_team}
@property
def opponent_username ( self) - > Optional[ str ] :
"""
:return: The opponent's username, or None if unknown.
:rtype: str, optional.
"""
return self. _opponent_username
@opponent_username. setter
def opponent_username ( self, value: str ) :
self. _opponent_username = value
@property
def player_role ( self) - > Optional[ str ] :
"""
:return: Player's role in given battle. p1/p2
:rtype: str, optional
"""
return self. _player_role
@player_role. setter
def player_role ( self, value: Optional[ str ] ) :
self. _player_role = value
@property
def player_username ( self) - > str :
"""
:return: The player's username.
:rtype: str
"""
return self. _player_username
@player_username. setter
def player_username ( self, value: str ) :
self. _player_username = value
@property
def players ( self) - > Tuple[ str , str ] :
"""
:return: The pair of players' usernames.
:rtype: Tuple[str, str]
"""
return self. _players[ 0 ] [ "username" ] , self. _players[ 1 ] [ "username" ]
@players. setter
def players ( self, players: Tuple[ str , str ] ) :
"""Sets the battle player's name:
:param player_1: First player's username.
:type player_1: str
:param player_1: Second player's username.
:type player_2: str
"""
player_1, player_2 = players
if player_1 != self. _player_username:
self. _opponent_username = player_1
else :
self. _opponent_username = player_2
@property
def rating ( self) - > Optional[ int ] :
"""
Player's rating after the end of the battle, if it was received.
:return: The player's rating after the end of the battle.
:rtype: int, optional
"""
return self. _rating
@property
def opponent_rating ( self) - > Optional[ int ] :
"""
Opponent's rating after the end of the battle, if it was received.
:return: The opponent's rating after the end of the battle.
:rtype: int, optional
"""
return self. _opponent_rating
@property
def rqid ( self) - > int :
"""
Should not be used.
:return: The last request's rqid.
:rtype: Tuple[str, str]
"""
return self. _rqid
@property
def side_conditions ( self) - > Dict[ SideCondition, int ] :
"""
:return: The player's side conditions. Keys are SideCondition objects, values
are:
- the number of layers of the side condition if the side condition is
stackable
- the turn where the SideCondition was setup otherwise
:rtype: Dict[SideCondition, int]
"""
return self. _side_conditions
@property
def team ( self) - > Dict[ str , Pokemon] :
"""
:return: The player's team. Keys are identifiers, values are pokemon objects.
:rtype: Dict[str, Pokemon]
"""
return self. _team
@team. setter
def team ( self, value: Dict[ str , Pokemon] ) :
self. _team = value
@property
def team_size ( self) - > int :
"""
:return: The number of Pokemon in the player's team.
:rtype: int
"""
if self. _player_role is not None :
return self. _team_size[ self. _player_role]
raise ValueError(
"Team size cannot be inferred without an assigned player role."
)
@property
def teampreview ( self) - > bool :
"""
:return: Whether the battle is awaiting a teampreview order.
:rtype: bool
"""
return self. _teampreview
@property
@abstractmethod
def trapped ( self) - > Any:
pass
@trapped. setter
@abstractmethod
def trapped ( self, value: Any) :
pass
@property
def turn ( self) - > int :
"""
:return: The current battle turn.
:rtype: int
"""
return self. _turn
@turn. setter
def turn ( self, turn: int ) :
"""Sets the current turn counter to given value.
:param turn: Current turn value.
:type turn: int
"""
self. _turn = turn
@property
def weather ( self) - > Dict[ Weather, int ] :
"""
:return: A Dict mapping the battle's weather (if any) to its starting turn
:rtype: Dict[Weather, int]
"""
return self. _weather
@property
def won ( self) - > Optional[ bool ] :
"""
:return: If the battle is finished, a boolean indicating whether the battle is
won. Otherwise None.
:rtype: Optional[bool]
"""
return self. _won
@property
def move_on_next_request ( self) - > bool :
"""
:return: Whether the next received request should yield a move order directly.
This can happen when a switch is forced, or an error is encountered.
:rtype: bool
"""
return self. _move_on_next_request
@move_on_next_request. setter
def move_on_next_request ( self, value: bool ) :
self. _move_on_next_request = value
@property
def reviving ( self) - > bool :
return self. _reviving
.\PokeLLMon\poke_env\environment\battle.py
from logging import Logger
from typing import Any, Dict, List, Optional, Union
from poke_env. environment. abstract_battle import AbstractBattle
from poke_env. environment. move import Move
from poke_env. environment. pokemon import Pokemon
from poke_env. environment. pokemon_type import PokemonType
class Battle ( AbstractBattle) :
def __init__ (
self,
battle_tag: str ,
username: str ,
logger: Logger,
gen: int ,
save_replays: Union[ str , bool ] = False ,
) :
super ( Battle, self) . __init__( battle_tag, username, logger, save_replays, gen)
self. _available_moves: List[ Move] = [ ]
self. _available_switches: List[ Pokemon] = [ ]
self. _can_dynamax: bool = False
self. _can_mega_evolve: bool = False
self. _can_tera: Optional[ PokemonType] = None
self. _can_z_move: bool = False
self. _opponent_can_dynamax = True
self. _opponent_can_mega_evolve = True
self. _opponent_can_z_move = True
self. _opponent_can_tera: bool = False
self. _force_switch: bool = False
self. _maybe_trapped: bool = False
self. _trapped: bool = False
self. battle_msg_history = ""
self. pokemon_hp_log_dict = { }
self. speed_list = [ ]
def clear_all_boosts ( self) :
if self. active_pokemon is not None :
self. active_pokemon. clear_boosts( )
if self. opponent_active_pokemon is not None :
self. opponent_active_pokemon. clear_boosts( )
def end_illusion ( self, pokemon_name: str , details: str ) :
if pokemon_name[ : 2 ] == self. _player_role:
active = self. active_pokemon
else :
active = self. opponent_active_pokemon
if active is None :
raise ValueError( "Cannot end illusion without an active pokemon." )
self. _end_illusion_on(
illusioned= active, illusionist= pokemon_name, details= details
)
def switch ( self, pokemon_str: str , details: str , hp_status: str ) :
identifier = pokemon_str. split( ":" ) [ 0 ] [ : 2 ]
if identifier == self. _player_role:
if self. active_pokemon:
self. active_pokemon. switch_out( )
else :
if self. opponent_active_pokemon:
self. opponent_active_pokemon. switch_out( )
pokemon = self. get_pokemon( pokemon_str, details= details)
pokemon. switch_in( details= details)
pokemon. set_hp_status( hp_status)
@property
def active_pokemon ( self) - > Optional[ Pokemon] :
"""
:return: 活跃的精灵
:rtype: Optional[Pokemon]
"""
for pokemon in self. team. values( ) :
if pokemon. active:
return pokemon
@property
def all_active_pokemons ( self) - > List[ Optional[ Pokemon] ] :
"""
:return: 包含所有活跃精灵和/或 None 的列表
:rtype: List[Optional[Pokemon]
"""
return [ self. active_pokemon, self. opponent_active_pokemon]
@property
def available_moves ( self) - > List[ Move] :
"""
:return: 玩家可以在当前回合使用的招式列表
:rtype: List[Move]
"""
return self. _available_moves
@property
def available_switches ( self) - > List[ Pokemon] :
"""
:return: 玩家可以在当前回合进行的替换列表
:rtype: List[Pokemon]
"""
return self. _available_switches
@property
def can_dynamax ( self) - > bool :
"""
:return: 当前活跃精灵是否可以极巨化
:rtype: bool
"""
return self. _can_dynamax
@property
def can_mega_evolve ( self) - > bool :
"""
:return: 当前活跃精灵是否可以超级进化
:rtype: bool
"""
return self. _can_mega_evolve
@property
def can_tera ( self) - > Optional[ PokemonType] :
"""
:return: None, or the type the active pokemon can terastallize into.
:rtype: PokemonType, optional
"""
return self. _can_tera
@property
def can_z_move ( self) - > bool :
"""
:return: Whether or not the current active pokemon can z-move.
:rtype: bool
"""
return self. _can_z_move
@property
def force_switch ( self) - > bool :
"""
:return: A boolean indicating whether the active pokemon is forced to switch
out.
:rtype: Optional[bool]
"""
return self. _force_switch
@property
def maybe_trapped ( self) - > bool :
"""
:return: A boolean indicating whether the active pokemon is maybe trapped by the
opponent.
:rtype: bool
"""
return self. _maybe_trapped
@property
def opponent_active_pokemon ( self) - > Optional[ Pokemon] :
"""
:return: The opponent active pokemon
:rtype: Pokemon
"""
for pokemon in self. opponent_team. values( ) :
if pokemon. active:
return pokemon
return None
@property
def opponent_can_dynamax ( self) - > bool :
"""
:return: Whether or not opponent's current active pokemon can dynamax
:rtype: bool
"""
return self. _opponent_can_dynamax
@opponent_can_dynamax. setter
def opponent_can_dynamax ( self, value: bool ) :
self. _opponent_can_dynamax = value
@property
def opponent_can_mega_evolve ( self) - > bool :
"""
:return: Whether or not opponent's current active pokemon can mega-evolve
:rtype: bool
"""
return self. _opponent_can_mega_evolve
@opponent_can_mega_evolve. setter
def opponent_can_mega_evolve ( self, value: bool ) :
self. _opponent_can_mega_evolve = value
def opponent_can_tera ( self) - > bool :
"""
:return: Whether or not opponent's current active pokemon can terastallize
:rtype: bool
"""
return self. _opponent_can_tera
@property
def opponent_can_z_move ( self) - > bool :
"""
:return: Whether or not opponent's current active pokemon can z-move
:rtype: bool
"""
return self. _opponent_can_z_move
@opponent_can_z_move. setter
def opponent_can_z_move ( self, value: bool ) :
self. _opponent_can_z_move = value
@property
def trapped ( self) - > bool :
"""
:return: A boolean indicating whether the active pokemon is trapped, either by
the opponent or as a side effect of one your moves.
:rtype: bool
"""
return self. _trapped
@trapped. setter
def trapped ( self, value: bool ) :
self. _trapped = value