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.
386 lines
15 KiB
386 lines
15 KiB
import csv
|
|
import requests
|
|
import time
|
|
import json
|
|
import os
|
|
import re
|
|
import sqlite3
|
|
|
|
# Initialize the database connection
|
|
conn = sqlite3.connect('pokemon_cache.db')
|
|
cursor = conn.cursor()
|
|
|
|
# Create the cache table if it doesn't exist
|
|
cursor.execute('''
|
|
CREATE TABLE IF NOT EXISTS cache (
|
|
key TEXT PRIMARY KEY,
|
|
value TEXT
|
|
)
|
|
''')
|
|
conn.commit()
|
|
|
|
# List of all main series Pokémon games in chronological order, with special games first in each generation
|
|
all_games = [
|
|
"Yellow", "Red", "Blue",
|
|
"Crystal", "Gold", "Silver",
|
|
"Emerald", "FireRed", "LeafGreen", "Ruby", "Sapphire",
|
|
"Platinum", "HeartGold", "SoulSilver", "Diamond", "Pearl",
|
|
"Black-2", "White-2", "Black", "White",
|
|
"X", "Y", "Omega-Ruby", "Alpha-Sapphire",
|
|
"Ultra-Sun", "Ultra-Moon", "Sun", "Moon",
|
|
"Sword", "Shield",
|
|
"Brilliant-Diamond", "Shining-Pearl",
|
|
"Legends-Arceus",
|
|
"Scarlet", "Violet",
|
|
"Unknown"
|
|
]
|
|
|
|
cache = {}
|
|
new_entries_count = 0
|
|
|
|
def get_cached_data():
|
|
global cache
|
|
cursor.execute("SELECT key, value FROM cache")
|
|
for key, value in cursor.fetchall():
|
|
cache[key] = json.loads(value)
|
|
|
|
def save_cached_data():
|
|
global cache, new_entries_count
|
|
if new_entries_count > 0:
|
|
for key, value in cache.items():
|
|
cursor.execute("INSERT OR REPLACE INTO cache (key, value) VALUES (?, ?)",
|
|
(key, json.dumps(value)))
|
|
conn.commit()
|
|
new_entries_count = 0
|
|
|
|
def update_cache(key, value):
|
|
global cache, new_entries_count
|
|
if key not in cache:
|
|
cache[key] = value
|
|
new_entries_count += 1
|
|
if new_entries_count >= 10:
|
|
save_cached_data()
|
|
time.sleep(1)
|
|
|
|
def read_pokemon_list(filename, limit=50):
|
|
pokemon_list = []
|
|
with open(filename, 'r', newline='', encoding='utf-8') as csvfile:
|
|
reader = csv.DictReader(csvfile)
|
|
for i, row in enumerate(reader):
|
|
if i >= limit:
|
|
break
|
|
# Split the name into base name and form
|
|
match = re.match(r'(.*?)\s*(\(.*\))?$', row['name'])
|
|
base_name, form = match.groups() if match else (row['name'], None)
|
|
row['base_name'] = base_name.strip()
|
|
row['form'] = form.strip('() ') if form else None
|
|
pokemon_list.append(row)
|
|
return pokemon_list
|
|
|
|
def sanitize_name_and_form(name, form):
|
|
adjusted_form = None
|
|
if form:
|
|
adjusted_form = form.lower()
|
|
#Some stupid special cases
|
|
if name.lower() == 'tauros':
|
|
if adjusted_form == 'paldean form':
|
|
adjusted_form = 'paldea combat breed'
|
|
elif 'blaze' in adjusted_form:
|
|
adjusted_form = 'paldea blaze breed'
|
|
elif 'aqua' in adjusted_form:
|
|
adjusted_form = 'paldea aqua breed'
|
|
|
|
replacements = {'forme': '',
|
|
'form': '',
|
|
'alolan': 'alola',
|
|
'galarian': 'galar',
|
|
'hisuian': 'hisui',
|
|
'paldean': 'paldea',
|
|
'size': '',
|
|
'10%': '10 power construct',
|
|
'hoopa': '',
|
|
'style': '',
|
|
'core': '',
|
|
'color': '',
|
|
'blood moon': 'bloodmoon'};
|
|
for old, new in replacements.items():
|
|
adjusted_form = adjusted_form.replace(old, new).strip()
|
|
|
|
missing_forms = ['burmy',
|
|
'shellos',
|
|
'gastrodon',
|
|
'wormadam',
|
|
'unown',
|
|
"deerling",
|
|
"sawsbuck",
|
|
"vivillon",
|
|
"flabébé",
|
|
"floette",
|
|
"florges",
|
|
"furfrou",
|
|
"sinistea",
|
|
"polteageist",
|
|
"alcremie",
|
|
"poltchageist",
|
|
"sinistcha"]
|
|
|
|
if name.lower() in missing_forms:
|
|
adjusted_form = None
|
|
|
|
if name.lower() == 'wormadam':
|
|
adjusted_form = adjusted_form.replace('cloak', '').strip()
|
|
if name.lower() == 'rotom':
|
|
adjusted_form = adjusted_form.replace('rotom', '').strip()
|
|
if name.lower() == 'darmanitan':
|
|
adjusted_form = adjusted_form + ' standard'
|
|
|
|
else:
|
|
default_forms = {'deoxys': 'normal',
|
|
'wormadam': 'plant',
|
|
'giratina': 'origin',
|
|
'tornadus': 'incarnate',
|
|
'shaymin': 'land',
|
|
'basculin': 'red-striped',
|
|
'darmanitan': 'standard',
|
|
'thundurus': 'incarnate',
|
|
'landorus': 'incarnate',
|
|
'enamorus': 'incarnate',
|
|
'keldeo': 'ordinary',
|
|
'meloetta': 'aria',
|
|
'meowstic': 'male',
|
|
'aegislash': 'shield',
|
|
'pumpkaboo': 'average',
|
|
'gourgeist': 'average',
|
|
'minior': 'red-meteor',
|
|
'zygarde': '50 power construct',
|
|
'oricorio': 'baile',
|
|
'lycanroc': 'midday',
|
|
'wishiwashi': 'solo',
|
|
'mimikyu': 'disguised',
|
|
'cramorant': 'gulping',
|
|
'toxtricity': 'low-key',
|
|
'eiscue': 'ice',
|
|
'indeedee': 'male',
|
|
'urshifu': 'single-strike',
|
|
'morpeko': 'full belly',
|
|
'oinkologne': 'male',
|
|
'maushold': 'family of three',
|
|
'squawkabilly': 'green plumage',
|
|
'palafin': 'zero',
|
|
'tatsugiri': 'curly',
|
|
'dudunsparce': 'two segment',
|
|
'basculegion': 'male'}
|
|
|
|
if name.lower() in default_forms:
|
|
adjusted_form = default_forms[name.lower()]
|
|
|
|
if adjusted_form:
|
|
api_name = f"{name.lower()}-{adjusted_form}"
|
|
else:
|
|
api_name = name.lower()
|
|
|
|
api_name = api_name.replace(' ', '-').replace("'", "").replace(".", "").replace('é', 'e').replace(':', '')
|
|
|
|
#more special cases
|
|
if api_name == 'oinkologne-male':
|
|
api_name = '916'
|
|
|
|
return api_name
|
|
|
|
def get_pokemon_data(pokemon_name, form, cache):
|
|
cache_key = f"pokemon_{pokemon_name}_{form}" if form else f"pokemon_{pokemon_name}"
|
|
if cache_key in cache:
|
|
return cache[cache_key]
|
|
|
|
api_name = sanitize_name_and_form(pokemon_name, form)
|
|
|
|
url = f"https://pokeapi.co/api/v2/pokemon/{api_name}"
|
|
print(f"Fetching Pokémon data for {pokemon_name}: {url}")
|
|
response = requests.get(url)
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
update_cache(cache_key, data)
|
|
return data
|
|
return None
|
|
|
|
def get_pokemon_encounter_data(pokemon_name, form, cache):
|
|
cache_key = f"pokemon_encounter_{pokemon_name}_{form}" if form else f"pokemon_encounter_{pokemon_name}"
|
|
if cache_key in cache:
|
|
return cache[cache_key]
|
|
|
|
api_name = sanitize_name_and_form(pokemon_name, form)
|
|
|
|
url = f"https://pokeapi.co/api/v2/pokemon/{api_name}/encounters"
|
|
print(f"Fetching encounter data for {pokemon_name}: {url}")
|
|
response = requests.get(url)
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
update_cache(cache_key, data)
|
|
return data
|
|
else:
|
|
return None
|
|
|
|
def get_earliest_game(encounter_data):
|
|
if not encounter_data:
|
|
return "Unknown", "Unknown"
|
|
|
|
game_methods = {}
|
|
for location_area in encounter_data:
|
|
for version_detail in location_area['version_details']:
|
|
game = version_detail['version']['name']
|
|
is_gift = any(method['method']['name'] == 'gift' for method in version_detail['encounter_details'])
|
|
|
|
if game not in game_methods:
|
|
game_methods[game] = "Gift" if is_gift else "Catchable"
|
|
elif game_methods[game] == "Gift" and not is_gift:
|
|
game_methods[game] = "Catchable"
|
|
|
|
for game in all_games:
|
|
if game.lower() in game_methods:
|
|
return game, game_methods[game.lower()]
|
|
|
|
return "Unknown", "Unknown"
|
|
|
|
def determine_earliest_games(pokemon_list, cache):
|
|
for pokemon in pokemon_list:
|
|
pokemon_data = get_pokemon_data(pokemon['base_name'], pokemon['form'], cache)
|
|
encounter_data = get_pokemon_encounter_data(pokemon['base_name'], pokemon['form'], cache)
|
|
pokemon['earliest_game'], pokemon['obtain_method'] = get_earliest_game(encounter_data)
|
|
print(f"Processed {pokemon['name']} (#{pokemon['number']}): {pokemon['earliest_game']} ({pokemon['obtain_method']})")
|
|
return pokemon_list
|
|
|
|
def get_species_data(pokemon_name, cache):
|
|
cache_key = f"species_{pokemon_name}"
|
|
if cache_key in cache:
|
|
return cache[cache_key]
|
|
|
|
api_name = sanitize_name_and_form(pokemon_name, None)
|
|
|
|
url = f"https://pokeapi.co/api/v2/pokemon-species/{api_name}/"
|
|
print(f"Fetching species data for {pokemon_name}: {url}")
|
|
response = requests.get(url)
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
update_cache(cache_key, data)
|
|
return data
|
|
return None
|
|
|
|
def get_evolution_chain(pokemon_name, cache):
|
|
species_data = get_species_data(pokemon_name, cache)
|
|
if not species_data:
|
|
return None
|
|
|
|
cache_key = f"evolution_{species_data['evolution_chain']['url']}"
|
|
if cache_key in cache:
|
|
return cache[cache_key]
|
|
|
|
evolution_response = requests.get(species_data['evolution_chain']['url'])
|
|
if evolution_response.status_code == 200:
|
|
evolution_data = evolution_response.json()
|
|
update_cache(cache_key, evolution_data)
|
|
return evolution_data
|
|
return None
|
|
|
|
def get_base_form(evolution_chain, cache):
|
|
if not evolution_chain or 'chain' not in evolution_chain:
|
|
return None
|
|
|
|
current = evolution_chain['chain']
|
|
while current:
|
|
species_name = current['species']['name']
|
|
species_data = get_species_data(species_name, cache)
|
|
|
|
if species_data and not species_data.get('is_baby', False):
|
|
return species_name
|
|
|
|
if not current['evolves_to']:
|
|
return species_name
|
|
|
|
current = current['evolves_to'][0]
|
|
|
|
return None
|
|
|
|
def adjust_for_evolution(pokemon_list, cache):
|
|
pokemon_dict = {f"{pokemon['base_name']}_{pokemon['form']}".lower(): pokemon for pokemon in pokemon_list}
|
|
|
|
for pokemon in pokemon_list:
|
|
species_data = get_species_data(pokemon['base_name'], cache)
|
|
evolution_chain = get_evolution_chain(pokemon['base_name'], cache)
|
|
base_form = get_base_form(evolution_chain, cache)
|
|
|
|
# Check if the Pokémon is a baby
|
|
if species_data and species_data.get('is_baby', False):
|
|
pokemon['obtain_method'] = 'Breed'
|
|
elif base_form:
|
|
base_key = f"{base_form}_{pokemon['form']}".lower()
|
|
if base_key in pokemon_dict:
|
|
base_pokemon = pokemon_dict[base_key]
|
|
if all_games.index(base_pokemon['earliest_game']) <= all_games.index(pokemon['earliest_game']) and base_pokemon['number'] != pokemon['number']:
|
|
pokemon['earliest_game'] = base_pokemon['earliest_game']
|
|
pokemon['obtain_method'] = 'Evolve'
|
|
|
|
print(f"Adjusted {pokemon['name']} (#{pokemon['number']}): {pokemon['earliest_game']} ({pokemon['obtain_method']})")
|
|
|
|
return pokemon_list
|
|
|
|
def save_to_csv(pokemon_list, filename='pokemon_earliest_games.csv'):
|
|
with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
|
|
fieldnames = ['number', 'name', 'earliest_game', 'obtain_method', 'encounter_locations']
|
|
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
|
|
|
writer.writeheader()
|
|
for pokemon in pokemon_list:
|
|
writer.writerow({
|
|
'number': pokemon['number'],
|
|
'name': pokemon['name'],
|
|
'earliest_game': pokemon['earliest_game'],
|
|
'obtain_method': pokemon['obtain_method'],
|
|
'encounter_locations': pokemon['encounter_locations']
|
|
})
|
|
|
|
def parse_encounter_locations(encounter_data, game):
|
|
locations = []
|
|
for location_area in encounter_data:
|
|
for version_detail in location_area['version_details']:
|
|
if version_detail['version']['name'] == game.lower():
|
|
location_name = location_area['location_area']['name']
|
|
for encounter_detail in version_detail['encounter_details']:
|
|
method = encounter_detail['method']['name']
|
|
condition = encounter_detail.get('condition', 'Any')
|
|
time = ', '.join(encounter_detail.get('time', ['Any']))
|
|
|
|
encounter_info = f"{location_name} ({method}"
|
|
if condition != 'Any':
|
|
encounter_info += f", {condition}"
|
|
if time != 'Any':
|
|
encounter_info += f", {time}"
|
|
encounter_info += ")"
|
|
|
|
if encounter_info not in locations:
|
|
locations.append(encounter_info)
|
|
return locations
|
|
|
|
def add_encounter_locations(pokemon_list, cache):
|
|
for pokemon in pokemon_list:
|
|
if pokemon['obtain_method'] == 'Catchable':
|
|
encounter_data = get_pokemon_encounter_data(pokemon['base_name'], pokemon['form'], cache)
|
|
locations = parse_encounter_locations(encounter_data, pokemon['earliest_game'])
|
|
pokemon['encounter_locations'] = ' | '.join(locations) if locations else 'Unknown'
|
|
else:
|
|
pokemon['encounter_locations'] = 'N/A'
|
|
print(f"Added encounter locations for {pokemon['name']} (#{pokemon['number']}) in {pokemon['earliest_game']}")
|
|
return pokemon_list
|
|
|
|
# Update the main function
|
|
if __name__ == "__main__":
|
|
get_cached_data()
|
|
|
|
pokemon_list = read_pokemon_list('pokemon_home_list.csv', limit=3000)
|
|
pokemon_list_with_games = determine_earliest_games(pokemon_list, cache)
|
|
pokemon_list_adjusted = adjust_for_evolution(pokemon_list_with_games, cache)
|
|
pokemon_list_with_locations = add_encounter_locations(pokemon_list_adjusted, cache)
|
|
save_to_csv(pokemon_list_with_locations)
|
|
|
|
save_cached_data() # Save any remaining new entries
|
|
conn.close() # Close the database connection
|
|
print(f"Earliest obtainable games and encounter locations determined for {len(pokemon_list)} Pokémon and saved to pokemon_earliest_games.csv")
|
|
|