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, get_shiftable_forms_bidirectional, parse_pfic, sanitize_filename class GeneratePlanWorkerSignals(QObject): finished = pyqtSignal(list) 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 self.game_plan 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: pfic = pokemon["PFIC"] if pokemon["storable_in_home"] == False: continue 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) """ def thingy(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 shiftable_form in get_shiftable_forms_bidirectional(evolved_pfic): game_pokemon[game['id']].add(shiftable_form["to_pfic"]) game_pokemon[game['id']].add(shiftable_form["from_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) for shiftable_form in get_shiftable_forms_bidirectional(evolved_pfic): game_pokemon[game['id']].add(shiftable_form["to_pfic"]) game_pokemon[game['id']].add(shiftable_form["from_pfic"]) for game in games_in_group: game_pokemon[game['id']] = set() for encounter in encounters: current_pfic = encounter['PFIC'] if game["id"] == encounter["game_id"]: game_pokemon[game['id']].add(current_pfic) for shiftable_form in get_shiftable_forms_bidirectional(current_pfic): game_pokemon[game['id']].add(shiftable_form["to_pfic"]) game_pokemon[game['id']].add(shiftable_form["from_pfic"]) thingy(shiftable_form["from_pfic"]) thingy(pfic) """ 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']]) pokemon_covered = {} if cache: 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: file_name = sanitize_filename(game["name"]) output_file = "./temp/"+file_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() search_value = "0412-04-002-2" if search_value in needed_pokemon: pass if search_value in available_pokemon: pass 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 = {} other_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 if pfic not in other_map: other_map[pfic] = {} other_map[pfic]["EvolveTo"] = [] other_map[pfic]["BreedFor"] = [] other_map[pfic]["EvolveTo"].append(to_get) 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 if pfic not in other_map: other_map[pfic] = {} other_map[pfic]["EvolveTo"] = [] other_map[pfic]["BreedFor"] = [] other_map[pfic]["BreedFor"].append(to_get) # 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 game_plan["other_map"] = other_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