Skip to content

Commit

Permalink
Pokemon optimizer enhancements (#3743)
Browse files Browse the repository at this point in the history
* catching every single pokemon nearby

* catch lured pokemon in all forts nearby

* adding run_interval to some tasks to avoid running all the time and minimum tick time of 5 seconds

Tasks inheriting from BaseTask should use `self._update_last_ran` and
`_time_to_run` if they want to implement the time based running. The
config to set a custom timer is named `run_interval`.

* added config to ignore item count for Spin and MoveToFort

this works good with the `run_interval` configuration added to
TransferPokemon and RecycleItem

* spinning all pokestops in range

* fixing loop in spin fort task

* First basic features of the pokemon optimizer

* For now, dry run only

* Add cygwin to supported platform and improved log readability (#2948)

* Add cygwin to supported platform and improved log readability

* fixed formatting

* - Add dry_run and use_lucky_egg in config
- Evolve all pokemons together and only if enough for a full lucky egg (90).
- Keep enough candies for consecutive evolutions of best pokemons
- Only evolve the lowest rank of a family

* Add lucky egg support when enough pokemon to evolve

* fixing returns

* - Support Eevee evolution scheme
- Rename "use_lucky_egg" parameter in the more accurate "evolve_only_with_lucky_egg"

* Revert "Merge remote-tracking branch 'origin/faeture/xp-improvements' into pokemon_optimizer"

This reverts commit ff1f5e4, reversing
changes made to e8fd901.

* - Fix an issue in evolve_pokemon task
- Use common inventory
- Add configuration example

* Add missing inventory refresh at the end of the process

* Add missing inventory refresh after catching a pokemon

* Add parameters "transfer" and "evolve" to activate/deactivate corresponding action. If both false, this is equivalent to a dry_run.
Add parameters "use_lucky_egg" to allow task to use a lucky egg before evolve.
Add parameter "minimum_evolve_for_lucky_egg" to add a requirement on the number of evolution before using a lucky egg.

* Move some functions around

* Default lucky egg to false + had again parameter "evolve_only_with_lucky_egg"

* Fix qn issue with egg counting
Add configuration parameter to allow customization of how pokemons are ranked in a family

* Update configuration example

* Upgrade to latest inventory

* Fix bug

* Add parameter "use_candies_for_xp" to activate/deactivate usage of candies to maximize xp
Add comments in the configuration example

* Add dps, dps_attack and dps_defense in available sorting keys. So you can now keep the best move.
Add more comments in config
Display ncp and dps for released and evolved pokemons

* Update inventory when releasing and evolving pokemons

* Display Pokemon Bag count update
  • Loading branch information
julienlavergne authored and elicwhite committed Aug 13, 2016
1 parent cf8d2bf commit 9b40f58
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 55 deletions.
56 changes: 53 additions & 3 deletions configs/config.json.optimizer.example
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,74 @@
{
"type": "PokemonOptimizer",
"config": {
"// the 'transfer' parameter activate or deactivate the transfer of pokemons": {},
"// at false, no pokemon is going to be transfered, ever": {},
"// at false, you will still get the log information of what the optimizer": {},
"// would have transfered if the parameter was true": {},
"transfer": true,
"// the 'evolve' parameter activate or deactivate the evolution of pokemons": {},
"// at false, no pokemon is going to be evolved, ever": {},
"// at false, you will still get the log information of what the": {},
"// optimizer would have evolved if the parameter was true": {},
"evolve": true,
"// the 'use_candies_for_xp' parameter let you choose if you want the optimizer": {},
"// to use your candies to evolve low quality pokemons in order to maximize your xp": {},
"// at false, the optimizer will still use candies to evolve your best Pokemons": {},
"use_candies_for_xp": true,
"// the 'use_lucky_egg' parameter let you choose if you want the optimizer": {},
"// to use a lucky egg right before evolving Pokemons. At false; the optimizer": {},
"// is free to evolve Pokemons even if you do not have any lucky egg.": {},
"use_lucky_egg": true,
"// the 'evolve_only_with_lucky_egg' parameter let you choose if you want the optimizer": {},
"// to only Evolve Pokemons when a lucky egg is available": {},
"evolve_only_with_lucky_egg": true,
"// the 'minimum_evolve_for_lucky_egg' parameter let you define the minimum": {},
"// number of Pokemons that must evolve before using a lucky egg": {},
"// If that number is not reached, and evolve_only_with_lucky_egg is true, evolution will be skipped": {},
"// If that number is not reached, and evolve_only_with_lucky_egg is false,": {},
"// evolution will be performed without using a lucky egg": {},
"minimum_evolve_for_lucky_egg": 90,
"// the 'keep' parameter let you define what pokemons you consider are the 'best'. These Pokemons": {},
"// will be keep and evolved. Note that Pokemons are evaluated inside their whole family": {},
"// Multiple way of ranking can be defined. Following configuration let you keep the best iv,": {},
"// the best ncp and the best cp": {},
"keep": [
{
"// Following setting let you keep the best iv of the family": {},
"// the 'top' parameter allow you to define how many Pokemons you want to keep": {},
"// at the top of your ranking. If several Pokemons get the same score, they are": {},
"// considered equal. Thus, top=1 might result in keeping more than 1 Pokemon.": {},
"top": 1,
"// the 'evolve' parameter let you choose if you want to evolve the Pokemons you keep": {},
"evolve": true,
"// Available sorting keys are:": true,
"// iv, cp, ncp, ivcp, max_cp, iv_attack, iv_defense, iv_stamina, hp_max, level": true,
"// the 'sort' parameter define how you want to rank your pokemons": {},
"// Critera are sorted fro, the most important to the least important.": {},
"// Available criteria are:": {},
"// 'iv' = individual value": {},
"// 'ivcp' = iv weigted so that for equal iv, attack > defense > stamina": {},
"// 'cp' = combat power (can be increased with candies)": {},
"// 'cp_exact' = combar power (not rounded)": {},
"// 'ncp' (normalized cp) or 'cp_percent' = ratio cp / max_cp": {},
"// iv_attack = attach component of iv": {},
"// iv_defense = defense component of iv": {},
"// iv_stamina = stamina component of iv": {},
"// dps = raw dps based on the moves of the pokemon": {},
"// dps_attack = average dps when attacking": {},
"// dps_defense = average dps when defending": {},
"// Note that the more criteria you add to this list, the less likely Pokemons": {},
"// will be equals": {},
"sort": ["iv"]
},
{
"// Following setting let you keep keep the best normalized cp of the family": {},
"// That is the Pokemon with higher CP once fully evolved": {},
"top": 1,
"evolve": true,
"sort": ["ncp"]
},
{
"// Following setting let you keep keep the best cp of the family.": {},
"// But will not evolve it further (in favor of the best ncp)": {},
"top": 1,
"evolve": false,
"sort": ["cp"]
Expand Down Expand Up @@ -76,7 +125,7 @@
{
"type": "MoveToFort",
"config": {
"lure_attraction": false,
"lure_attraction": true,
"lure_max_distance": 2000,
"ignore_item_count": true
}
Expand All @@ -97,6 +146,7 @@
"location_cache": true,
"distance_unit": "km",
"reconnecting_timeout": 15,
"min_ultraball_to_keep": 10,
"logging_color": true,
"catch": {
"any": {
Expand Down
4 changes: 2 additions & 2 deletions pokemongo_bot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def _register_events(self):
)
self.event_manager.register_event(
'pokemon_evolved',
parameters=('pokemon', 'iv', 'cp', 'xp')
parameters=('pokemon', 'iv', 'cp', 'ncp', 'dps', 'xp')
)
self.event_manager.register_event('skip_evolve')
self.event_manager.register_event('threw_berry_failed', parameters=('status_code',))
Expand Down Expand Up @@ -392,7 +392,7 @@ def _register_events(self):
)
self.event_manager.register_event(
'pokemon_release',
parameters=('pokemon', 'cp', 'iv')
parameters=('pokemon', 'iv', 'cp', 'ncp', 'dps')
)

# polyline walker
Expand Down
4 changes: 3 additions & 1 deletion pokemongo_bot/cell_workers/evolve_pokemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ def _execute_pokemon_evolve(self, pokemon, cache):
'pokemon': pokemon.name,
'iv': pokemon.iv,
'cp': pokemon.cp,
'xp': 0
'ncp': '?',
'dps': '?',
'xp': '?'
}
)
awarded_candies = response_dict.get('responses', {}).get('EVOLVE_POKEMON', {}).get('candy_awarded', 0)
Expand Down
139 changes: 91 additions & 48 deletions pokemongo_bot/cell_workers/pokemon_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ class PokemonOptimizer(BaseTask):

def initialize(self):
self.family_by_family_id = {}
self.last_pokemon_count = 0
self.logger = logging.getLogger(self.__class__.__name__)

self.config_transfer = self.config.get("transfer", False)
self.config_evolve = self.config.get("evolve", False)
self.config_use_candies_for_xp = self.config.get("use_candies_for_xp", True)
self.config_use_lucky_egg = self.config.get("use_lucky_egg", False)
self.config_evolve_only_with_lucky_egg = self.config.get("evolve_only_with_lucky_egg", True)
self.config_minimum_evolve_for_lucky_egg = self.config.get("minimum_evolve_for_lucky_egg", 90)
Expand All @@ -25,7 +27,13 @@ def initialize(self):
{"top": 1, "evolve": False, "sort": ["cp"]}])

def get_pokemon_slot_left(self):
return self.bot._player["max_pokemon_storage"] - len(inventory.pokemons()._data)
pokemon_count = len(inventory.pokemons()._data)

if pokemon_count != self.last_pokemon_count:
self.last_pokemon_count = pokemon_count
self.logger.info("Pokemon Bag: %s/%s", pokemon_count, self.bot._player["max_pokemon_storage"])

return self.bot._player["max_pokemon_storage"] - pokemon_count

def work(self):
if self.get_pokemon_slot_left() > 5:
Expand Down Expand Up @@ -56,6 +64,9 @@ def parse_inventory(self):
for pokemon in inventory.pokemons().all():
family_id = pokemon.first_evolution_id
setattr(pokemon, "ncp", pokemon.cp_percent)
setattr(pokemon, "dps", pokemon.moveset.dps)
setattr(pokemon, "dps_attack", pokemon.moveset.dps_attack)
setattr(pokemon, "dps_defense", pokemon.moveset.dps_defense)

self.family_by_family_id.setdefault(family_id, []).append(pokemon)

Expand Down Expand Up @@ -173,69 +184,89 @@ def get_evolution_plan(self, family_id, family, evolve_best, keep_best):
next_evo.name = inventory.pokemons().name_for(next_pid)
evolve_best.append(next_evo)

# Compute how many crap we should keep if we want to batch evolve them for xp
junior_evolution_cost = inventory.pokemons().evolution_cost_for(family_id)
if self.config_use_candies_for_xp:
# Compute how many crap we should keep if we want to batch evolve them for xp
junior_evolution_cost = inventory.pokemons().evolution_cost_for(family_id)

# transfer + keep_for_evo = len(crap)
# leftover_candies = candies - len(crap) + transfer * 1
# keep_for_evo = leftover_candies / junior_evolution_cost
#
# keep_for_evo = (candies - len(crap) + transfer) / junior_evolution_cost
# keep_for_evo = (candies - keep_for_evo) / junior_evolution_cost
# transfer + keep_for_evo = len(crap)
# leftover_candies = candies - len(crap) + transfer * 1
# keep_for_evo = leftover_candies / junior_evolution_cost
#
# keep_for_evo = (candies - len(crap) + transfer) / junior_evolution_cost
# keep_for_evo = (candies - keep_for_evo) / junior_evolution_cost

if (candies > 0) and junior_evolution_cost:
keep_for_evo = int(candies / (junior_evolution_cost + 1))
else:
keep_for_evo = 0
if (candies > 0) and junior_evolution_cost:
keep_for_evo = int(candies / (junior_evolution_cost + 1))
else:
keep_for_evo = 0

evo_crap = [p for p in crap if p.has_next_evolution() and p.evolution_cost == junior_evolution_cost][:keep_for_evo]
transfer = [p for p in crap if p not in evo_crap]
evo_crap = [p for p in crap if p.has_next_evolution() and p.evolution_cost == junior_evolution_cost][:keep_for_evo]
transfer = [p for p in crap if p not in evo_crap]
else:
evo_crap = []
transfer = crap

return (transfer, can_evolve_best, evo_crap)

def apply_optimization(self, transfer, evo):
for pokemon in transfer:
self.transfer_pokemon(pokemon)

if self.config_evolve and self.config_use_lucky_egg:
if len(evo) == 0:
return

if self.config_evolve and self.config_use_lucky_egg and (not self.bot.config.test):
lucky_egg = inventory.items().get(Item.ITEM_LUCKY_EGG.value) # @UndefinedVariable

if lucky_egg.count == 0:
if self.config_evolve_only_with_lucky_egg:
self.logger.info("Skipping evolution step. No lucky egg available")
return
elif len(evo) >= self.config_minimum_evolve_for_lucky_egg:
self.use_lucky_egg()
if self.config_evolve_only_with_lucky_egg and (lucky_egg.count == 0):
self.logger.info("Skipping evolution step. No lucky egg available")
return

if len(evo) < self.config_minimum_evolve_for_lucky_egg:
self.logger.info("Skipping evolution step. Not enough Pokemons (%s) to evolve", len(evo))
return

self.use_lucky_egg()

self.logger.info("Evolving %s Pokemons", len(evo))

for pokemon in evo:
self.evolve_pokemon(pokemon)

def transfer_pokemon(self, pokemon):
if self.config_transfer:
self.bot.api.release_pokemon(pokemon_id=pokemon.id)
if self.config_transfer and (not self.bot.config.test):
response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon.id)
else:
pass
response_dict = {"responses": {"RELEASE_POKEMON": {"candy_awarded": 0}}}

if not response_dict:
return False

self.emit_event("pokemon_release",
formatted="Exchanged {pokemon} [IV {iv}] [CP {cp}]",
formatted="Exchanged {pokemon} [IV {iv}] [CP {cp}] [NCP {ncp}] [DPS {dps}]",
data={"pokemon": pokemon.name,
"iv": pokemon.iv,
"cp": pokemon.cp})
"cp": pokemon.cp,
"ncp": round(pokemon.ncp, 2),
"dps": round(pokemon.dps, 2)})

