"""Generate mock logs for ease of testing"""
import datetime
import hashlib
import random
import re
from onix import contexts
from onix import metrics
from onix import utilities
from onix.model import Moveset, PokeStats, Player
from onix.collection.log_reader import get_all_formes, normalize_hidden_power
def _generate_random_ev_list():
"""Generate random EV spread where all EVs are multiples of 4 and are
less than 255
Returns:
:obj:`list` of `int` :
The 6 EV values
"""
while True:
ev_line = [random.randrange(127) for _ in range(5)]
ev_line = [0] + sorted(ev_line) + [127]
ev_list = [4*(ev_line[i+1] - ev_line[i]) for i in range(6)]
if max(ev_list) < 255:
break
return ev_list
[docs]def generate_pokemon(species, context,
level=100, hackmons=False, any_ability=False):
"""
Randomly generate a Showdown-style Pokemon dict and the corresponding
``Moveset`` DTO for the given species
Args:
species (str) : species or forme name
context (contexts.Context) : The resources needed by the function.
Requires pokedex, formats_data, accessible_formes, natures and
sanitizer.
level (:obj:`int`, optional) : the Pokemon's desired level.
Default is 100.
hackmons (:obj:`bool`, optional) :
Set to True if this is for a metagame where a battle forme or mega
evolution can appear outside its base forme. Default is False.
any_ability (:obj:`bool`, optional) :
Set to True if the Pokemon can have have "illegal" abilities.
Default is False.
Returns:
(tuple) :
* dict : A Showdown-style Pokemon dict of the specified species
* Moveset : The corresponding moveset that should be parsed
"""
contexts.require(context, 'pokedex', 'formats_data', 'accessible_formes',
'natures', 'sanitizer')
ability_pool = list(context.pokedex[species]['abilities'].values())
move_pool = context.formats_data[species]['randomBattleMoves']
item_pool = ['leftovers', 'lifeorb', 'focussash', 'choiceband',
'choicescarf', 'choicespecs', 'rockyhelmet']
natures_pool = list(context.natures.keys())
ability = context.sanitizer.sanitize(random.choice(ability_pool))
gender = 'u'
item = context.sanitizer.sanitize(context.formats_data[species].get(
'requiredItem', random.choice(item_pool)))
moves = random.sample(move_pool, min(4, len(move_pool)))
if 'return' not in moves:
happiness = 255
else:
happiness = 0
nature = random.choice(natures_pool)
stats = ('hp', 'atk', 'def', 'spa', 'spd', 'spe')
iv_list = [random.randrange(32) for _ in range(6)]
ev_list = _generate_random_ev_list()
iv_dict = dict(zip(stats, iv_list))
ev_dict = dict(zip(stats, ev_list))
ivs = PokeStats(*iv_list)
evs = PokeStats(*ev_list)
pokemon_dict = {
'species': context.pokedex[species]['species'],
'name': context.pokedex[species]['species'],
'ability': ability,
'nature': context.natures[nature]['name'],
'item': item,
'moves': normalize_hidden_power(moves, ivs),
'ivs': iv_dict,
'evs': ev_dict,
'level': level,
}
if happiness != 255:
pokemon_dict['happiness'] = happiness
formes = [forme._replace(
stats=utilities.calculate_stats(forme.stats, context.natures[nature],
ivs, evs, level))
for forme in get_all_formes(species, ability, item,
moves, context, hackmons,
any_ability)]
moveset = context.sanitizer.sanitize(Moveset(formes, gender, item, moves,
level, happiness))
return pokemon_dict, moveset
[docs]def generate_player(name, **ratings):
"""
Generate a Showdown-style player's rating dict and the corresponding
``Player`` DTO for the given species
Args:
name (str) : the player's name
**ratings : values to put in the player's rating dict. Unset values
will be randomly generated.
Returns:
(tuple) :
* dict : A Showdown-style ratings dict for the specified player
* Player : The corresponding DTO that should be parsed
"""
if ratings is None:
ratings = {}
pid = ratings.get('userid', utilities.sanitize_string(name))
w = ratings.get('w', random.randrange(100))
l = ratings.get('l', random.randrange(100))
t = ratings.get('t', random.randrange(10))
elo = ratings.get('elo', random.uniform(1000., 1700.))
r = ratings.get('r', random.uniform(1000., 2000.))
rd = ratings.get('rd', random.uniform(25., 130.))
rpr = ratings.get('rpr', r + random.uniform(-25, 25))
rprd = ratings.get('rprd', rd - random.uniform(0, 25))
rating_dict = dict(elo=elo,
formatid=ratings.get('formatid', 'randombattle'),
l=l, r=r, rd=rd, rpr=rpr, rprd=rprd,
rpsigma=ratings.get('rpsigma', 0),
rptime=ratings.get('rptime',
int(datetime.datetime.now()
.strftime("%s"))),
sigma=ratings.get('sigma', 0),
t=t, userid=pid, username=name, w=w)
rating_dict['col1'] = ratings.get('col1', rating_dict['w']
+ rating_dict['l'] + rating_dict['t']
+ random.randrange(20))
rating_dict['userid'] = pid
rating_dict['entryid'] = ratings.get('entryid',
int(hashlib.sha512('{0}{1}'.format(
rating_dict['formatid'],
rating_dict['userid'])
.encode('utf-8'))
.hexdigest()[:7], 16))
rating_dict['gxe'] = ratings.get('gxe',
metrics.gxe(rating_dict['r'],
rating_dict['rd']))
rating_dict['oldelo'] = ratings.get('oldelo', rating_dict['elo']
+ random.uniform(-25, 25))
player = Player(pid, dict(w=w, l=l, t=t, elo=elo,
r=r, rd=rd, rpr=rpr, rprd=rprd))
return rating_dict, player
[docs]def generate_log(players, teams, turns=None, end_type=None):
"""
Generate a mock log.
Args:
players (:obj:`list` of :obj:`dict`) :
The rating dictionaries of the players in the match
teams (:obj:`list` of :obj:`list` of :obj:`dict`) :
The Pokemon dictionaries for each player's team. Must have same
length as `players`.
turns (:obj:`int`, optional) :
Number of turns in the battle. Default is a random value.
end_type (:obj:`str`, optional) :
End type. Default is "normal"
Returns:
dict :
The mock log
"""
if len(players) != len(teams):
raise ValueError('players list and teams list must have same length')
log = dict(endType=end_type or 'normal',
log="If you are trying to parse this, "
"something has gone horribly wrong",
seed=[random.randrange(65535) for _ in range(4)],
turns=turns or random.randrange(128))
for i in range(len(players)):
log['p{0}'.format(i+1)] = players[i]['username']
log['p{0}team'.format(i+1)] = teams[i]
log['p{0}rating'.format(i+1)] = players[i]
return log