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.
269 lines
14 KiB
269 lines
14 KiB
import sqlite3
|
|
from collections import defaultdict
|
|
|
|
class OriginDexPlanner:
|
|
def __init__(self, db_path):
|
|
self.conn = sqlite3.connect(db_path)
|
|
self.conn.row_factory = sqlite3.Row
|
|
|
|
def get_game_data(self):
|
|
"""Fetch game and pokemon information from the database."""
|
|
cursor = self.conn.cursor()
|
|
cursor.execute("SELECT * FROM games")
|
|
games = cursor.fetchall()
|
|
|
|
cursor.execute("SELECT * FROM pokemon_forms WHERE name IN ('Elekid', 'Electabuzz', 'Electivire')")
|
|
pokemon_forms = cursor.fetchall()
|
|
|
|
cursor.execute("SELECT * FROM encounters")
|
|
encounters = cursor.fetchall()
|
|
|
|
exclusive_encounters = []
|
|
cursor.execute("SELECT * FROM evolution_chains WHERE from_pfic IN (SELECT PFIC FROM pokemon_forms WHERE name IN ('Elekid', 'Electabuzz', 'Electivire'))")
|
|
evolutions = cursor.fetchall()
|
|
|
|
return games, pokemon_forms, encounters, exclusive_encounters, evolutions
|
|
|
|
def build_pokemon_data(self):
|
|
"""Construct data dictionaries to store relationships between the Pokemon and encounters."""
|
|
games, pokemon_forms, encounters, exclusive_encounters, evolutions = self.get_game_data()
|
|
|
|
pokemon_by_gen = defaultdict(list)
|
|
game_by_gen = defaultdict(list)
|
|
encounter_data = defaultdict(list)
|
|
|
|
for game in games:
|
|
game_by_gen[game['generation']].append(game)
|
|
|
|
for pokemon in pokemon_forms:
|
|
pokemon_by_gen[pokemon['generation']].append(pokemon)
|
|
|
|
# Build a dict of encounters, mapping game_id to Pokemon encountered in it
|
|
for encounter in encounters:
|
|
encounter_data[encounter['game_id']].append(encounter)
|
|
|
|
evolution_map = defaultdict(list)
|
|
for evolution in evolutions:
|
|
from_pfic = evolution['from_pfic']
|
|
to_pfic = evolution['to_pfic']
|
|
# Lookup generation from pokemon_forms table
|
|
cursor = self.conn.cursor()
|
|
cursor.execute("SELECT generation FROM pokemon_forms WHERE PFIC = ?", (to_pfic,))
|
|
to_generation = cursor.fetchone()['generation']
|
|
evolution_map[from_pfic].append((to_pfic, to_generation))
|
|
|
|
exclusive_group_map = defaultdict(list)
|
|
for exclusive_encounter in exclusive_encounters:
|
|
exclusive_group_map[exclusive_encounter['group_id']].append(exclusive_encounter['encounter_id'])
|
|
|
|
return pokemon_by_gen, game_by_gen, encounter_data, evolution_map, exclusive_group_map
|
|
|
|
def generate_plan(self, generations_to_group_list=None):
|
|
"""Generate a game plan to catch all Pokemon in their origin generation."""
|
|
if generations_to_group_list is None:
|
|
generations_to_group_list = []
|
|
|
|
pokemon_by_gen, game_by_gen, encounter_data, evolution_map, exclusive_group_map = self.build_pokemon_data()
|
|
|
|
plan = []
|
|
pokemon_to_catch = defaultdict(list)
|
|
caught_pokemon = set()
|
|
pokemon_names = {}
|
|
|
|
# Handle multiple sets of grouped generations
|
|
grouped_generations_sets = [set(generations) for generations in generations_to_group_list]
|
|
for grouped_generations in grouped_generations_sets:
|
|
grouped_games = []
|
|
grouped_pokemon_list = []
|
|
for gen in grouped_generations:
|
|
if gen in game_by_gen:
|
|
grouped_games.extend(game_by_gen[gen])
|
|
grouped_pokemon_list.extend(pokemon_by_gen[gen])
|
|
|
|
if grouped_games:
|
|
plan.extend(self.generate_plan_for_generation(grouped_games, grouped_pokemon_list, encounter_data, evolution_map, exclusive_group_map, pokemon_names, caught_pokemon, game_by_gen))
|
|
|
|
# Loop through each generation, generating a plan for each game
|
|
for gen in sorted(game_by_gen.keys()):
|
|
# Skip generations that have been grouped
|
|
if any(gen in grouped_generations for grouped_generations in grouped_generations_sets):
|
|
continue
|
|
games = game_by_gen[gen]
|
|
pokemon_list = pokemon_by_gen[gen]
|
|
|
|
plan.extend(self.generate_plan_for_generation(games, pokemon_list, encounter_data, evolution_map, exclusive_group_map, pokemon_names, caught_pokemon, game_by_gen))
|
|
|
|
return plan
|
|
|
|
def generate_plan_for_generation(self, games, pokemon_list, encounter_data, evolution_map, exclusive_group_map, pokemon_names, caught_pokemon, game_by_gen):
|
|
"""Generate a game plan for a specific generation or group of generations."""
|
|
plan = []
|
|
pokemon_to_catch = defaultdict(list)
|
|
pokemon_to_breed = defaultdict(list)
|
|
catchable_pokemon = set()
|
|
|
|
# Create a set of baby Pokémon PFICs
|
|
baby_pokemon = set(pokemon['PFIC'] for pokemon in pokemon_list if pokemon['is_baby_form'])
|
|
|
|
# Identify unique evolution chains and the starting point
|
|
for pokemon in pokemon_list:
|
|
pfic = pokemon['PFIC']
|
|
pokemon_names[pfic] = f'{pokemon["name"]} ({pokemon["form_name"] if pokemon["form_name"] is not None else ""})'
|
|
if pfic not in evolution_map: # Not evolved from anything
|
|
catchable_pokemon.add(pfic)
|
|
else:
|
|
catchable_pokemon.add(pfic)
|
|
# Add all evolution stages to catchable list if they belong to the current or previous generations
|
|
current = pfic
|
|
current_generation = pokemon['generation']
|
|
while current in evolution_map:
|
|
next_pfic, next_generation = evolution_map[current][0]
|
|
if any(p['PFIC'] == next_pfic for p in pokemon_list):
|
|
if next_generation <= current_generation:
|
|
catchable_pokemon.add(next_pfic)
|
|
current = next_pfic
|
|
|
|
# Determine the best game to catch the most Pokemon
|
|
best_game = None
|
|
max_catchable = 0
|
|
game_catchable_pokemon = defaultdict(set)
|
|
for game in games:
|
|
game_id = game['id']
|
|
encounters = encounter_data[game_id]
|
|
|
|
# Track how many unique Pokemon are available in this game
|
|
for encounter in encounters:
|
|
pfic = encounter['pfic']
|
|
if pfic in catchable_pokemon:
|
|
game_catchable_pokemon[game_id].add(pfic)
|
|
|
|
# Update the best game if this game has more catchable Pokemon
|
|
if len(game_catchable_pokemon[game_id]) > max_catchable:
|
|
max_catchable = len(game_catchable_pokemon[game_id])
|
|
best_game = game
|
|
|
|
# Use the best game to catch as many unique Pokemon as possible
|
|
remaining_games = [game for game in games if game != best_game]
|
|
if best_game:
|
|
game_id = best_game['id']
|
|
game_name = best_game['name']
|
|
encounters = encounter_data[game_id]
|
|
|
|
for encounter in encounters:
|
|
pfic = encounter['pfic']
|
|
if pfic in catchable_pokemon and pfic not in caught_pokemon:
|
|
evolution_chain = self.get_full_evolution_chain(pfic, evolution_map)
|
|
base_pokemon = evolution_chain[0]
|
|
if base_pokemon not in caught_pokemon:
|
|
# Calculate the number of Pokemon needed for the full evolution chain
|
|
count = len(evolution_chain)
|
|
if encounter['static_encounter']:
|
|
count = min(count, encounter['static_encounter_count'] or 1)
|
|
|
|
if base_pokemon in baby_pokemon:
|
|
# For baby Pokémon, catch the first non-baby evolution and breed for the baby
|
|
non_baby_pokemon = next((p for p in evolution_chain if p not in baby_pokemon), None)
|
|
if non_baby_pokemon:
|
|
pokemon_to_catch[game_name].append({'pfic': non_baby_pokemon, 'count': 1})
|
|
pokemon_to_breed[game_name].append({'pfic': base_pokemon, 'count': 1})
|
|
else:
|
|
pokemon_to_catch[game_name].append({'pfic': base_pokemon, 'count': count})
|
|
|
|
caught_pokemon.update(evolution_chain)
|
|
|
|
# Account for exclusive encounters
|
|
exclusive_group_ids = [group['group_id'] for group in exclusive_group_map if group['encounter_id'] == encounter['id']]
|
|
if exclusive_group_ids:
|
|
other_options = exclusive_group_map[exclusive_group_ids[0]]
|
|
if len(other_options) > 1:
|
|
# Pick one of the options, mark the rest to catch in another game
|
|
catchable_pokemon.remove(pfic)
|
|
else:
|
|
continue
|
|
|
|
# Use remaining games to catch any remaining Pokemon
|
|
for game in remaining_games:
|
|
game_id = game['id']
|
|
game_name = game['name']
|
|
encounters = encounter_data[game_id]
|
|
|
|
for encounter in encounters:
|
|
pfic = encounter['pfic']
|
|
if pfic in catchable_pokemon and pfic not in caught_pokemon:
|
|
evolution_chain = self.get_full_evolution_chain(pfic, evolution_map)
|
|
base_pokemon = evolution_chain[0]
|
|
if base_pokemon not in caught_pokemon:
|
|
# Calculate the number of Pokemon needed for the full evolution chain
|
|
count = len(evolution_chain)
|
|
if encounter['static_encounter']:
|
|
count = min(count, encounter['static_encounter_count'] or 1)
|
|
|
|
if base_pokemon in baby_pokemon:
|
|
# For baby Pokémon, catch the first non-baby evolution and breed for the baby
|
|
non_baby_pokemon = next((p for p in evolution_chain if p not in baby_pokemon), None)
|
|
if non_baby_pokemon:
|
|
pokemon_to_catch[game_name].append({'pfic': non_baby_pokemon, 'count': 1})
|
|
pokemon_to_breed[game_name].append({'pfic': base_pokemon, 'count': 1})
|
|
else:
|
|
pokemon_to_catch[game_name].append({'pfic': base_pokemon, 'count': count})
|
|
|
|
caught_pokemon.update(evolution_chain)
|
|
|
|
# Handle new evolutions or forms added in later generations
|
|
for pfic in list(caught_pokemon):
|
|
if pfic in evolution_map:
|
|
for new_evolution, new_generation in evolution_map[pfic]:
|
|
# Check if the new evolution is from a later generation
|
|
full_evolution_chain = self.get_full_evolution_chain(pfic, evolution_map)
|
|
current_generation = min((pokemon['generation'] for pokemon in pokemon_list if pokemon['PFIC'] in full_evolution_chain), default=None)
|
|
if new_generation and current_generation and new_generation > current_generation:
|
|
# Add the baby/base form to be caught in the new generation if required
|
|
base_pokemon = full_evolution_chain[0]
|
|
new_gen_games = game_by_gen[new_generation]
|
|
for game in new_gen_games:
|
|
game_id = game['id']
|
|
game_name = game['name']
|
|
encounters = encounter_data[game_id]
|
|
for encounter in encounters:
|
|
if encounter['pfic'] == base_pokemon and base_pokemon not in caught_pokemon:
|
|
if base_pokemon in baby_pokemon:
|
|
non_baby_pokemon = next((p for p in full_evolution_chain if p not in baby_pokemon), None)
|
|
if non_baby_pokemon:
|
|
pokemon_to_catch[game_name].append({'pfic': non_baby_pokemon, 'count': 1})
|
|
pokemon_to_breed[game_name].append({'pfic': base_pokemon, 'count': 1})
|
|
else:
|
|
pokemon_to_catch[game_name].append({'pfic': base_pokemon, 'count': 1})
|
|
caught_pokemon.add(base_pokemon)
|
|
break
|
|
|
|
# Generate the plan for this generation or group of generations
|
|
for game_name in set(list(pokemon_to_catch.keys()) + list(pokemon_to_breed.keys())):
|
|
plan.append(f"Play {game_name}:")
|
|
if game_name in pokemon_to_catch:
|
|
plan.append(f" Catch {len(pokemon_to_catch[game_name])} unique Pokemon:")
|
|
for pokemon in pokemon_to_catch[game_name]:
|
|
plan.append(f" - {pokemon_names[pokemon['pfic']]}: {pokemon['count']} times")
|
|
|
|
if game_name in pokemon_to_breed:
|
|
plan.append(f" Breed {len(pokemon_to_breed[game_name])} Pokemon:")
|
|
for pokemon in pokemon_to_breed[game_name]:
|
|
plan.append(f" - {pokemon_names[pokemon['pfic']]}: {pokemon['count']} times")
|
|
|
|
return plan
|
|
|
|
def get_full_evolution_chain(self, pfic, evolution_map):
|
|
"""Get the full evolution chain for a given PFIC."""
|
|
chain = [pfic]
|
|
while pfic in evolution_map:
|
|
pfic = evolution_map[pfic][0][0]
|
|
chain.append(pfic)
|
|
return chain
|
|
|
|
def display_plan(self, generations_to_group_list=None):
|
|
plan = self.generate_plan(generations_to_group_list)
|
|
for step in plan:
|
|
print(step)
|
|
|
|
# Example usage
|
|
planner = OriginDexPlanner('pokemon_forms.db')
|
|
planner.display_plan(generations_to_group_list=[[1, 2], [3, 4, 5, 6]])
|