mirror of
https://github.com/LazoCoder/Pokemon-Terminal
synced 2024-11-27 06:10:29 +00:00
285 lines
11 KiB
Python
285 lines
11 KiB
Python
"""This files the loading of the pokemon database and the pokemon object"""
|
|
|
|
import os
|
|
import random
|
|
|
|
|
|
class Pokemon:
|
|
"""Class to represent pokemons"""
|
|
# ID is stored as a string because it must maintain "003" format, not "3".
|
|
__id = ""
|
|
__name = ""
|
|
__region = ""
|
|
__path = "" # The location of the image.
|
|
__pkmn_type = ""
|
|
__pkmn_type_secondary = ""
|
|
__dark_threshold = 0.5
|
|
|
|
def __init__(self, identifier, name, region, path, pkmn_type,
|
|
pkmn_type_secondary, dark_threshold):
|
|
self.__id = identifier
|
|
self.__name = name
|
|
self.__region = region
|
|
self.__path = path
|
|
self.__dark_threshold = float(dark_threshold)
|
|
self.__pkmn_type = pkmn_type
|
|
self.__pkmn_type_secondary = pkmn_type_secondary
|
|
|
|
def get_id(self):
|
|
# Pokemon from folder 'Extra' have no ID.
|
|
return self.__id or "---"
|
|
|
|
def get_name(self):
|
|
return self.__name
|
|
|
|
def get_region(self):
|
|
return self.__region
|
|
|
|
def get_path(self):
|
|
return self.__path
|
|
|
|
def get_pkmn_type(self):
|
|
return self.__pkmn_type
|
|
|
|
def get_pkmn_type_secondary(self):
|
|
return self.__pkmn_type_secondary
|
|
|
|
def get_dark_threshold(self):
|
|
return self.__dark_threshold
|
|
|
|
def is_extra(self):
|
|
return self.__id is None
|
|
|
|
def __str__(self):
|
|
name = self.get_name().title()
|
|
return self.get_id() + " " + name + " at " + self.get_path()
|
|
|
|
|
|
class Database:
|
|
"""The Database object is a container for all the supported Pokemon."""
|
|
POKEMON_TYPES = ('normal', 'fire', 'fighting', 'water', 'flying',
|
|
'grass', 'poison', 'electric', 'ground', 'psychic',
|
|
'rock', 'ice', 'bug', 'dragon', 'ghost', 'dark',
|
|
'steel', 'fairy')
|
|
__directory = "" # The global location of the code.
|
|
MAX_ID = 719 # Highest possible Pokemon ID.
|
|
REGIONS = ('kanto', 'johto', 'hoenn', 'sinnoh', 'unova', 'kalos')
|
|
|
|
def __init__(self):
|
|
self.__pokemon_list = []
|
|
self.__pokemon_dictionary = {}
|
|
self.__pokemon_type_dictionary = {}
|
|
self.directory = os.path.dirname(os.path.realpath(__file__))
|
|
for pkmn_t in self.POKEMON_TYPES:
|
|
self.__pokemon_type_dictionary[pkmn_t] = []
|
|
self.__load_data()
|
|
self.__load_extra()
|
|
|
|
def __str__(self):
|
|
return "\n".join(str(element) for element in self.__pokemon_list)
|
|
|
|
def __contains__(self, pokemon):
|
|
# Check for a Pokemon by ID or name.
|
|
if isinstance(pokemon, int) or str(pokemon).isdigit():
|
|
return self.pokemon_id_exists(int(pokemon))
|
|
elif isinstance(pokemon, str):
|
|
return self.__pokemon_dictionary.get(pokemon) is not None
|
|
else:
|
|
return self.pokemon_name_exists(pokemon.get_name())
|
|
|
|
def __len__(self):
|
|
return len(self.__pokemon_list)
|
|
|
|
def get_pokemon_of_type(self, pkmn_type: str, single: bool = True):
|
|
pkmns = self.__pokemon_type_dictionary.get(pkmn_type)
|
|
if pkmns is None:
|
|
return None
|
|
return random.choice(pkmns) if single else pkmns
|
|
|
|
def get_all(self):
|
|
# Get all the Pokemon.
|
|
return [pokemon for pokemon in self.__pokemon_list]
|
|
# or... return self.__pokemon_list[:]
|
|
# return a copy of self.__pokemon_list
|
|
|
|
def get_kanto(self):
|
|
# Get all the Pokemon from the Kanto region.
|
|
return self.__get_region("kanto")
|
|
|
|
def get_johto(self):
|
|
# Get all the Pokemon from the Johto region.
|
|
return self.__get_region("johto")
|
|
|
|
def get_hoenn(self):
|
|
# Get all the Pokemon from the Hoenn region.
|
|
return self.__get_region("hoenn")
|
|
|
|
def get_sinnoh(self):
|
|
# Get all the Pokemon from the Sinnoh region.
|
|
return self.__get_region("sinnoh")
|
|
|
|
def get_unova(self):
|
|
# Get all the Pokemon from the Unova region.
|
|
return self.__get_region("unova")
|
|
|
|
def get_kalos(self):
|
|
# Get all the Pokemon from the Kalos region.
|
|
return self.__get_region("kalos")
|
|
|
|
def get_extra(self):
|
|
# Get all the Extra Pokemon images available.
|
|
return [p for p in self.__pokemon_list if p.is_extra()]
|
|
|
|
def get_light(self, threshold=0.4, all_pkmn=False):
|
|
light = [pokemon.get_name() for pokemon in self.__pokemon_list
|
|
if pokemon.get_dark_threshold() > threshold]
|
|
return light if all_pkmn else random.choice(light)
|
|
|
|
def get_dark(self, threshold=0.6, all_pkmn=False):
|
|
dark = [pokemon.get_name() for pokemon in self.__pokemon_list
|
|
if pokemon.get_dark_threshold() < threshold]
|
|
return dark if all_pkmn else random.choice(dark)
|
|
|
|
def __get_region(self, region):
|
|
# Helper method for getting all the Pokemon of a specified region.
|
|
return [pokemon for pokemon in self.__pokemon_list
|
|
if pokemon.get_region() == region and not pokemon.is_extra()]
|
|
|
|
def get_random(self):
|
|
# Select a random Pokemon from the database.
|
|
return random.choice(self.__pokemon_list)
|
|
|
|
def get_random_from_region(self, region):
|
|
# Get a random Pokemon from a specific region.
|
|
return random.choice(self.__get_region(region))
|
|
|
|
def pokemon_id_exists(self, identifier):
|
|
# Check for Pokemon by ID.
|
|
identifier = int(identifier)
|
|
return 0 < identifier <= self.MAX_ID
|
|
|
|
def pokemon_name_exists(self, name):
|
|
# Check for Pokemon by Name.
|
|
return name.lower() in self.__pokemon_dictionary
|
|
|
|
def get_pokemon(self, pokemon):
|
|
# Get a Pokemon by name or ID.
|
|
if isinstance(pokemon, Pokemon):
|
|
return pokemon
|
|
if not isinstance(pokemon, (int, str)):
|
|
raise Exception("The parameter Pokemon must be of type integer" +
|
|
" or string.")
|
|
if isinstance(pokemon, str):
|
|
pokemon = pokemon.lower()
|
|
if pokemon not in self:
|
|
raise Exception("No such Pokemon in the database.")
|
|
if isinstance(pokemon, int) or str(pokemon).isdigit():
|
|
return self.get_pokemon_by_id(int(pokemon))
|
|
else:
|
|
return self.get_pokemon_by_name(pokemon)
|
|
|
|
def get_pokemon_by_name(self, name):
|
|
# Get a Pokemon by its name.
|
|
if not isinstance(name, str):
|
|
raise TypeError("The type of name must be a string.")
|
|
if not self.pokemon_name_exists(name):
|
|
raise Exception("No such Pokemon in the database.")
|
|
return self.__pokemon_dictionary[name]
|
|
|
|
def get_pokemon_by_id(self, identifier):
|
|
# Get a Pokemon by its ID.
|
|
if not isinstance(identifier, int) and not str(identifier).isdigit():
|
|
raise TypeError("The Pokemon ID must be a number.")
|
|
identifier = int(identifier)
|
|
if not self.pokemon_id_exists(identifier):
|
|
raise Exception("The Pokemon ID must be between 1 and " +
|
|
str(self.MAX_ID) + " inclusive.")
|
|
# Subtract 1 to convert to 0 base indexing.
|
|
return self.__pokemon_list[identifier - 1]
|
|
|
|
def names_with_prefix(self, prefix):
|
|
# Return Pokemon who's names begin with the specified prefix.
|
|
return [pokemon for pokemon in self.__pokemon_list
|
|
if str(pokemon.get_name()).startswith(prefix)]
|
|
|
|
def names_with_infix(self, infix):
|
|
# Return Pokemon who's names contains the specified infix.
|
|
return [pokemon for pokemon in self.__pokemon_list
|
|
if infix in str(pokemon.get_name())]
|
|
|
|
def __load_data(self):
|
|
# Load all the Pokemon data. This does not include the 'Extra' Pokemon.
|
|
with open(self.directory + "/./Data/pokemon.txt", 'r') as data_file:
|
|
# Load everything but the Pokemon from the 'Extra' folder.
|
|
for i, line in enumerate(data_file):
|
|
identifier = int(i) + 1
|
|
pkmn_data = line.strip().split()
|
|
name = pkmn_data[0]
|
|
dark_threshold = pkmn_data[1]
|
|
pkmn_type = pkmn_data[2]
|
|
pkmn_type_snd = pkmn_data[3] if len(pkmn_data) >= 4 else ""
|
|
identifier = '{:03}'.format(identifier)
|
|
region = self.__determine_region(identifier)
|
|
path = self.__determine_folder(identifier) + "/" + identifier\
|
|
+ ".jpg"
|
|
pokemon = Pokemon(identifier, name, region, path, pkmn_type,
|
|
pkmn_type_snd, dark_threshold)
|
|
self.__pokemon_type_dictionary[pkmn_type].append(pokemon)
|
|
if pkmn_type_snd != '':
|
|
self.__pokemon_type_dictionary[pkmn_type_snd]\
|
|
.append(pokemon)
|
|
self.__pokemon_list.append(pokemon)
|
|
self.__pokemon_dictionary[pokemon.get_name()] = pokemon
|
|
|
|
def __load_extra(self):
|
|
"""Load all the file names of the images in the Extra folder."""
|
|
extra_dir = os.path.join(self.directory, "Images", "Extra")
|
|
for file in os.listdir(extra_dir):
|
|
name, ext = os.path.splitext(file.lower())
|
|
if ext == '.jpg':
|
|
path = os.path.join(extra_dir, file)
|
|
father = self.__pokemon_dictionary.get(name.split("-")[0])
|
|
if father is not None:
|
|
pokemon = Pokemon(None, name, father.get_region(),
|
|
path, father.get_pkmn_type(),
|
|
father.get_pkmn_type_secondary(),
|
|
father.get_dark_threshold())
|
|
else:
|
|
pokemon = Pokemon(None, name, None, path, None, None, 0.5)
|
|
if name in self.__pokemon_dictionary:
|
|
raise Exception("Duplicate names detected.\nThe name of "
|
|
+ "the file " + str(name) + ".jpg in the "
|
|
+ "folder 'Extra' must be changed.")
|
|
self.__pokemon_list.append(pokemon)
|
|
self.__pokemon_dictionary[pokemon.get_name()] = pokemon
|
|
|
|
def __determine_region(self, identifier):
|
|
"""Determine which region a Pokemon is from."""
|
|
identifier = int(identifier)
|
|
if identifier < 1:
|
|
raise Exception("Pokemon ID cannot be less than 1.")
|
|
if identifier < 152:
|
|
return "kanto"
|
|
elif identifier < 252:
|
|
return "johto"
|
|
elif identifier < 387:
|
|
return "hoenn"
|
|
elif identifier < 494:
|
|
return "sinnoh"
|
|
elif identifier < 650:
|
|
return "unova"
|
|
elif identifier < 720:
|
|
return "kalos"
|
|
else:
|
|
raise Exception("Pokemon ID cannot be greater than 719.")
|
|
|
|
def __determine_folder(self, identifier):
|
|
# Determine which folder a Pokemon is from.
|
|
suffix_dict = {"kanto": "I - Kanto",
|
|
"johto": "II - Johto",
|
|
"hoenn": "III - Hoenn",
|
|
"sinnoh": "IV - Sinnoh",
|
|
"unova": "V - Unova",
|
|
"kalos": "VI - Kalos"}
|
|
suffix = suffix_dict.get(self.__determine_region(identifier))
|
|
return "{}/Images/Generation {}".format(self.directory, suffix)
|