Browse Source
- Mostly all working, about 7 or so forms not account for, excluding event pokemonplan_generation
6 changed files with 516 additions and 3 deletions
@ -0,0 +1,367 @@ |
|||
from PyQt6.QtCore import QObject, pyqtSignal, QRunnable |
|||
import json |
|||
|
|||
from cache import cache |
|||
from db import db |
|||
|
|||
from utility.data import exclusive_choice_pokemon |
|||
from utility.functions import get_shiftable_forms, parse_pfic |
|||
|
|||
class GeneratePlanWorkerSignals(QObject): |
|||
finished = pyqtSignal(dict) |
|||
|
|||
class GeneratePlanWorker(QRunnable): |
|||
def __init__(self): |
|||
super().__init__() |
|||
self.signals = GeneratePlanWorkerSignals() |
|||
self.caught_pokemon = {} |
|||
self.group_plan = [] |
|||
self.game_plan = [] |
|||
|
|||
def run(self): |
|||
try: |
|||
gathered_data = self.generate_plan() |
|||
self.signals.finished.emit(gathered_data) |
|||
except Exception as e: |
|||
print(f"Error gathering Pokémon home storage status: {e}") |
|||
|
|||
def generate_plan(self): |
|||
generational_groups = [1, 2], [3, 4, 5], [6], [7], [8], [9] |
|||
|
|||
for group in generational_groups: |
|||
group_plan = self.plan_for_group(group) |
|||
self.group_plan.append(group_plan) |
|||
|
|||
for group in self.group_plan: |
|||
for game in group: |
|||
game_plan = self.plan_for_game(game, group[game]) |
|||
self.game_plan.append(game_plan) |
|||
|
|||
storable_in_home = db.get_pokemon_home_list() |
|||
|
|||
total_accounted_for = 0 |
|||
for entry in self.game_plan: |
|||
total_accounted_for += len(entry["pokemon_map"]) |
|||
|
|||
total_needed = len(storable_in_home) |
|||
|
|||
for home_pokemon in storable_in_home: |
|||
found = False |
|||
for game in self.game_plan: |
|||
if home_pokemon["PFIC"] in game["pokemon_map"]: |
|||
found = True |
|||
break |
|||
if not found: |
|||
print(home_pokemon) |
|||
|
|||
return {} |
|||
|
|||
def plan_for_group(self, group): |
|||
group_plan = [] |
|||
needed_pokemon = set() |
|||
games_in_group = [] |
|||
game_pokemon = {} |
|||
|
|||
for generation in group: |
|||
games_in_group.extend(db.get_games_by_generation(generation)) |
|||
pokemon_in_generation = db.get_pokemon_by_generation(generation) |
|||
for pokemon in pokemon_in_generation: |
|||
if pokemon["storable_in_home"] == False: |
|||
continue |
|||
|
|||
pfic = pokemon["PFIC"] |
|||
|
|||
testing = [ |
|||
"0140-01-000-1", "0138-01-000-1", "0140-01-000-2", "0138-01-000-2", |
|||
"0141-01-000-1", "0139-01-000-1", "0141-01-000-2", "0139-01-000-2", |
|||
] |
|||
|
|||
#if pfic not in testing: |
|||
# continue |
|||
|
|||
if pokemon["gender_relevant"] or pokemon["PFIC"][-1] == '0' or not any(pokemon["PFIC"][:-1] == s[:-1] for s in needed_pokemon): |
|||
needed_pokemon.add(pfic) |
|||
|
|||
random = db.get_all_encounters("random") |
|||
static = db.get_all_encounters("static") |
|||
starter = db.get_all_encounters("starter") |
|||
encounters = [] |
|||
encounters.extend(random) |
|||
encounters.extend(static) |
|||
encounters.extend(starter) |
|||
|
|||
for game in games_in_group: |
|||
game_pokemon[game['id']] = set() |
|||
for encounter in encounters: |
|||
if game["id"] == encounter["game_id"]: |
|||
current_pfic = encounter['PFIC'] |
|||
game_pokemon[game['id']].add(current_pfic) |
|||
evolution_chains = db.get_full_evolution_paths(current_pfic) |
|||
if evolution_chains and (len(evolution_chains["predecessors"]) > 0 or len(evolution_chains["successors"]) > 0): |
|||
for chains in evolution_chains["predecessors"]: |
|||
for evolved_pfic, method in chains: |
|||
if evolved_pfic in needed_pokemon: |
|||
game_pokemon[game['id']].add(evolved_pfic) |
|||
|
|||
for chains in evolution_chains["successors"]: |
|||
for evolved_pfic, method in chains: |
|||
if evolved_pfic in needed_pokemon: |
|||
game_pokemon[game['id']].add(evolved_pfic) |
|||
|
|||
selected_games = [] |
|||
catch_in_game = {} |
|||
remaining_pokemon = needed_pokemon.copy() |
|||
available_games = games_in_group.copy() |
|||
while remaining_pokemon: |
|||
cache = {} |
|||
for game in available_games: |
|||
cache[game['id']] = self.get_covered_pokemon(game, remaining_pokemon, game_pokemon[game['id']]) |
|||
|
|||
best_game = max(available_games, key=lambda g: len(cache[g["id"]])) |
|||
pokemon_covered = cache[best_game['id']] |
|||
|
|||
if not pokemon_covered: |
|||
print("No more Pokémon can be covered. Breaking loop.") |
|||
break |
|||
|
|||
selected_games.append(best_game) |
|||
catch_in_game[best_game["id"]] = pokemon_covered |
|||
remaining_pokemon -= pokemon_covered |
|||
|
|||
available_games.remove(best_game) |
|||
|
|||
for game in selected_games[:-1]: |
|||
|
|||
if game['id'] in cache and all(pokemon in cache[best_game['id']] |
|||
for pokemon in cache[game['id']] ): |
|||
selected_games.remove(game) |
|||
print(f"Removed {game['name']} as it's covered by {best_game['name']}") |
|||
|
|||
for game in selected_games: |
|||
output_file = "./temp/"+game["name"]+".json" |
|||
with open(output_file, 'w', encoding='utf-8') as f: |
|||
temp = [] |
|||
for pfic in catch_in_game[game["id"]]: |
|||
deets = db.get_pokemon_details(pfic, ["pfic", "name", "form_name"]) |
|||
temp.append(deets) |
|||
temp.sort(key=lambda x: parse_pfic(x["pfic"])) |
|||
json.dump(temp, f, indent=4, ensure_ascii=False) |
|||
pass |
|||
|
|||
return catch_in_game |
|||
|
|||
def get_covered_pokemon(self, game, needed_pokemon, available_pokemon): |
|||
exclusive_groups = self.get_exclusive_groups(game['id']) |
|||
pokemon_covered = set() |
|||
|
|||
evolution_paths = {} |
|||
evolution_predecessors = {} |
|||
all_pokemon = needed_pokemon | available_pokemon |
|||
|
|||
for group in exclusive_groups: |
|||
for pfic in group: |
|||
all_pokemon.add(pfic) |
|||
|
|||
for pfic in all_pokemon: |
|||
chain = db.get_full_evolution_paths(pfic) |
|||
evolution_paths[pfic] = chain |
|||
|
|||
predecessors = set([pfic]) |
|||
if chain and chain.get("predecessors"): |
|||
for entry in chain["predecessors"]: |
|||
for evolved_pfic, _ in entry: |
|||
predecessors.add(evolved_pfic) |
|||
evolution_predecessors[pfic] = predecessors |
|||
|
|||
exclusive_group_predecessors = [] |
|||
for group in exclusive_groups: |
|||
group_pokemon = set() |
|||
for pfic in group: |
|||
group_pokemon.update(evolution_predecessors.get(pfic, set())) |
|||
exclusive_group_predecessors.append(group_pokemon) |
|||
|
|||
def record_pokemon(pfic, container, needed): |
|||
container.add(pfic) |
|||
evolution_chains = evolution_paths.get(pfic) |
|||
if evolution_chains and (evolution_chains.get("predecessors") or evolution_chains.get("successors")): |
|||
for chains in evolution_chains.get("predecessors", []): |
|||
for evolved_pfic, _ in chains: |
|||
if evolved_pfic in needed: |
|||
container.add(evolved_pfic) |
|||
for chains in evolution_chains.get("successors", []): |
|||
for evolved_pfic, _ in chains: |
|||
if evolved_pfic in needed: |
|||
container.add(evolved_pfic) |
|||
|
|||
for pfic in needed_pokemon & available_pokemon: |
|||
if pfic in pokemon_covered: |
|||
continue |
|||
previous_evolutions = evolution_predecessors.get(pfic, set()) |
|||
is_exclusive = False |
|||
for group_pokemon in exclusive_group_predecessors: |
|||
if previous_evolutions & group_pokemon: |
|||
is_exclusive = True |
|||
if not pokemon_covered & group_pokemon: |
|||
record_pokemon(pfic, pokemon_covered, needed_pokemon) |
|||
break |
|||
if not is_exclusive: |
|||
record_pokemon(pfic, pokemon_covered, needed_pokemon) |
|||
|
|||
return pokemon_covered |
|||
|
|||
def get_exclusive_groups(self, game_id): |
|||
for data in exclusive_choice_pokemon: |
|||
if data["game_id"] == game_id: |
|||
return data["choices"] |
|||
return [] |
|||
|
|||
def plan_for_game(self, game_id, required_pokemon): |
|||
game = db.get_game_by_id(game_id) |
|||
game_plan = { |
|||
"game_name": game['name'], |
|||
"pokemon_to_catch": {}, |
|||
"pokemon_to_breed": {}, |
|||
"pokemon_map": {} |
|||
} |
|||
|
|||
print(f'Processing {game['name']}') |
|||
|
|||
random = db.get_all_encounters("random") |
|||
static = db.get_all_encounters("static") |
|||
starter = db.get_all_encounters("starter") |
|||
encounters = [] |
|||
encounters.extend(random) |
|||
encounters.extend(static) |
|||
encounters.extend(starter) |
|||
|
|||
encounters_in_game = {} |
|||
|
|||
for encounter in encounters: |
|||
if game["id"] == encounter["game_id"]: |
|||
encounters_in_game[encounter["PFIC"]] = encounter |
|||
|
|||
pokemon_to_catch = {} |
|||
pokemon_to_breed = {} |
|||
pokemon_map = {} |
|||
|
|||
def record_catch(pfic, gender, to_get): |
|||
if pfic not in encounters_in_game: |
|||
pass |
|||
|
|||
if pfic not in pokemon_to_catch: |
|||
pokemon_to_catch[pfic] = {} |
|||
|
|||
data = pokemon_to_catch[pfic] |
|||
if gender not in data: |
|||
data[gender] = 1 |
|||
else: |
|||
data[gender] += 1 |
|||
|
|||
if to_get not in pokemon_map: |
|||
pokemon_map[to_get] = {} |
|||
|
|||
pokemon_map[to_get]["ByEvolving"] = pfic |
|||
|
|||
def record_breed(pfic, gender, to_get): |
|||
if pfic not in pokemon_to_breed: |
|||
pokemon_to_breed[pfic] = {} |
|||
|
|||
data = pokemon_to_breed[pfic] |
|||
if gender not in data: |
|||
data[gender] = 1 |
|||
else: |
|||
data[gender] += 1 |
|||
|
|||
if to_get not in pokemon_map: |
|||
pokemon_map[to_get] = {} |
|||
|
|||
pokemon_map[to_get]["ByBreeding"] = pfic |
|||
|
|||
# TODO: Move this to a last pass |
|||
#if pfic not in pokemon_to_catch: |
|||
# record_catch(pfic, gender) |
|||
|
|||
def get_gender_string(value): |
|||
value_map = {"0": "Any", "1": "Male", "2": "Female"} |
|||
return value_map.get(str(value), "Unknown") |
|||
|
|||
missing_count = 0 |
|||
|
|||
for pfic in required_pokemon: |
|||
pokemon_data = db.get_pokemon_details(pfic) |
|||
evolution_chain = db.get_full_evolution_paths(pfic) |
|||
if evolution_chain and not any(evolution_chain["predecessors"]): |
|||
if pokemon_data["is_baby_form"]: |
|||
recorded = False |
|||
evolutions = db.get_evolution_graph(pfic) |
|||
for evolution in evolutions: |
|||
if evolution in encounters_in_game: |
|||
bucket = get_gender_string(0) |
|||
record_breed(evolution, bucket, pfic) |
|||
recorded = True |
|||
if not recorded: |
|||
if pfic in encounters_in_game: |
|||
bucket = get_gender_string(pfic[-1]) |
|||
record_catch(pfic, bucket, pfic) |
|||
else: |
|||
if pokemon_data["gender_relevant"]: |
|||
bucket = get_gender_string(pfic[-1]) |
|||
record_catch(pfic, bucket, pfic) |
|||
else: |
|||
shiftable_forms = get_shiftable_forms(pfic) |
|||
if len(shiftable_forms) > 0: |
|||
shiftable_pfic = shiftable_forms[0]["to_pfic"] |
|||
record_catch(shiftable_pfic, "Any", pfic) |
|||
else: |
|||
record_catch(pfic, "Any", pfic) |
|||
elif evolution_chain: |
|||
bucket = get_gender_string(0) |
|||
if pokemon_data["gender_relevant"]: |
|||
bucket = get_gender_string(pfic[-1]) |
|||
first_form = db.find_most_distant_predecessors(pfic) |
|||
if first_form: |
|||
first_form_pfic = first_form[0][0] |
|||
first_form_data = db.get_pokemon_details(first_form_pfic) |
|||
if first_form_data["is_baby_form"] == False: |
|||
shiftable_forms = get_shiftable_forms(first_form_pfic) |
|||
if len(shiftable_forms) > 0: |
|||
shiftable_pfic = shiftable_forms[0]["to_pfic"] |
|||
record_catch(shiftable_pfic, bucket, pfic) |
|||
else: |
|||
record_catch(first_form_pfic, bucket, pfic) |
|||
else: |
|||
recorded = False |
|||
evolutions = db.get_evolution_graph(first_form_pfic) |
|||
for evolution in evolutions: |
|||
if evolution in encounters_in_game: |
|||
record_catch(evolution, bucket, pfic) |
|||
recorded = True |
|||
if not recorded: |
|||
if first_form_pfic in encounters_in_game: |
|||
bucket = get_gender_string(pfic[-1]) |
|||
record_catch(first_form_pfic, bucket, pfic) |
|||
|
|||
total_catch = 0 |
|||
for sub_dict in pokemon_to_catch.values(): |
|||
total_catch += sum(sub_dict.values()) |
|||
|
|||
total_breed = 0 |
|||
for sub_dict in pokemon_to_breed.values(): |
|||
total_breed += sum(sub_dict.values()) |
|||
|
|||
all = total_catch + total_breed + missing_count |
|||
|
|||
sorted_keys = sorted(pokemon_to_catch.keys()) |
|||
|
|||
# Create a new dictionary with sorted keys |
|||
sorted_dict = {key: pokemon_to_catch[key] for key in sorted_keys} |
|||
game_plan["pokemon_to_catch"] = pokemon_to_catch |
|||
game_plan["pokemon_to_breed"] = pokemon_to_breed |
|||
game_plan["pokemon_map"] = pokemon_map |
|||
|
|||
for required in required_pokemon: |
|||
if required not in pokemon_map: |
|||
pokemon_data = db.get_pokemon_details(required) |
|||
print(pokemon_data["name"]) |
|||
|
|||
return game_plan |
|||
Loading…
Reference in new issue