Skip to content

Commit

Permalink
[Feature] added keep pokemon for batch evolution (#2255)
Browse files Browse the repository at this point in the history
* added keep_for_evo

* accounted for non evolable pokemon

* additional logging

* additional logging

* moved get_candies to utils

* disregard 2nd stage evolution pokemon

* added sample configs
  • Loading branch information
MFizz authored and douglascamata committed Aug 2, 2016
1 parent 550b2c3 commit ea42eac
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 33 deletions.
5 changes: 5 additions & 0 deletions configs/config.json.cluster.example
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@
"// any": {"keep_best_iv": 3},
"// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat:": {},
"// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3}
"// Example of keeping as many Zubat as you have candy to evolve,
"// Zubat": {"keep_for_evo": true}
"// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat and on top as many Zubat
as you have candy to evolve:": {},
"// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3, "keep_for_evo": true}
},
"vips" : {
"Any pokemon put here directly force to use Berry & Best Ball to capture, to secure the capture rate!": {},
Expand Down
5 changes: 5 additions & 0 deletions configs/config.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@
"// any": {"keep_best_iv": 3},
"// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat:": {},
"// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3}
"// Example of keeping as many Zubat as you have candy to evolve,
"// Zubat": {"keep_for_evo": true}
"// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat and on top as many Zubat
as you have candy to evolve:": {},
"// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3, "keep_for_evo": true}
},
"vips" : {
"Any pokemon put here directly force to use Berry & Best Ball to capture, to secure the capture rate!": {},
Expand Down
5 changes: 5 additions & 0 deletions configs/config.json.path.example
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@
"any": {"catch_above_cp": 0, "catch_above_iv": 0, "logic": "or"},
"// Example of always catching Rattata:": {},
"// Rattata": { "always_catch" : true }
"// Example of keeping as many Zubat as you have candy to evolve,
"// Zubat": {"keep_for_evo": true}
"// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat and on top as many Zubat
as you have candy to evolve:": {},
"// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3, "keep_for_evo": true}
},
"release": {
"any": {"release_below_cp": 0, "release_below_iv": 0, "logic": "or"},
Expand Down
105 changes: 72 additions & 33 deletions pokemongo_bot/cell_workers/transfer_pokemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@
from pokemongo_bot import logger
from pokemongo_bot.human_behaviour import action_delay
from pokemongo_bot.cell_workers.base_task import BaseTask
from pokemongo_bot.cell_workers.utils import get_candies


class TransferPokemon(BaseTask):
def work(self):
pokemon_groups = self._release_pokemon_get_groups()
candies = get_candies(self.bot)
evolvable = 0
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)
keep_best, keep_best_cp, keep_best_iv, keep_for_evo = self._validate_keep_best_config(pokemon_name)

if keep_best:
best_pokemon_ids = set()
Expand All @@ -33,41 +37,74 @@ def work(self):
order_criteria = 'iv'

# remove best pokemons from all pokemons array
all_pokemons = group
best_pokemons = []
best_pokemon = []
for best_pokemon_id in best_pokemon_ids:
for pokemon in all_pokemons:
for pokemon in group:
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)]
group.remove(pokemon)
best_pokemon.append(pokemon)

