diff --git a/configs/config.json.optimizer.example b/configs/config.json.optimizer.example index 4db7f2cee6..2e91f525d8 100644 --- a/configs/config.json.optimizer.example +++ b/configs/config.json.optimizer.example @@ -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"] @@ -76,7 +125,7 @@ { "type": "MoveToFort", "config": { - "lure_attraction": false, + "lure_attraction": true, "lure_max_distance": 2000, "ignore_item_count": true } @@ -97,6 +146,7 @@ "location_cache": true, "distance_unit": "km", "reconnecting_timeout": 15, + "min_ultraball_to_keep": 10, "logging_color": true, "catch": { "any": { diff --git a/pokemongo_bot/__init__.py b/pokemongo_bot/__init__.py index eabac4e9f3..ff5257c043 100644 --- a/pokemongo_bot/__init__.py +++ b/pokemongo_bot/__init__.py @@ -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',)) @@ -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 diff --git a/pokemongo_bot/cell_workers/evolve_pokemon.py b/pokemongo_bot/cell_workers/evolve_pokemon.py index b5675aba8f..4de40fdb7d 100644 --- a/pokemongo_bot/cell_workers/evolve_pokemon.py +++ b/pokemongo_bot/cell_workers/evolve_pokemon.py @@ -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) diff --git a/pokemongo_bot/cell_workers/pokemon_optimizer.py b/pokemongo_bot/cell_workers/pokemon_optimizer.py index ba7072eb2d..81f78ddf33 100644 --- a/pokemongo_bot/cell_workers/pokemon_optimizer.py +++ b/pokemongo_bot/cell_workers/pokemon_optimizer.py @@ -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) @@ -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: @@ -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) @@ -173,23 +184,27 @@ 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) @@ -197,15 +212,21 @@ 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)) @@ -213,29 +234,39 @@ def apply_optimization(self, transfer, 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", @@ -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}) @@ -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}}} @@ -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 diff --git a/pokemongo_bot/cell_workers/transfer_pokemon.py b/pokemongo_bot/cell_workers/transfer_pokemon.py index a8eb62c34a..f9a6da6fc4 100644 --- a/pokemongo_bot/cell_workers/transfer_pokemon.py +++ b/pokemongo_bot/cell_workers/transfer_pokemon.py @@ -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)