Skip to content

Commit

Permalink
Add "names" filter to apply sorting rules to selected families only (#…
Browse files Browse the repository at this point in the history
…4313)

Make sure optimizer try its best to reach the minimum evolve count if we want to use lucky eggs
Do not transfer favorite pokemon and pokemon in fort
Add database logging stuff
Update pokemon optimizer config example
Update pokemon.json
  • Loading branch information
julienlavergne authored and solderzzc committed Aug 20, 2016
1 parent d710686 commit 940133f
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 35 deletions.
20 changes: 14 additions & 6 deletions configs/config.json.optimizer.example
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
{
"type": "PokemonOptimizer",
"config": {
"enabled": true,
"// 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": {},
Expand Down Expand Up @@ -114,12 +115,16 @@
"// '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": {},
"// '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": {},
"// 'attack_perfection' = ratio dps_attack / best_dps_attack. Return same order as 'dps_attack'": {},
"// 'dps_defense' = average dps when defending": {},
"// 'defense_perfection' = ratio dps_defense / best_dps_defense. Return same order as 'dps_defense'": {},
"// 'hp' = current health points": {},
"// 'hp_max' = max health points": {},
"// Note that the more criteria you add to this list, the less likely Pokemons": {},
"// will be equals": {},
"sort": ["iv"]
Expand All @@ -134,6 +139,9 @@
{
"// Following setting let you keep keep the best cp of the family.": {},
"// But will not evolve it further (in favor of the best ncp)": {},
"// It will only applies to the family of 'Dragonite', 'Arcanine' and 'Muk'": {},
"// Other families are not following this setting": {},
"names": ["Dragonite", "Arcanine", "Muk"],
"top": 1,
"evolve": false,
"sort": ["cp"]
Expand Down
8 changes: 5 additions & 3 deletions data/pokemon.json
Original file line number Diff line number Diff line change
Expand Up @@ -1609,6 +1609,7 @@
],
"Special Attack(s)": [
"Body Slam",
"Dazzling Gleam",
"Disarming Voice",
"Play Rough",
"Dazzling Gleam"
Expand Down Expand Up @@ -3540,8 +3541,8 @@
"Grass"
],
"Fast Attack(s)": [
"Lick",
"Ice Shard",
"Lick",
"Water Gun"
],
"Weight": "90.0 kg",
Expand Down Expand Up @@ -4805,8 +4806,8 @@
"Grass"
],
"Fast Attack(s)": [
"Tackle",
"Quick Attack",
"Tackle",
"Water Gun"
],
"Weight": "34.5 kg",
Expand Down Expand Up @@ -4865,7 +4866,8 @@
"Special Attack(s)": [
"Hydro Pump",
"Power Gem",
"Psybeam"
"Psybeam",
"Psychic"
],
"BaseAttack": 194,
"BaseDefense": 192,
Expand Down
98 changes: 72 additions & 26 deletions pokemongo_bot/cell_workers/pokemon_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from pokemongo_bot import inventory
from pokemongo_bot.base_dir import _base_dir
from pokemongo_bot.base_task import BaseTask
from pokemongo_bot.datastore import Datastore
from pokemongo_bot.human_behaviour import sleep, action_delay
from pokemongo_bot.item_list import Item
from pokemongo_bot.worker_result import WorkerResult
Expand All @@ -17,9 +18,12 @@
ERROR_LOCATION_UNSET = 5


class PokemonOptimizer(BaseTask):
class PokemonOptimizer(Datastore, BaseTask):
SUPPORTED_TASK_API_VERSION = 1

def __init__(self, bot, config):
super(PokemonOptimizer, self).__init__(bot, config)

def initialize(self):
self.family_by_family_id = {}
self.max_pokemon_storage = inventory.get_pokemon_inventory_size()
Expand All @@ -36,8 +40,8 @@ def initialize(self):
{"top": 1, "evolve": True, "sort": ["ncp"]},
{"top": 1, "evolve": False, "sort": ["cp"]}])

