|
|
|
|
import sqlite3
|
|
|
|
|
from flask import Flask, render_template, jsonify
|
|
|
|
|
from collections import defaultdict
|
|
|
|
|
import os
|
|
|
|
|
import json
|
|
|
|
|
import re
|
|
|
|
|
import wordninja
|
|
|
|
|
from typing import List, Set
|
|
|
|
|
|
|
|
|
|
class CustomWordNinja:
|
|
|
|
|
def __init__(self, custom_words: List[str] = None):
|
|
|
|
|
self.custom_words = []
|
|
|
|
|
if custom_words:
|
|
|
|
|
# Store custom words with original capitalization, sorted by length
|
|
|
|
|
self.custom_words = sorted(custom_words, key=len, reverse=True)
|
|
|
|
|
|
|
|
|
|
def split(self, text: str) -> str:
|
|
|
|
|
working_text = text
|
|
|
|
|
|
|
|
|
|
# First handle exact custom words to preserve capitalization
|
|
|
|
|
for word in self.custom_words:
|
|
|
|
|
pattern = re.compile(word, re.IGNORECASE)
|
|
|
|
|
working_text = pattern.sub(f' {word} ', working_text)
|
|
|
|
|
|
|
|
|
|
# Clean up spaces
|
|
|
|
|
working_text = ' '.join(working_text.split())
|
|
|
|
|
|
|
|
|
|
# For remaining text, use wordninja
|
|
|
|
|
parts = []
|
|
|
|
|
for part in working_text.split():
|
|
|
|
|
if part in self.custom_words:
|
|
|
|
|
parts.append(part)
|
|
|
|
|
else:
|
|
|
|
|
split_parts = wordninja.split(part)
|
|
|
|
|
parts.extend(split_parts)
|
|
|
|
|
|
|
|
|
|
return ' '.join(parts)
|
|
|
|
|
|
|
|
|
|
POKEMON_PROPER_NOUNS = {
|
|
|
|
|
"Alola",
|
|
|
|
|
"Kanto",
|
|
|
|
|
"Johto",
|
|
|
|
|
"Hoenn",
|
|
|
|
|
"Sinnoh",
|
|
|
|
|
"Unova",
|
|
|
|
|
"Kalos",
|
|
|
|
|
"Galar",
|
|
|
|
|
"Hisui",
|
|
|
|
|
"Paldea",
|
|
|
|
|
"Augurite",
|
|
|
|
|
"Electirizer",
|
|
|
|
|
"Magmarizer"
|
|
|
|
|
# Add any other proper nouns that should be preserved
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
|
|
|
|
def load_pokemon_data():
|
|
|
|
|
pokemon_list = []
|
|
|
|
|
|
|
|
|
|
conn = sqlite3.connect('pokemon_forms.db')
|
|
|
|
|
cursor = conn.cursor()
|
|
|
|
|
|
|
|
|
|
# First query: Get all Pokémon data
|
|
|
|
|
cursor.execute('''
|
|
|
|
|
SELECT
|
|
|
|
|
pf.national_dex, pf.name, pf.form_name, pf.PFIC, pf.generation,
|
|
|
|
|
ps.storable_in_home
|
|
|
|
|
FROM pokemon_forms pf
|
|
|
|
|
JOIN pokemon_storage ps ON pf.PFIC = ps.PFIC
|
|
|
|
|
|
|
|
|
|
WHERE ps.storable_in_home = 1
|
|
|
|
|
ORDER BY pf.PFIC
|
|
|
|
|
''')
|
|
|
|
|
|
|
|
|
|
pokemon_data = cursor.fetchall()
|
|
|
|
|
|
|
|
|
|
# Process the data
|
|
|
|
|
current_group = []
|
|
|
|
|
current_generation = None
|
|
|
|
|
current_dex_number = None
|
|
|
|
|
pokemon_forms = []
|
|
|
|
|
|
|
|
|
|
for row in pokemon_data:
|
|
|
|
|
national_dex, name, form_name, pfic, generation, storable_in_home = row
|
|
|
|
|
|
|
|
|
|
mark_id = None
|
|
|
|
|
mark_icon = None
|
|
|
|
|
|
|
|
|
|
cursor.execute('''
|
|
|
|
|
SELECT mark_id
|
|
|
|
|
FROM form_marks
|
|
|
|
|
WHERE pfic = ?
|
|
|
|
|
''', (pfic,))
|
|
|
|
|
result = cursor.fetchone()
|
|
|
|
|
mark_id = result[0] if result else None
|
|
|
|
|
|
|
|
|
|
if mark_id:
|
|
|
|
|
cursor.execute('''
|
|
|
|
|
SELECT icon_path
|
|
|
|
|
FROM marks
|
|
|
|
|
WHERE id = ?
|
|
|
|
|
''', (mark_id,))
|
|
|
|
|
result = cursor.fetchone()
|
|
|
|
|
mark_icon = result[0] if result else None
|
|
|
|
|
|
|
|
|
|
pokemon = {
|
|
|
|
|
'pfic': pfic,
|
|
|
|
|
'ID': national_dex,
|
|
|
|
|
'Name': name,
|
|
|
|
|
'Form': form_name if form_name else "Default",
|
|
|
|
|
'Image': f"images/pokemon/{pfic}.png",
|
|
|
|
|
'IsDefault': form_name is None or form_name == '',
|
|
|
|
|
'Generation': generation,
|
|
|
|
|
'StorableInHome': storable_in_home,
|
|
|
|
|
'MarkIcon': mark_icon,
|
|
|
|
|
'MarkID': mark_id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Add the Pokémon to the current group
|
|
|
|
|
if national_dex != current_dex_number:
|
|
|
|
|
if pokemon_forms:
|
|
|
|
|
for form in pokemon_forms:
|
|
|
|
|
current_group.append(form)
|
|
|
|
|
if len(current_group) == 30:
|
|
|
|
|
pokemon_list.append(current_group)
|
|
|
|
|
current_group = []
|
|
|
|
|
pokemon_forms = []
|
|
|
|
|
current_dex_number = national_dex
|
|
|
|
|
|
|
|
|
|
if form_name is None or form_name == '':
|
|
|
|
|
if current_generation is None or generation != current_generation:
|
|
|
|
|
if current_group:
|
|
|
|
|
while len(current_group) < 30:
|
|
|
|
|
current_group.append(None) # Add empty slots
|
|
|
|
|
pokemon_list.append(current_group)
|
|
|
|
|
current_group = []
|
|
|
|
|
current_generation = generation
|
|
|
|
|
|
|
|
|
|
pokemon_forms.append(pokemon)
|
|
|
|
|
|
|
|
|
|
# Add the last set of forms
|
|
|
|
|
for form in pokemon_forms:
|
|
|
|
|
current_group.append(form)
|
|
|
|
|
if len(current_group) == 30:
|
|
|
|
|
pokemon_list.append(current_group)
|
|
|
|
|
current_group = []
|
|
|
|
|
|
|
|
|
|
# Add any remaining Pokémon
|
|
|
|
|
if current_group:
|
|
|
|
|
while len(current_group) < 30:
|
|
|
|
|
current_group.append(None) # Add empty slots to the last group
|
|
|
|
|
pokemon_list.append(current_group)
|
|
|
|
|
|
|
|
|
|
conn.close()
|
|
|
|
|
return pokemon_list
|
|
|
|
|
|
|
|
|
|
@app.route('/')
|
|
|
|
|
def index():
|
|
|
|
|
pokemon_list = load_pokemon_data()
|
|
|
|
|
|
|
|
|
|
splitter = CustomWordNinja(POKEMON_PROPER_NOUNS)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
with open('efficiency_plan.json', 'r', encoding='utf-8') as f:
|
|
|
|
|
efficiency_plan = json.load(f)
|
|
|
|
|
|
|
|
|
|
conn = sqlite3.connect('pokemon_forms.db')
|
|
|
|
|
cursor = conn.cursor()
|
|
|
|
|
|
|
|
|
|
def get_evolution_methods(from_pfic, to_pfic):
|
|
|
|
|
# Get direct evolution method
|
|
|
|
|
cursor.execute('''
|
|
|
|
|
SELECT method, to_pfic
|
|
|
|
|
FROM evolution_chains
|
|
|
|
|
WHERE from_pfic = ? AND to_pfic = ?
|
|
|
|
|
''', (from_pfic, to_pfic))
|
|
|
|
|
direct = cursor.fetchone()
|
|
|
|
|
|
|
|
|
|
if direct:
|
|
|
|
|
words = splitter.split(direct[0])
|
|
|
|
|
return [words]
|
|
|
|
|
|
|
|
|
|
# Try to find indirect evolution path
|
|
|
|
|
cursor.execute('''
|
|
|
|
|
WITH RECURSIVE evolution_path AS (
|
|
|
|
|
-- Base case: direct evolutions from start
|
|
|
|
|
SELECT from_pfic, to_pfic, method, 1 as depth
|
|
|
|
|
FROM evolution_chains
|
|
|
|
|
WHERE from_pfic = ?
|
|
|
|
|
|
|
|
|
|
UNION ALL
|
|
|
|
|
|
|
|
|
|
-- Recursive case: follow chain
|
|
|
|
|
SELECT e.from_pfic, e.to_pfic, e.method, ep.depth + 1
|
|
|
|
|
FROM evolution_chains e
|
|
|
|
|
JOIN evolution_path ep ON e.from_pfic = ep.to_pfic
|
|
|
|
|
WHERE ep.depth < 3 -- Prevent infinite loops
|
|
|
|
|
)
|
|
|
|
|
SELECT method
|
|
|
|
|
FROM evolution_path
|
|
|
|
|
WHERE to_pfic = ?
|
|
|
|
|
ORDER BY depth;
|
|
|
|
|
''', (from_pfic, to_pfic))
|
|
|
|
|
|
|
|
|
|
methods = cursor.fetchall()
|
|
|
|
|
if methods:
|
|
|
|
|
# Clean up each method string
|
|
|
|
|
cleaned_methods = []
|
|
|
|
|
for method in methods:
|
|
|
|
|
# Split and rejoin with spaces
|
|
|
|
|
words = splitter.split(method[0])
|
|
|
|
|
cleaned_methods.append(words)
|
|
|
|
|
return cleaned_methods
|
|
|
|
|
return ['Evolution']
|
|
|
|
|
|
|
|
|
|
# Enhance the plan with evolution methods
|
|
|
|
|
for game in efficiency_plan:
|
|
|
|
|
for pokemon in game['pokemon']:
|
|
|
|
|
if pokemon.get('evolve_to'):
|
|
|
|
|
for evolution in pokemon['evolve_to']:
|
|
|
|
|
methods = get_evolution_methods(pokemon['pfic'], evolution['pfic'])
|
|
|
|
|
evolution['method'] = ' → '.join(methods)
|
|
|
|
|
|
|
|
|
|
conn.close()
|
|
|
|
|
|
|
|
|
|
except FileNotFoundError:
|
|
|
|
|
efficiency_plan = []
|
|
|
|
|
|
|
|
|
|
return render_template('index.html',
|
|
|
|
|
grouped_pokemon=pokemon_list,
|
|
|
|
|
efficiency_plan=efficiency_plan)
|
|
|
|
|
|
|
|
|
|
@app.route('/pokemon/<string:pfic>')
|
|
|
|
|
def pokemon_details(pfic):
|
|
|
|
|
conn = sqlite3.connect('pokemon_forms.db')
|
|
|
|
|
cursor = conn.cursor()
|
|
|
|
|
|
|
|
|
|
cursor.execute('''
|
|
|
|
|
SELECT pf.form_name, g.name, g.id as game_id, e.location, e.day, e.time,
|
|
|
|
|
e.dual_slot, e.static_encounter, e.static_encounter_count,
|
|
|
|
|
e.extra_text, e.stars, e.fishing, e.rods, e.starter
|
|
|
|
|
FROM pokemon_forms pf
|
|
|
|
|
JOIN encounters e ON pf.PFIC = e.pfic
|
|
|
|
|
JOIN games g ON e.game_id = g.id
|
|
|
|
|
WHERE pf.pfic = ?
|
|
|
|
|
ORDER BY g.id, pf.form_name, e.location
|
|
|
|
|
''', (pfic,))
|
|
|
|
|
|
|
|
|
|
encounters = [
|
|
|
|
|
{
|
|
|
|
|
'form': form,
|
|
|
|
|
'game': game,
|
|
|
|
|
'game_id': game_id,
|
|
|
|
|
'location': location,
|
|
|
|
|
'day': day,
|
|
|
|
|
'time': time,
|
|
|
|
|
'dual_slot': dual_slot,
|
|
|
|
|
'static_encounter': static_encounter,
|
|
|
|
|
'static_encounter_count': static_encounter_count,
|
|
|
|
|
'extra_text': extra_text,
|
|
|
|
|
'stars': stars,
|
|
|
|
|
'fishing': fishing,
|
|
|
|
|
'rods': rods,
|
|
|
|
|
'starter': starter
|
|
|
|
|
}
|
|
|
|
|
for form, game, game_id, location, day, time, dual_slot, static_encounter, static_encounter_count,
|
|
|
|
|
extra_text, stars, fishing, rods, starter in cursor.fetchall()
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
conn.close()
|
|
|
|
|
return jsonify(encounters)
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
extra_files = ['.']
|
|
|
|
|
extra_dirs = ['./templates/', './static/']
|
|
|
|
|
for extra_dir in extra_dirs:
|
|
|
|
|
for dirname, dirs, files in os.walk(extra_dir):
|
|
|
|
|
for filename in files:
|
|
|
|
|
filename = os.path.join(dirname, filename)
|
|
|
|
|
if os.path.isfile(filename):
|
|
|
|
|
extra_files.append(filename)
|
|
|
|
|
|
|
|
|
|
app.run(debug=True, extra_files=extra_files)
|