if transfer_pokemons:
logger.log("Keep {} best {}, based on {}".format(len(best_pokemons),
if len(best_pokemon) > 0:
logger.log("Keep {} best {}, based on {}".format(len(best_pokemon),
pokemon_name,
order_criteria), "green")
for best_pokemon in best_pokemons:
for best_pokemon in best_pokemon:
logger.log("{} [CP {}] [Potential {}]".format(pokemon_name,
best_pokemon['cp'],
best_pokemon['iv']), 'green')

logger.log("Transferring {} pokemon".format(len(transfer_pokemons)), "green")
high_pokemon = []
for pokemon in group:
if self.should_release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv']):
group.remove(pokemon)
high_pokemon.append(pokemon)
if len(high_pokemon) > 0:
logger.log("Keep {} {}, based on cp/iv criteria".format(len(high_pokemon),
pokemon_name), "green")
for high_pokemon in high_pokemon:
logger.log("{} [CP {}] [Potential {}]".format(pokemon_name,
high_pokemon['cp'],
high_pokemon['iv']), 'green')

if keep_for_evo and len(group) > 0:
if 'Previous evolution(s)' in self.bot.pokemon_list[pokemon_id - 1]:
logger.log(
'{} has previous evolution stages. This focuses on 1st stage because they use less '
'candy'.format(pokemon_name), 'red')
continue

if candies == {}:
logger.log("Api call for candies failed, try again")
return
candy = candies[pokemon_id]
if 'Next Evolution Requirements' in self.bot.pokemon_list[pokemon_id - 1]:
req_candy = self.bot.pokemon_list[pokemon_id - 1]['Next Evolution Requirements']['Amount']
num_keep = (len(group) + candy) / (req_candy + 1)

if len(group) > num_keep:
group.sort(key=lambda x: x['iv'], reverse=True)
evo_pokemon = group[:num_keep]
group = group[num_keep:]
else:
evo_pokemon = group
group = []

evolvable += len(evo_pokemon)
if len(evo_pokemon) > 0:
logger.log("Keep {} {}, for evolution - {} candies".format(len(evo_pokemon),
pokemon_name, candy), "green")
for evo_pokemon in evo_pokemon:
logger.log("{} [CP {}] [Potential {}]".format(pokemon_name,
evo_pokemon['cp'],
evo_pokemon['iv']), 'green')

logger.log("Transferring {} {}".format(len(group), pokemon_name), "green")

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']
for pokemon in group:
self.release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv'], pokemon['pokemon_data']['id'])

if self.should_release_pokemon(pokemon_name, pokemon_cp, pokemon_potential):
self.release_pokemon(pokemon_name, item['cp'], item['iv'], item['pokemon_data']['id'])
logger.log("{} pokemon transferred total. {} evolutions ready (based on pokemons additional to the ones kept"
" with cp/iv criteria)".format(len(group), evolvable), "green")

def _release_pokemon_get_groups(self):
pokemon_groups = {}
Expand Down Expand Up @@ -126,15 +163,16 @@ def get_pokemon_potential(self, pokemon_data):
continue
return round((total_iv / 45.0), 2)

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

if (keep_best_mode
and not release_config.has_key('never_release')
and not release_config.has_key('always_release')
and not release_config.has_key('release_below_cp')
and not release_config.has_key('release_below_iv')):
return True
release_strings = ['never_release', 'always_release', 'release_below_cp', 'release_below_iv']
keep_strings = ['keep_best_cp', 'keep_best_iv']
if not any(x in release_config for x in release_strings):
if any(x in release_config for x in keep_strings):
return True
else:
return False

cp_iv_logic = release_config.get('logic')
if not cp_iv_logic:
Expand Down Expand Up @@ -201,6 +239,7 @@ def _validate_keep_best_config(self, pokemon_name):

keep_best_cp = release_config.get('keep_best_cp', 0)
keep_best_iv = release_config.get('keep_best_iv', 0)
keep_for_evo = release_config.get('keep_for_evo', False)

if keep_best_cp or keep_best_iv:
keep_best = True
Expand All @@ -221,4 +260,4 @@ def _validate_keep_best_config(self, pokemon_name):
if keep_best_cp == 0 and keep_best_iv == 0:
keep_best = False

return keep_best, keep_best_cp, keep_best_iv
return keep_best, keep_best_cp, keep_best_iv, keep_for_evo
11 changes: 11 additions & 0 deletions pokemongo_bot/cell_workers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,14 @@ def find_biggest_cluster(radius, points, order=None):
return {'latitude': best_coord[0], 'longitude': best_coord[1], 'num_points': len(max_clique)}
else:
return None


def get_candies(bot):
response_dict = bot.get_inventory()
inv = response_dict.get("responses", {}).get("GET_INVENTORY", {}).get("inventory_delta").get("inventory_items")
candies = {}
for item in inv:
candy = item.get("inventory_item_data", {}).get("candy", {})
if candy != {}:
candies[candy['family_id']] = candy['candy']
return candies

15 comments on commit ea42eac

@DanielVolz
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bot just released my best pokemon and my config is the same:
screenshot 2016-08-02 20 20 12
I don't konw if it's this PR but it's my best guess.

@douglascamata
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverting this.

@KLVN
Copy link
Contributor

@KLVN KLVN commented on ea42eac Aug 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DanielVolz Have you just copied and pasted the example config.json?

@DanielVolz
Copy link

@DanielVolz DanielVolz commented on ea42eac Aug 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KLVN no, I used my "old" one. Some commits before this PR.

@DanielVolz
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@douglascamata man you're fast ;). Thanks for the great work!

@relomy
Copy link

@relomy relomy commented on ea42eac Aug 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be working fine for me. Curious to hear what the issue is. :)

@g2384
Copy link

@g2384 g2384 commented on ea42eac Aug 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is painful. I'm so scared now.

@DanielVolz
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@g2384 tell me about it :(

@douglascamata
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I already reverted this.

@surewhynotmon
Copy link

@surewhynotmon surewhynotmon commented on ea42eac Aug 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed that this also contributed to
[14:28:11] Exchanging Vaporeon [CP 1250] [Potential 0.8] for candy!
[14:28:14] Exchanging Snorlax [CP 1757] [Potential 0.89] for candy!

Everyone needs to be more alert about transfer_pokemon changes now.

@KLVN
Copy link
Contributor

@KLVN KLVN commented on ea42eac Aug 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everyone needs to be more alert about transfer_pokemon changes now.

I would disable every option that could result in transfers and set release_configs to 0, so users have to change it by themselves and are aware of config.json and what it does. Also it's their own fault if they set wrong values.

@surewhynotmon
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KLVN I had config set very specifically
"any": {"keep_best_iv": 2, "release_below_cp": 1000, "release_below_iv": 0.8, "logic": "or"},
"Snorlax": { "release_below_cp": 0, "release_below_iv": 0.8, "logic": "and" }.
That Snorlax or Vaporeon does not meet any of those rules...Even worse, the commit also removed the log output on why a Pokemon was removed so there is no way to know why it happened.

That commit just ignored the config altogether.

If previous commit doesn't release Pokemons, and suddenly out of nowhere a new commit just start releasing pokemons on the same config, the user can't do much about it except being paranoid and careful about dev branch, commenting out the Release api call and dry-run it first before actually doing any release api call.

Honestly, a dry-run option for this may not be a bad idea since it deals with an irreversible change happening once on startup, so user has an option to test their release rules between git pull or config changes.

@Strange-Penguin
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A way to test the configs would be great. A dry-run so the bot outputs

Snorlax [CP 1757] [Potential 0.89] would be released (Matches {rule here})

@KLVN
Copy link
Contributor

@KLVN KLVN commented on ea42eac Aug 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or an optional prompt that asks every time before a Pokemon will be released/transferred.

"tasks": [ { "type": "PromptBeforeTransfer" }

Snorlax [CP 1757] [Potential 0.89] matches criteria {rule here}. Release? (y/n)

@surewhynotmon
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will require supervision though. Think knowing why and ability to dry-run after git pull would be enough.

Please sign in to comment.