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

Update TransferPokemon to use new Inventory Class #3320

Merged
merged 5 commits into from
Aug 10, 2016
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
202 changes: 80 additions & 122 deletions pokemongo_bot/cell_workers/transfer_pokemon.py
Original file line number Diff line number Diff line change
@@ -1,139 +1,86 @@
import json
import os

from pokemongo_bot.base_dir import _base_dir
from pokemongo_bot import inventory
from pokemongo_bot.human_behaviour import action_delay
from pokemongo_bot.base_task import BaseTask
from pokemongo_bot.inventory import Pokemons


class TransferPokemon(BaseTask):
SUPPORTED_TASK_API_VERSION = 1

def work(self):
pokemon_groups = self._release_pokemon_get_groups()
for pokemon_id in pokemon_groups:
group = pokemon_groups[pokemon_id]

if len(group) > 0:
pokemon_name = self.bot.pokemon_list[pokemon_id - 1]['Name']
keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)

if keep_best:
best_pokemon_ids = set()
order_criteria = 'none'
if keep_best_cp >= 1:
cp_limit = keep_best_cp
best_cp_pokemons = sorted(group, key=lambda x: (x['cp'], x['iv']), reverse=True)[:cp_limit]
best_pokemon_ids = set(pokemon['pokemon_data']['id'] for pokemon in best_cp_pokemons)
order_criteria = 'cp'

if keep_best_iv >= 1:
iv_limit = keep_best_iv
best_iv_pokemons = sorted(group, key=lambda x: (x['iv'], x['cp']), reverse=True)[:iv_limit]
best_pokemon_ids |= set(pokemon['pokemon_data']['id'] for pokemon in best_iv_pokemons)
if order_criteria == 'cp':
order_criteria = 'cp and iv'
else:
order_criteria = 'iv'

# remove best pokemons from all pokemons array
all_pokemons = group
best_pokemons = []
for best_pokemon_id in best_pokemon_ids:
for pokemon in all_pokemons:
if best_pokemon_id == pokemon['pokemon_data']['id']:
all_pokemons.remove(pokemon)
best_pokemons.append(pokemon)

transfer_pokemons = [pokemon for pokemon in all_pokemons
if self.should_release_pokemon(pokemon_name,
pokemon['cp'],
pokemon['iv'],
True)]

if transfer_pokemons:
if best_pokemons:
self.emit_event(
'keep_best_release',
formatted="Keeping best {amount} {pokemon}, based on {criteria}",
data={
'amount': len(best_pokemons),
'pokemon': pokemon_name,
'criteria': order_criteria
}
)
for pokemon in transfer_pokemons:
self.release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv'], pokemon['pokemon_data']['id'])
else:
group = sorted(group, key=lambda x: x['cp'], reverse=True)
for item in group:
pokemon_cp = item['cp']
pokemon_potential = item['iv']

if self.should_release_pokemon(pokemon_name, pokemon_cp, pokemon_potential):
self.release_pokemon(pokemon_name, item['cp'], item['iv'], item['pokemon_data']['id'])
for pokemon_id, group in pokemon_groups.iteritems():
pokemon_name = Pokemons.name_for(pokemon_id)
keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)

if keep_best:
best_pokemon_ids = set()
order_criteria = 'none'
if keep_best_cp >= 1:
cp_limit = keep_best_cp
best_cp_pokemons = sorted(group, key=lambda x: (x.cp, x.iv), reverse=True)[:cp_limit]
best_pokemon_ids = set(pokemon.id for pokemon in best_cp_pokemons)
order_criteria = 'cp'

if keep_best_iv >= 1:
iv_limit = keep_best_iv
best_iv_pokemons = sorted(group, key=lambda x: (x.iv, x.cp), reverse=True)[:iv_limit]
best_pokemon_ids |= set(pokemon.id for pokemon in best_iv_pokemons)
if order_criteria == 'cp':
order_criteria = 'cp and iv'
else:
order_criteria = 'iv'

# remove best pokemons from all pokemons array
all_pokemons = group
best_pokemons = []
for best_pokemon_id in best_pokemon_ids:
for pokemon in all_pokemons:
if best_pokemon_id == pokemon.id:
all_pokemons.remove(pokemon)
best_pokemons.append(pokemon)

transfer_pokemons = [pokemon for pokemon in all_pokemons if self.should_release_pokemon(pokemon,True)]

if transfer_pokemons:
if best_pokemons:
self.emit_event(
'keep_best_release',
formatted="Keeping best {amount} {pokemon}, based on {criteria}",
data={
'amount': len(best_pokemons),
'pokemon': pokemon_name,
'criteria': order_criteria
}
)
for pokemon in transfer_pokemons:
self.release_pokemon(pokemon)
else:
group = sorted(group, key=lambda x: x.cp, reverse=True)
for pokemon in group:
if self.should_release_pokemon(pokemon):
self.release_pokemon(pokemon)

def _release_pokemon_get_groups(self):
pokemon_groups = {}
request = self.bot.api.create_request()
request.get_player()
request.get_inventory()
inventory_req = request.call()

if inventory_req.get('responses', False) is False:
return pokemon_groups

inventory_dict = inventory_req['responses']['GET_INVENTORY']['inventory_delta']['inventory_items']

user_web_inventory = os.path.join(_base_dir, 'web', 'inventory-%s.json' % (self.bot.config.username))
with open(user_web_inventory, 'w') as outfile:
json.dump(inventory_dict, outfile)

for pokemon in inventory_dict:
try:
reduce(dict.__getitem__, [
"inventory_item_data", "pokemon_data", "pokemon_id"
], pokemon)
except KeyError:
continue