self.transfer_wait_min = self.config.get('transfer_wait_min', 1)
self.transfer_wait_max = self.config.get('transfer_wait_max', 4)
self.config_transfer_wait_min = self.config.get("transfer_wait_min", 1)
self.config_transfer_wait_max = self.config.get("transfer_wait_max", 4)

def get_pokemon_slot_left(self):
pokemon_count = inventory.Pokemons.get_space_used()
Expand Down Expand Up @@ -97,15 +101,21 @@ def save_web_inventory(self):
def get_family_optimized(self, family_id, family):
evolve_best = []
keep_best = []
family_names = self.get_family_names(family_id)

for criteria in self.config_keep:
names = criteria.get("names", [])

if names and not any(n in family_names for n in names):
continue

if criteria.get("evolve", True):
evolve_best += self.get_top_rank(family, criteria)
else:
keep_best += self.get_top_rank(family, criteria)

evolve_best = self.unique_pokemons(evolve_best)
keep_best = self.unique_pokemons(keep_best)
evolve_best = self.unique_pokemon(evolve_best)
keep_best = self.unique_pokemon(keep_best)

return self.get_evolution_plan(family_id, family, evolve_best, keep_best)

Expand All @@ -119,14 +129,20 @@ def get_multi_family_optimized(self, family_id, family, nb_branch):
if not self.config_evolve:
transfer, evo_best, evo_crap = self.get_family_optimized(family_id, other_family)
elif len(senior_pids) < nb_branch:
# We did not get every combination yet = All other Pokemons are potentially good to keep
# We did not get every combination yet = All other Pokemon are potentially good to keep
transfer, evo_best, evo_crap = self.get_evolution_plan(family_id, [], other_family, [])
evo_best.sort(key=lambda p: p.iv * p.ncp, reverse=True)
else:
evolve_best = []
keep_best = []
names = self.get_family_names(family_id)

for criteria in self.config_keep:
family_names = criteria.get("names", [])

if names and not any(n in family_names for n in names):
continue

top = []

for f in senior_grouped_family.values():
Expand All @@ -139,15 +155,21 @@ def get_multi_family_optimized(self, family_id, family, nb_branch):
else:
keep_best += self.get_better_rank(family, criteria, worst)

evolve_best = self.unique_pokemons(evolve_best)
keep_best = self.unique_pokemons(keep_best)
evolve_best = self.unique_pokemon(evolve_best)
keep_best = self.unique_pokemon(keep_best)
transfer, evo_best, evo_crap = self.get_evolution_plan(family_id, other_family, evolve_best, keep_best)

for senior_pid, senior_family in senior_grouped_family.items():
transfer += self.get_family_optimized(senior_pid, senior_family)[0]

return (transfer, evo_best, evo_crap)

def get_family_names(self, family_id):
ids = [family_id]
ids += inventory.Pokemons.data_for(family_id).next_evolutions_all[:]
datas = [inventory.Pokemons.data_for(x) for x in ids]
return [x.name for x in datas]

def get_top_rank(self, family, criteria):
sorted_family = self.get_sorted_family(family, criteria)
index = criteria.get("top", 1) - 1
Expand All @@ -170,7 +192,7 @@ def get_rank(self, pokemon, criteria):
def get_pokemon_max_cp(self, pokemon_name):
return int(self.pokemon_max_cp.get(pokemon_name, 0))

def unique_pokemons(self, l):
def unique_pokemon(self, l):
seen = set()
return [p for p in l if not (p.unique_id in seen or seen.add(p.unique_id))]

Expand All @@ -181,11 +203,12 @@ def get_evolution_plan(self, family_id, family, evolve_best, keep_best):
crap = family[:]
crap = [p for p in crap if p not in evolve_best]
crap = [p for p in crap if p not in keep_best]
crap = [p for p in crap if not p.in_fort and not p.is_favorite]
crap.sort(key=lambda p: p.iv * p.ncp, reverse=True)

candies += len(crap)

