diff --git a/configs/config.json.optimizer.example b/configs/config.json.optimizer.example index 287df3c843..80e801896d 100644 --- a/configs/config.json.optimizer.example +++ b/configs/config.json.optimizer.example @@ -18,6 +18,9 @@ "evolve_only_with_lucky_egg": false, "evolve_count_for_lucky_egg": 80, "may_use_lucky_egg": true, + "may_evolve_favorites": true, + "may_upgrade_favorites": true, + "may_unfavor_pokemon": false, "upgrade": true, "upgrade_level": 30, "groups": { diff --git a/docs/pokemon_optimizer.md b/docs/pokemon_optimizer.md index dbb28d6b1a..0ccefad359 100644 --- a/docs/pokemon_optimizer.md +++ b/docs/pokemon_optimizer.md @@ -17,6 +17,9 @@ - [evolve_only_with_lucky_egg](#evolve_only_with_lucky_egg) - [evolve_count_for_lucky_egg](#evolve_count_for_lucky_egg) - [may_use_lucky_egg](#may_use_lucky_egg) + - [may_evolve_favorites](#may_evolve_favorites) + - [may_upgrade_favorites](#may_upgrade_favorites) + - [may_unfavor_pokemon](#may_unfavor_pokemon) - [upgrade](#upgrade) - [upgrade_level](#upgrade_level) - [groups](#groups) @@ -29,6 +32,7 @@ - [evolve](#rule-evolve) - [upgrade](#rule-upgrade) - [buddy](#rule-buddy) + - [favorite](#rule-favorite) - [Eevee case](#eevee-case) - [FAQ](#faq) @@ -42,7 +46,7 @@ There is only one pass at each action. It will also collect the candies from your Buddy and select the next buddy. -In case that logging will be enabled, look for .log file in data folder. +In case that logging will be enabled, look for .log file in data folder. [[back to top](#pokemon-optimizer)] @@ -69,6 +73,9 @@ In case that logging will be enabled, look for .log file in data folder. "evolve_only_with_lucky_egg": false, "evolve_count_for_lucky_egg": 80, "may_use_lucky_egg": true, + "may_evolve_favorites": true, + "may_upgrade_favorites": true, + "may_unfavor_pokemon": false, "upgrade": true, "upgrade_level": 30, "groups": { @@ -333,6 +340,39 @@ Define whether you allow the Pokemon Optimizer to use a lucky egg before evolvin [[back to top](#pokemon-optimizer)] +### may_evolve_favorites +| Parameter | Possible values | Default | +|---------------------|-----------------|---------| +| `may_evolve_favorites` | `true`, `false` | `true` | + +Define whether you allow the Pokemon Optimizer to evolve favorite Pokemon or not. +
At `true`, the Pokemon Optimizer will evolve favorite Pokemon according to the rules. +
At `false`, the Pokemon Optimizer will not evolve favorite Pokemon. + +[[back to top](#pokemon-optimizer)] + +### may_upgrade_favorites +| Parameter | Possible values | Default | +|---------------------|-----------------|---------| +| `may_upgrade_favorites` | `true`, `false` | `true` | + +Define whether you allow the Pokemon Optimizer to upgrade favorite Pokemon or not. +
At `true`, the Pokemon Optimizer will upgrade favorite Pokemon according to the rules. +
At `false`, the Pokemon Optimizer will not upgrade favorite Pokemon. + +[[back to top](#pokemon-optimizer)] + +### may_unfavor_pokemon +| Parameter | Possible values | Default | +|---------------------|-----------------|---------| +| `may_unfavor_pokemon` | `true`, `false` | `false` | + +Define whether you allow the Pokemon Optimizer to unmark favorite Pokemon as favorite or not. +
At `true`, the Pokemon Optimizer will unmark favorite Pokemon if it no longer matches favorite rules. +
At `false`, the Pokemon Optimizer will not unmark favorite Pokemon. + +[[back to top](#pokemon-optimizer)] + ### upgrade | Parameter | Possible values | Default | |-----------|-----------------|---------| @@ -637,6 +677,8 @@ By default, if `evolve` is not provided or is empty, no Pokemon will be evolved. The parameter can be a boolean value (`true` or `false`) or a list a criteria. The available criteria are the same as for the [`sort`](#available-criteria) parameter. +*Note!* If [may_evolve_favorites](#may_evolve_favorites) is `false`, favorite Pokemon will never be evolved! + The minimum requirement values can be a single value or a range.
They can also be a negative value if you wish to evolve Pokemon below a certain criteria: @@ -663,8 +705,10 @@ By default, if `upgrade` is not provided or is empty, no Pokemon will be upgrade The parameter can be a boolean value (`true` or `false`) or a list a criteria. The available criteria are the same as for the [`sort`](#available-criteria) parameter. +*Note!* If [may_upgrade_favorites](#may_upgrade_favorites) is `false`, favorite Pokemon will never be upgraded! + The minimum requirement values can be a single value or a range. -
They can also be a negative value if you wish to evolve Pokemon below a certain criteria: +
They can also be a negative value if you wish to upgrade Pokemon below a certain criteria: - `"upgrade": false` will not try to upgrade any of the Pokemon selected. - `"upgrade": true` will try to upgrade all Pokemon selected. @@ -677,6 +721,32 @@ The minimum requirement values can be a single value or a range. [[back to top](#pokemon-optimizer)] +#### rule favorite +| Parameter | Possible values | Default | +|-----------|-----------------|---------| +| `favorite` | (see below) | `false` | + +Define minimum requirements to favorite the Pokemon. +Only Pokemon meeting these minimum requirements will be marked as favorite. +By default, if `favorite` is not provided or is empty, no Pokemon will be marked favorite. + +The parameter can be a boolean value (`true` or `false`) or a list a criteria. +The available criteria are the same as for the [`sort`](#available-criteria) parameter. + +The minimum requirement values can be a single value or a range. +
They can also be a negative value if you wish to mark Pokemon below a certain criteria as favorite: + +- `"favorite": false` will not try to mark any of the Pokemon selected as favorite. +- `"favorite": true` will try to mark all Pokemon selected as favorite. +- `"favorite": {"iv": 0.9}` will only favorite Pokemon with `iv` greater than `0.9`. +- `"favorite": {"iv": 0.9, "cp": 1200}` will only favorite Pokemon with `iv` greater than `0.9` and `cp` greater than `1200`. +- `"favorite": {"iv": 0.9}` will only favorite Pokemon with `iv` greater than `0.9`. +- `"favorite": {"cp": -20}` will only favorite Pokemon with `cp` lower than `20`. +- `"favorite": {"cp": [10, 20]}` will only favorite Pokemon with `cp` between `10` and `20`. +- `"favorite": {"iv": [[0.3, 0.5], [0.9, 1.0]]}` will only favorite Pokemon with `iv` between `0.3` and `0.5` or between `0.9` and `1.0`. + +[[back to top](#pokemon-optimizer)] + #### rule buddy | Parameter | Possible values | Default | |-----------|-----------------|---------| diff --git a/pokemongo_bot/__init__.py b/pokemongo_bot/__init__.py index 1ce7c0bf09..45d873c179 100644 --- a/pokemongo_bot/__init__.py +++ b/pokemongo_bot/__init__.py @@ -509,6 +509,14 @@ def _register_events(self): 'pokemon_evolved', parameters=('pokemon', 'iv', 'cp', 'candy', 'xp') ) + self.event_manager.register_event( + 'pokemon_favored', + parameters=('pokemon', 'iv', 'cp') + ) + self.event_manager.register_event( + 'pokemon_unfavored', + parameters=('pokemon', 'iv', 'cp') + ) self.event_manager.register_event( 'pokemon_evolve_check', parameters=('has', 'needs') diff --git a/pokemongo_bot/cell_workers/pokemon_optimizer.py b/pokemongo_bot/cell_workers/pokemon_optimizer.py index 4e92e02f4f..bc21849104 100644 --- a/pokemongo_bot/cell_workers/pokemon_optimizer.py +++ b/pokemongo_bot/cell_workers/pokemon_optimizer.py @@ -70,6 +70,9 @@ def initialize(self): self.config_evolve_only_with_lucky_egg = self.config.get("evolve_only_with_lucky_egg", False) self.config_evolve_count_for_lucky_egg = self.config.get("evolve_count_for_lucky_egg", 80) self.config_may_use_lucky_egg = self.config.get("may_use_lucky_egg", False) + self.config_may_evolve_favorites = self.config.get("may_evolve_favorites", True) + self.config_may_upgrade_favorites = self.config.get("may_upgrade_favorites", True) + self.config_may_unfavor_pokemon = self.config.get("may_unfavor_pokemon", False) self.config_upgrade = self.config.get("upgrade", False) self.config_upgrade_level = self.config.get("upgrade_level", 30) self.config_groups = self.config.get("groups", {"gym": ["Dragonite", "Snorlax", "Lapras", "Arcanine"]}) @@ -124,108 +127,136 @@ def work(self): if not self.enabled: return WorkerResult.SUCCESS - self.check_buddy() + # Repeat the optimizer 2 times, to get rid of the trash evolved. + for _ in itertools.repeat(None, 2): + self.check_buddy() + self.open_inventory() - if self.lock_buddy and (self.get_pokemon_slot_left() > self.config_min_slots_left): - return WorkerResult.SUCCESS + keep_all = [] + try_evolve_all = [] + try_upgrade_all = [] + buddy_all = [] + favor_all = [] - self.open_inventory() + for rule in self.config_rules: + mode = rule.get("mode", "by_family") + names = rule.get("names", []) + check_top = rule.get("top", "all") + check_keep = rule.get("keep", True) + whitelist, blacklist = self.get_colorlist(names) - keep_all = [] - try_evolve_all = [] - try_upgrade_all = [] - buddy_all = [] + if check_top == "all" and names == [] and check_keep: + self.logger.info("WARNING!! Will not transfer any Pokemon!!") + self.logger.info(rule) + self.logger.info("This rule is set to keep (`keep` is true) all Pokemon (no `top` and no `names` set!!)") + self.logger.info("Are you sure you want this?") - for rule in self.config_rules: - mode = rule.get("mode", "by_family") - names = rule.get("names", []) - whitelist, blacklist = self.get_colorlist(names) + if mode == "by_pokemon": + for pokemon_id, pokemon_list in self.group_by_pokemon_id(inventory.pokemons().all()): + name = inventory.pokemons().name_for(pokemon_id) - if mode == "by_pokemon": - for pokemon_id, pokemon_list in self.group_by_pokemon_id(inventory.pokemons().all()): - name = inventory.pokemons().name_for(pokemon_id) + if name in blacklist: + continue - if name in blacklist: - continue + if whitelist and (name not in whitelist): + continue - if whitelist and (name not in whitelist): - continue + sorted_list = self.score_and_sort(pokemon_list, rule) - sorted_list = self.score_and_sort(pokemon_list, rule) + if len(sorted_list) == 0: + continue - if len(sorted_list) == 0: - continue + keep, try_evolve, try_upgrade, buddy, favor = self.get_best_pokemon_for_rule(sorted_list, rule) + keep_all += keep + try_evolve_all += try_evolve + try_upgrade_all += try_upgrade + buddy_all += buddy + favor_all += favor + elif mode == "by_family": + for family_id, pokemon_list in self.group_by_family_id(inventory.pokemons().all()): + matching_names = self.get_family_names(family_id) - keep, try_evolve, try_upgrade, buddy = self.get_best_pokemon_for_rule(sorted_list, rule) - keep_all += keep - try_evolve_all += try_evolve - try_upgrade_all += try_upgrade - buddy_all += buddy - elif mode == "by_family": - for family_id, pokemon_list in self.group_by_family_id(inventory.pokemons().all()): - matching_names = self.get_family_names(family_id) + if any(n in blacklist for n in matching_names): + continue - if any(n in blacklist for n in matching_names): - continue + if whitelist and not any(n in whitelist for n in matching_names): + continue - if whitelist and not any(n in whitelist for n in matching_names): - continue + sorted_list = self.score_and_sort(pokemon_list, rule) + + if len(sorted_list) == 0: + continue + + if family_id == 133: # "Eevee" + keep, try_evolve, try_upgrade, buddy, favor = self.get_multi_best_pokemon_for_rule(sorted_list, rule, 3) + else: + keep, try_evolve, try_upgrade, buddy, favor = self.get_best_pokemon_for_rule(sorted_list, rule) + + keep_all += keep + try_evolve_all += try_evolve + try_upgrade_all += try_upgrade + buddy_all += buddy + favor_all += favor + elif mode == "overall": + pokemon_list = [] + + for pokemon in inventory.pokemons().all(): + name = pokemon.name + + if name in blacklist: + continue + + if whitelist and (name not in whitelist): + continue + + pokemon_list.append(pokemon) sorted_list = self.score_and_sort(pokemon_list, rule) if len(sorted_list) == 0: continue - if family_id == 133: # "Eevee" - keep, try_evolve, try_upgrade, buddy = self.get_multi_best_pokemon_for_rule(sorted_list, rule, 3) - else: - keep, try_evolve, try_upgrade, buddy = self.get_best_pokemon_for_rule(sorted_list, rule) - + keep, try_evolve, try_upgrade, buddy, favor = self.get_best_pokemon_for_rule(sorted_list, rule) keep_all += keep try_evolve_all += try_evolve try_upgrade_all += try_upgrade buddy_all += buddy - elif mode == "overall": - pokemon_list = [] - + favor_all += favor + + keep_all = self.unique_pokemon_list(keep_all) + try_evolve_all = self.unique_pokemon_list(try_evolve_all) + try_upgrade_all = self.unique_pokemon_list(try_upgrade_all) + buddy_all = self.unique_pokemon_list(buddy_all) + try_favor_all = self.unique_pokemon_list(favor_all) + # Favorites has nothing to do with evolve, can be done even when bag not full + # Like a buddy + if self.config_may_unfavor_pokemon: + unfavor = [] for pokemon in inventory.pokemons().all(): - name = pokemon.name - - if name in blacklist: - continue - - if whitelist and (name not in whitelist): - continue - - pokemon_list.append(pokemon) - - sorted_list = self.score_and_sort(pokemon_list, rule) - - if len(sorted_list) == 0: - continue - - keep, try_evolve, try_upgrade, buddy = self.get_best_pokemon_for_rule(sorted_list, rule) - keep_all += keep - try_evolve_all += try_evolve - try_upgrade_all += try_upgrade - buddy_all += buddy - - keep_all = self.unique_pokemon_list(keep_all) - try_evolve_all = self.unique_pokemon_list(try_evolve_all) - try_upgrade_all = self.unique_pokemon_list(try_upgrade_all) - buddy_all = self.unique_pokemon_list(buddy_all) - - if (not self.lock_buddy) and (len(buddy_all) > 0): - new_buddy = buddy_all[0] - - if (not self.buddy) or (self.buddy["id"] != new_buddy.unique_id): - self.set_buddy_pokemon(new_buddy) + if not pokemon in try_favor_all and pokemon.is_favorite: + unfavor.append(pokemon) + if len(unfavor) > 0: + self.logger.info("Marking %s Pokemon as no longer favorite", len(unfavor)) + for pokemon in unfavor: + self.unfavor_pokemon(pokemon) + # Dont favor Pokemon if already a favorite + try_favor_all = [p for p in try_favor_all if not p.is_favorite] + if len(try_favor_all) > 0: + self.logger.info("Setting %s Poken as favorite", len(try_favor_all)) + + for pokemon in try_favor_all: + if pokemon.is_favorite is False: + self.favor_pokemon(pokemon) + + if (not self.lock_buddy) and (len(buddy_all) > 0): + new_buddy = buddy_all[0] + + if (not self.buddy) or (self.buddy["id"] != new_buddy.unique_id): + self.set_buddy_pokemon(new_buddy) + + if self.get_pokemon_slot_left() > self.config_min_slots_left: + return WorkerResult.SUCCESS - if self.get_pokemon_slot_left() > self.config_min_slots_left: - return WorkerResult.SUCCESS - - # Repeat the optimizer 2 times, to get rid of the trash evolved. - for _ in itertools.repeat(None, 2): transfer_all = [] evolve_all = [] upgrade_all = [] @@ -234,6 +265,7 @@ def work(self): keep = [p for p in keep_all if self.get_family_id(p) == family_id] try_evolve = [p for p in try_evolve_all if self.get_family_id(p) == family_id] try_upgrade = [p for p in try_upgrade_all if self.get_family_id(p) == family_id] + try_favor = [p for p in try_favor_all if self.get_family_id(p) == family_id] transfer, evolve, upgrade, xp = self.get_evolution_plan(family_id, pokemon_list, keep, try_evolve, try_upgrade) @@ -242,6 +274,14 @@ def work(self): upgrade_all += upgrade xp_all += xp + if not self.config_may_evolve_favorites: + self.logger.info("Removing favorites from evolve list.") + evolve_all = [p for p in evolve_all if not p.is_favorite] + + if not self.config_may_upgrade_favorites: + self.logger.info("Removing favorites from upgrade list.") + upgrade_all = [p for p in upgrade_all if not p.is_favorite] + self.apply_optimization(transfer_all, evolve_all, upgrade_all, xp_all) return WorkerResult.SUCCESS @@ -399,6 +439,7 @@ def get_score(self, pokemon, rule): rule_evolve = rule.get("evolve", True) rule_upgrade = rule.get("upgrade", False) rule_buddy = rule.get("buddy", False) + rule_favor = rule.get("favorite", False) keep = rule_keep not in [False, {}] keep &= self.satisfy_requirements(pokemon, rule_keep) @@ -414,10 +455,13 @@ def get_score(self, pokemon, rule): may_buddy &= pokemon.in_fort is False may_buddy &= self.satisfy_requirements(pokemon, may_buddy) + may_favor = rule_favor not in [False, {}] + may_favor &= self.satisfy_requirements(pokemon, may_favor) + if self.debug: - self.log("%s %s %s %s %s %s" % (pokemon, tuple(score), keep, may_try_evolve, may_try_upgrade, may_buddy)) + self.log("P:%s S:%s K:%s E:%s U:%s B:%s F:%s" % (pokemon, tuple(score), keep, may_try_evolve, may_try_upgrade, may_buddy, may_favor)) - return tuple(score), keep, may_try_evolve, may_try_upgrade, may_buddy + return tuple(score), keep, may_try_evolve, may_try_upgrade, may_buddy, may_favor def satisfy_requirements(self, pokemon, req): if type(req) is bool: @@ -487,22 +531,25 @@ def get_multi_best_pokemon_for_rule(self, family_list, rule, nb_branch): try_evolve_all = [] try_upgrade_all = [] buddy_all = [] + favor_all = [] if not self.config_evolve: # Player handle evolution manually = Fall-back to per Pokemon behavior for _, pokemon_list in self.group_by_pokemon_id(family_list): - keep, try_evolve, try_upgrade, buddy = self.get_best_pokemon_for_rule(pokemon_list, rule) + keep, try_evolve, try_upgrade, buddy, favor = self.get_best_pokemon_for_rule(pokemon_list, rule) keep_all += keep try_evolve_all += try_evolve try_upgrade_all += try_upgrade buddy_all += buddy + favor_all += favor else: for _, pokemon_list in self.group_by_pokemon_id(senior_pokemon_list): - keep, try_evolve, try_upgrade, buddy = self.get_best_pokemon_for_rule(pokemon_list, rule) + keep, try_evolve, try_upgrade, buddy, favor = self.get_best_pokemon_for_rule(pokemon_list, rule) keep_all += keep try_evolve_all += try_evolve try_upgrade_all += try_upgrade buddy_all += buddy + favor_all += favor if len(other_family_list) > 0: if len(senior_pids) < nb_branch: @@ -513,21 +560,23 @@ def get_multi_best_pokemon_for_rule(self, family_list, rule, nb_branch): best.sort(key=lambda p: p.__score__[0], reverse=True) worst = best[-1] - keep, try_evolve, try_upgrade, buddy = self.get_better_pokemon(other_family_list, worst, 12) + keep, try_evolve, try_upgrade, buddy, favor = self.get_better_pokemon(other_family_list, worst, 12) keep_all += keep try_evolve_all += try_evolve try_upgrade_all += try_upgrade buddy_all += buddy + favor_all += favor - return keep_all, try_evolve_all, try_upgrade_all, buddy_all + return keep_all, try_evolve_all, try_upgrade_all, buddy_all, favor_all def get_better_pokemon(self, pokemon_list, worst, limit=1000): keep = [p for p in pokemon_list if p.__score__[0] >= worst.__score__[0]][:limit] try_evolve = [p for p in keep if p.__score__[2] is True] try_upgrade = [p for p in keep if (p.__score__[2] is False) and (p.__score__[3] is True)] buddy = [p for p in keep if p.__score__[4] is True] + favor = [p for p in keep if p.__score__[5] is True] - return keep, try_evolve, try_upgrade, buddy + return keep, try_evolve, try_upgrade, buddy, favor def get_evolution_plan(self, family_id, family_list, keep, try_evolve, try_upgrade): candies = inventory.candies().get(family_id).quantity @@ -725,13 +774,13 @@ def transfer_pokemon(self, pokemons): return False except Exception: return False - + for pokemon in transfered: candy = inventory.candies().get(pokemon.pokemon_id) if self.config_transfer and (not self.bot.config.test): candy.add(1) - + self.emit_event("pokemon_release", formatted="Exchanged {pokemon} [IV {iv}] [CP {cp}] [{candy} candies]", data={"pokemon": pokemon.name, @@ -997,3 +1046,31 @@ def _get_buddyid(self): if self.buddy and'id' in self.buddy: return self.buddy['id'] return 0 + + def favor_pokemon(self, pokemon): + response_dict = self.bot.api.set_favorite_pokemon(pokemon_id=pokemon.unique_id, is_favorite=True) + if response_dict: + result = response_dict.get('responses', {}).get('SET_FAVORITE_POKEMON', {}).get('result', 0) + if result is 1: # Request success + # Mark Pokemon as favorite + pokemon.is_favorite = True + self.emit_event("pokemon_favored", + formatted="Favored {pokemon} [IV {iv}] [CP {cp}]", + data={"pokemon": pokemon.name, + "iv": pokemon.iv, + "cp": pokemon.cp}) + action_delay(self.config_action_wait_min, self.config_action_wait_max) + + def unfavor_pokemon(self, pokemon): + response_dict = self.bot.api.set_favorite_pokemon(pokemon_id=pokemon.unique_id, is_favorite=False) + if response_dict: + result = response_dict.get('responses', {}).get('SET_FAVORITE_POKEMON', {}).get('result', 0) + if result is 1: # Request success + # Mark Pokemon as no longer favorite + pokemon.is_favorite = False + self.emit_event("pokemon_unfavored", + formatted="Unfavored {pokemon} [IV {iv}] [CP {cp}]", + data={"pokemon": pokemon.name, + "iv": pokemon.iv, + "cp": pokemon.cp}) + action_delay(self.config_action_wait_min, self.config_action_wait_max)