if self.config_transfer and (not self.bot.config.test):
candy = response_dict.get("responses", {}).get("RELEASE_POKEMON", {}).get("candy_awarded", 0)

inventory.candies().get(pokemon.pokemon_id).add(candy)
inventory.pokemons().remove(pokemon.id)

if self.config_transfer:
inventory.candies().get(pokemon.pokemon_id).add(1)
action_delay(self.bot.config.action_wait_min, self.bot.config.action_wait_max)

return True

def use_lucky_egg(self):
lucky_egg = inventory.items().get(Item.ITEM_LUCKY_EGG.value) # @UndefinedVariable

if self.config_evolve and self.config_use_lucky_egg:
response_dict = self.bot.use_lucky_egg()
lucky_egg.remove(1)
else:
response_dict = {"responses": {"USE_ITEM_XP_BOOST": {"result": 1}}}
if lucky_egg.count == 0:
return False

response_dict = self.bot.use_lucky_egg()

if not response_dict:
self.emit_event("lucky_egg_error",
Expand All @@ -246,6 +277,8 @@ def use_lucky_egg(self):
result = response_dict.get("responses", {}).get("USE_ITEM_XP_BOOST", {}).get("result", 0)

if result == 1:
lucky_egg.remove(1)

self.emit_event("used_lucky_egg",
formatted="Used lucky egg ({amount_left} left).",
data={"amount_left": lucky_egg.count})
Expand All @@ -257,7 +290,7 @@ def use_lucky_egg(self):
return False

def evolve_pokemon(self, pokemon):
if self.config_evolve:
if self.config_evolve and (not self.bot.config.test):
response_dict = self.bot.api.evolve_pokemon(pokemon_id=pokemon.id)
else:
response_dict = {"responses": {"EVOLVE_POKEMON": {"result": 1}}}
Expand All @@ -266,20 +299,30 @@ def evolve_pokemon(self, pokemon):
return False

result = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("result", 0)

if result != 1:
return False

xp = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("experience_awarded", 0)
candy = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("candy_awarded", 0)
evolution = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("evolved_pokemon_data", {})

if result == 1:
self.emit_event("pokemon_evolved",
formatted="Evolved {pokemon} [IV {iv}] [CP {cp}] [+{xp} xp]",
data={"pokemon": pokemon.name,
"iv": pokemon.iv,
"cp": pokemon.cp,
"xp": xp})
self.emit_event("pokemon_evolved",
formatted="Evolved {pokemon} [IV {iv}] [CP {cp}] [NCP {ncp}] [DPS {dps}] [+{xp} xp]",
data={"pokemon": pokemon.name,
"iv": pokemon.iv,
"cp": pokemon.cp,
"ncp": round(pokemon.ncp, 2),
"dps": round(pokemon.dps, 2),
"xp": xp})

if self.config_evolve:
inventory.candies().get(pokemon.pokemon_id).consume(pokemon.evolution_cost)
sleep(20)
if self.config_evolve and (not self.bot.config.test):
inventory.candies().get(pokemon.pokemon_id).consume(pokemon.evolution_cost - candy)
inventory.pokemons().remove(pokemon.id)

return True
else:
return False
new_pokemon = inventory.Pokemon(evolution)
inventory.pokemons().add(new_pokemon)

sleep(20)

return True
4 changes: 3 additions & 1 deletion pokemongo_bot/cell_workers/transfer_pokemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ def release_pokemon(self, pokemon):
data={
'pokemon': pokemon.name,
'cp': pokemon.cp,
'iv': pokemon.iv
'iv': pokemon.iv,
'ncp': pokemon.cp_percent,
'dps': pokemon.moveset.dps
}
)
action_delay(self.bot.config.action_wait_min, self.bot.config.action_wait_max)
Expand Down

1 comment on commit 9b40f58

@Daniel-ltw
Copy link

Choose a reason for hiding this comment

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

How does the transfer work with this plugin?

Please sign in to comment.