Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pokemon optimizer round 3 #4313

Merged
merged 1 commit into from
Aug 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
],
Expand Down Expand Up @@ -3539,8 +3540,8 @@
"Grass"
],
"Fast Attack(s)": [
"Lick",
"Ice Shard",
"Lick",
"Water Gun"
],
"Weight": "90.0 kg",
Expand Down Expand Up @@ -4804,8 +4805,8 @@
"Grass"
],
"Fast Attack(s)": [
"Tackle",
"Quick Attack",
"Tackle",
"Water Gun"
],
"Weight": "34.5 kg",
Expand Down Expand Up @@ -4864,7 +4865,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