Skip to content

Commit 060dfbb

Browse files
author
Gin
committed
add script to process collected Home pokemon
1 parent 604b8cc commit 060dfbb

File tree

1 file changed

+213
-0
lines changed

1 file changed

+213
-0
lines changed
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Script to check which Pokemon from a subset you've already collected.
4+
5+
Usage:
6+
python check_pokemon_collection.py --subset SUBSET_FILE --pages BOX_PAGE_FILE1 [BOX_PAGE_FILE2 ...] --trainers TRAINER_FILE [--national NATIONAL_DEX]
7+
8+
Example:
9+
python check_pokemon_collection.py \
10+
--subset /path/to/Pokedex-Lumiose.json \
11+
--pages /path/to/box_order_page_1.json /path/to/box_order_page_2.json \
12+
--trainers /path/to/my_ot.json \
13+
--national /path/to/Pokedex-National.json
14+
15+
You can also use "*" when specifying pages:
16+
python check_pokemon_collection.py \
17+
--subset /path/to/Pokedex-Lumiose.json \
18+
--pages /path/to/box_order_page_*.json \
19+
--trainers /path/to/my_ot.json \
20+
--national /path/to/Pokedex-National.json
21+
"""
22+
23+
import json
24+
import argparse
25+
from pathlib import Path
26+
from typing import Dict, List, Set
27+
28+
29+
def load_json(filepath: str) -> any:
30+
"""Load a JSON file."""
31+
# Use utf-8-sig to handle BOM if present
32+
with open(filepath, 'r', encoding='utf-8-sig') as f:
33+
return json.load(f)
34+
35+
36+
def load_national_pokedex(filepath: str) -> List[str]:
37+
"""Load the national pokedex mapping (dex number -> pokemon name)."""
38+
pokedex = load_json(filepath)
39+
# The array is 0-indexed but national dex starts at 1
40+
# So index 0 = dex #1, index 1 = dex #2, etc.
41+
return pokedex
42+
43+
44+
def load_subset(filepath: str) -> List[str]:
45+
"""Load the subset of pokemon names we're looking for (preserving order)."""
46+
subset_list = load_json(filepath)
47+
return subset_list
48+
49+
50+
def load_trainer_mapping(filepath: str) -> Dict[int, str]:
51+
"""Load trainer ID to name mapping."""
52+
mapping_str = load_json(filepath)
53+
# Convert string keys to integers
54+
return {int(k): v for k, v in mapping_str.items()}
55+
56+
57+
def load_box_pages(filepaths: List[str]) -> List[dict]:
58+
"""Load all box page JSON files and combine them."""
59+
all_pokemon = []
60+
for page_idx, filepath in enumerate(filepaths):
61+
pokemon_list = load_json(filepath)
62+
for pokemon in pokemon_list:
63+
pokemon['page'] = page_idx
64+
all_pokemon.extend(pokemon_list)
65+
return all_pokemon
66+
67+
68+
def get_pokemon_name(national_dex_number: int, national_pokedex: List[str]) -> str:
69+
"""Get pokemon name from national dex number."""
70+
# national_dex_number 1 -> index 0
71+
index = national_dex_number - 1
72+
if 0 <= index < len(national_pokedex):
73+
return national_pokedex[index]
74+
return f"Unknown (#{national_dex_number})"
75+
76+
77+
def get_trainer_name(ot_id: int, trainer_mapping: Dict[int, str]) -> str:
78+
"""Get trainer name from OT ID, or return ID if not found."""
79+
return trainer_mapping.get(ot_id, str(ot_id))
80+
81+
82+
def is_valid_pokemon(pokemon: dict) -> bool:
83+
"""Check if a pokemon object has the minimum required fields (not an empty slot)."""
84+
required_fields = ['national_dex_number', 'ot_id']
85+
return all(field in pokemon for field in required_fields)
86+
87+
88+
def format_gender(gender: str) -> str:
89+
"""Format gender for display."""
90+
if gender == "Male":
91+
return "♂"
92+
elif gender == "Female":
93+
return "♀"
94+
else:
95+
return "-"
96+
97+
98+
def format_ball(ball_slug: str) -> str:
99+
"""Format pokeball name for display."""
100+
# Remove '-ball' suffix and capitalize
101+
if ball_slug.endswith('-ball'):
102+
ball_name = ball_slug[:-5]
103+
else:
104+
ball_name = ball_slug
105+
return ball_name.capitalize()
106+
107+
108+
def main():
109+
parser = argparse.ArgumentParser(
110+
description='Check which Pokemon from a subset you have collected.',
111+
formatter_class=argparse.RawDescriptionHelpFormatter,
112+
epilog=__doc__
113+
)
114+
parser.add_argument('--subset', required=True, help='Path to subset pokedex JSON (e.g., Pokedex-Lumiose.json)')
115+
parser.add_argument('--pages', nargs='+', required=True, help='Path(s) to one or more JSON files where each file stores a single page of box order')
116+
parser.add_argument('--trainers', required=True, help='Path to trainer ID mapping JSON (my_ot.json)')
117+
parser.add_argument('--national', help='Path to national pokedex JSON (default: auto-detect from subset location)')
118+
119+
args = parser.parse_args()
120+
121+
# Auto-detect national pokedex if not provided
122+
if args.national:
123+
national_path = args.national
124+
else:
125+
# Try to find Pokedex-National.json in the same directory as subset
126+
subset_dir = Path(args.subset).parent
127+
national_path = subset_dir / 'Pokedex-National.json'
128+
if not national_path.exists():
129+
# Try the Pokemon/Pokedex directory
130+
national_path = subset_dir.parent / 'Pokedex' / 'Pokedex-National.json'
131+
if not national_path.exists():
132+
print(f"Error: Could not find Pokedex-National.json. Please specify with --national")
133+
return 1
134+
135+
# Load all data
136+
print(f"Loading national pokedex from: {national_path}")
137+
national_pokedex = load_national_pokedex(str(national_path))
138+
139+
print(f"Loading subset from: {args.subset}")
140+
subset = load_subset(args.subset)
141+
142+
print(f"Loading trainer mapping from: {args.trainers}")
143+
trainer_mapping = load_trainer_mapping(args.trainers)
144+
145+
print(f"Loading {len(args.pages)} box page(s)...")
146+
all_pokemon = load_box_pages(args.pages)
147+
148+
# Filter pokemon in subset
149+
print(f"\nSearching for {len(subset)} pokemon in {len(all_pokemon)} slots...")
150+
print("=" * 100)
151+
152+
# Build a mapping from pokemon name to list of found instances
153+
found_pokemon_map = {}
154+
for pokemon in all_pokemon:
155+
if not is_valid_pokemon(pokemon):
156+
continue
157+
158+
pokemon_name = get_pokemon_name(pokemon['national_dex_number'], national_pokedex)
159+
160+
if pokemon_name in subset:
161+
if pokemon_name not in found_pokemon_map:
162+
found_pokemon_map[pokemon_name] = []
163+
164+
found_pokemon_map[pokemon_name].append({
165+
'name': pokemon_name,
166+
'trainer': get_trainer_name(pokemon.get('ot_id'), trainer_mapping),
167+
'gender': pokemon.get('gender', 'Unknown'),
168+
'ball': pokemon.get('ball_slug', 'unknown'),
169+
'alpha': pokemon.get('alpha', False),
170+
'shiny': pokemon.get('shiny', False),
171+
'page': pokemon.get('page') + 1, # make them 1-indexed
172+
'box': pokemon.get('box', -2) + 1,
173+
'row': pokemon.get('row', -2) + 1,
174+
'column': pokemon.get('column', -2) + 1,
175+
})
176+
177+
# Flatten results in the order of the subset
178+
found_pokemon = []
179+
for pokemon_name in subset:
180+
if pokemon_name in found_pokemon_map:
181+
found_pokemon.extend(found_pokemon_map[pokemon_name])
182+
183+
# Print results
184+
print(f"\n{'Pokemon':<20} {'Trainer':<15} {'Gender':<8} {'Ball':<15} {'Alpha':<7} {'Shiny':<7} {'Location'}")
185+
print("=" * 110)
186+
187+
for p in found_pokemon:
188+
alpha_str = "✓" if p['alpha'] else "-"
189+
shiny_str = "✓" if p['shiny'] else "-"
190+
location = f"Page {p['page']} Box {p['box']}, Row {p['row']} Col {p['column']}"
191+
192+
print(f"{p['name']:<20} {p['trainer']:<15} {format_gender(p['gender']):<8} "
193+
f"{format_ball(p['ball']):<15} {alpha_str:<7} {shiny_str:<7} {location}")
194+
195+
# Summary
196+
print("=" * 110)
197+
# Count unique pokemon found
198+
unique_found = len(set(p['name'] for p in found_pokemon))
199+
print(f"\nFound {unique_found} / {len(subset)} unique pokemon from subset")
200+
print(f"Total instances: {len(found_pokemon)}")
201+
print(f"Missing {len(subset) - unique_found} pokemon")
202+
203+
# Show missing pokemon
204+
if unique_found < len(subset):
205+
found_names = {p['name'] for p in found_pokemon}
206+
missing = [name for name in subset if name not in found_names]
207+
print(f"\nMissing pokemon:")
208+
for i, name in enumerate(missing, 1):
209+
print(f" {i}. {name}")
210+
211+
212+
if __name__ == '__main__':
213+
main()

0 commit comments

Comments
 (0)