pokemon_data = pokemon['inventory_item_data']['pokemon_data']

# pokemon in fort, so we cant transfer it
if 'deployed_fort_id' in pokemon_data and pokemon_data['deployed_fort_id']:
continue

# favorite pokemon can't transfer in official game client
if pokemon_data.get('favorite', 0) is 1:
for pokemon in inventory.pokemons(True).all():
if pokemon.in_fort or pokemon.is_favorite:
continue

group_id = pokemon_data['pokemon_id']
group_pokemon_cp = pokemon_data['cp']
group_pokemon_iv = self.get_pokemon_potential(pokemon_data)
group_id = pokemon.pokemon_id

if group_id not in pokemon_groups:
pokemon_groups[group_id] = []

pokemon_groups[group_id].append({
'cp': group_pokemon_cp,
'iv': group_pokemon_iv,
'pokemon_data': pokemon_data
})
pokemon_groups[group_id].append(pokemon)

return pokemon_groups

def get_pokemon_potential(self, pokemon_data):
total_iv = 0
iv_stats = ['individual_attack', 'individual_defense', 'individual_stamina']
for individual_stat in iv_stats:
try:
total_iv += pokemon_data[individual_stat]
except Exception:
continue
return round((total_iv / 45.0), 2)

def should_release_pokemon(self, pokemon_name, cp, iv, keep_best_mode = False):
release_config = self._get_release_config_for(pokemon_name)
def should_release_pokemon(self, pokemon, keep_best_mode = False):
release_config = self._get_release_config_for(pokemon.name)

if (keep_best_mode
and not release_config.has_key('never_release')
Expand All @@ -158,11 +105,11 @@ def should_release_pokemon(self, pokemon_name, cp, iv, keep_best_mode = False):
return True

release_cp = release_config.get('release_below_cp', 0)
if cp < release_cp:
if pokemon.cp < release_cp:
release_results['cp'] = True

release_iv = release_config.get('release_below_iv', 0)
if iv < release_iv:
if pokemon.iv < release_iv:
release_results['iv'] = True

logic_to_function = {
Expand All @@ -175,9 +122,9 @@ def should_release_pokemon(self, pokemon_name, cp, iv, keep_best_mode = False):
'future_pokemon_release',
formatted="Releasing {pokemon} (CP {cp}/IV {iv}) based on rule: CP < {below_cp} {cp_iv_logic} IV < {below_iv}",
data={
'pokemon': pokemon_name,
'cp': cp,
'iv': iv,
'pokemon': pokemon.name,
'cp': pokemon.cp,
'iv': pokemon.iv,
'below_cp': release_cp,
'cp_iv_logic': cp_iv_logic.upper(),
'below_iv': release_iv
Expand All @@ -186,16 +133,27 @@ def should_release_pokemon(self, pokemon_name, cp, iv, keep_best_mode = False):

return logic_to_function[cp_iv_logic](*release_results.values())

def release_pokemon(self, pokemon_name, cp, iv, pokemon_id):
response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon_id)
def release_pokemon(self, pokemon):
try:
if self.bot.config.test:
candy_awarded = 1
else:
response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon.id)
candy_awarded = response_dict['responses']['RELEASE_POKEMON']['candy_awarded']
except KeyError:
return

# We could refresh here too, but adding 1 saves a inventory request
candy = inventory.candies().get(pokemon.pokemon_id)
candy.add(candy_awarded)
self.bot.metrics.released_pokemon()
self.emit_event(
'pokemon_release',
formatted='Exchanged {pokemon} [CP {cp}] [IV {iv}] for candy.',
data={
'pokemon': pokemon_name,
'cp': cp,
'iv': iv
'pokemon': pokemon.name,
'cp': pokemon.cp,
'iv': pokemon.iv
}
)
action_delay(self.bot.config.action_wait_min, self.bot.config.action_wait_max)
Expand Down
15 changes: 11 additions & 4 deletions pokemongo_bot/inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,11 @@ def __init__(self, data):
self._static_data = Pokemons.data_for(self.pokemon_id)
self.name = Pokemons.name_for(self.pokemon_id)
self.iv = self._compute_iv()
self.in_fort = 'deployed_fort_id' in data
self.is_favorite = data.get('favorite', 0) is 1

def can_evolve_now(self):
return self.has_next_evolution() and self.candy_quantity > self.evolution_cost
return self.has_next_evolution() and self.candy_quantity >= self.evolution_cost

def has_next_evolution(self):
return 'Next Evolution Requirements' in self._static_data
Expand Down Expand Up @@ -217,11 +219,14 @@ def refresh(self):
# TODO: it would be better if this class was used for all
# inventory management. For now, I'm just clearing the old inventory field
self.bot.latest_inventory = None
inventory = self.bot.get_inventory()['responses']['GET_INVENTORY'][
'inventory_delta']['inventory_items']
inventory = self.bot.get_inventory()['responses']['GET_INVENTORY']['inventory_delta']['inventory_items']
for i in (self.pokedex, self.candy, self.items, self.pokemons):
i.refresh(inventory)

user_web_inventory = os.path.join(_base_dir, 'web', 'inventory-%s.json' % (self.bot.config.username))
with open(user_web_inventory, 'w') as outfile:
json.dump(inventory, outfile)


_inventory = None

Expand All @@ -244,7 +249,9 @@ def candies(refresh=False):
return _inventory.candy


def pokemons():
def pokemons(refresh=False):
if refresh:
refresh_inventory()
return _inventory.pokemons


Expand Down