# Let's see if we can evolve our best pokemons
# Let's see if we can evolve our best Pokemon
can_evolve_best = []

for pokemon in evolve_best:
Expand Down Expand Up @@ -237,7 +260,7 @@ def get_evolution_plan(self, family_id, family, evolve_best, keep_best):
return (transfer, can_evolve_best, evo_crap)

def apply_optimization(self, transfer, evo):
self.logger.info("Transferring %s Pokemons", len(transfer))
self.logger.info("Transferring %s Pokemon", len(transfer))

for pokemon in transfer:
self.transfer_pokemon(pokemon)
Expand All @@ -246,19 +269,26 @@ def apply_optimization(self, transfer, evo):
return

if self.config_evolve and self.config_may_use_lucky_egg and (not self.bot.config.test):
if len(evo) >= self.config_evolve_count_for_lucky_egg:
lucky_egg = inventory.items().get(Item.ITEM_LUCKY_EGG.value) # @UndefinedVariable
lucky_egg = inventory.items().get(Item.ITEM_LUCKY_EGG.value) # @UndefinedVariable

if lucky_egg.count > 0:
self.use_lucky_egg()
elif self.config_evolve_only_with_lucky_egg:
self.logger.info("Skipping evolution step. No lucky egg available")
if lucky_egg.count == 0:
if self.config_evolve_only_with_lucky_egg:
self.emit_event("skip_evolve",
formatted="Skipping evolution step. No lucky egg available")
return
elif len(evo) < self.config_evolve_count_for_lucky_egg:
if self.config_evolve_only_with_lucky_egg:
self.emit_event("skip_evolve",
formatted="Skipping evolution step. Not enough Pokemon to evolve with lucky egg: %s/%s" % (len(evo), self.config_evolve_count_for_lucky_egg))
return
elif self.get_pokemon_slot_left() > 5:
self.emit_event("skip_evolve",
formatted="Waiting for more Pokemon to evolve with lucky egg: %s/%s" % (len(evo), self.config_evolve_count_for_lucky_egg))
return
elif self.config_evolve_only_with_lucky_egg:
self.logger.info("Skipping evolution step. Not enough Pokemons (%s) to evolve with lucky egg", len(evo))
return
else:
self.use_lucky_egg()

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

for pokemon in evo:
self.evolve_pokemon(pokemon)
Expand All @@ -281,16 +311,23 @@ def transfer_pokemon(self, pokemon):
"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(self.get_candy_gained_count(response_dict))
inventory.candies().get(pokemon.pokemon_id).add(candy)
inventory.pokemons().remove(pokemon.unique_id)

action_delay(self.transfer_wait_min, self.transfer_wait_max)
with self.bot.database as db:
cursor = db.cursor()
cursor.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='transfer_log'")

return True
db_result = cursor.fetchone()

if db_result[0] == 1:
db.execute("INSERT INTO transfer_log (pokemon, iv, cp) VALUES (?, ?, ?)", (pokemon.name, pokemon.iv, pokemon.cp))

action_delay(self.config_transfer_wait_min, self.config_transfer_wait_max)

def get_candy_gained_count(self, response_dict):
return response_dict['responses']['RELEASE_POKEMON']['candy_awarded']
return True

def use_lucky_egg(self):
lucky_egg = inventory.items().get(Item.ITEM_LUCKY_EGG.value) # @UndefinedVariable
Expand Down Expand Up @@ -360,6 +397,15 @@ def evolve_pokemon(self, pokemon):
new_pokemon = inventory.Pokemon(evolution)
inventory.pokemons().add(new_pokemon)

with self.bot.database as db:
cursor = db.cursor()
cursor.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='evolve_log'")

db_result = cursor.fetchone()

if db_result[0] == 1:
db.execute("INSERT INTO evolve_log (pokemon, iv, cp) VALUES (?, ?, ?)", (pokemon.name, pokemon.iv, pokemon.cp))

sleep(self.config_evolve_time)

return True

0 comments on commit 940133f

Please sign in to comment.