You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

367 lines
14 KiB

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