# The Database object is a container for all the supported Pokemon. import os import random class Pokemon: __id = "" # ID is stored as a string because it must maintain "003" format, not "3". __name = "" __region = "" __path = "" # The location of the image. def __init__(self, identifier, name, region, path): self.__id = identifier self.__name = name self.__region = region self.__path = path def get_id(self): # Pokemon from folder 'Extra' have no ID. return "---" if self.is_extra() else self.__id def get_name(self): return self.__name def get_region(self): return self.__region def get_path(self): return self.__path def is_extra(self): return self.__id is None def __str__(self): if self.is_extra(): return "--- " + self.get_name().capitalize() + " at " + self.get_path() else: return self.get_id() + " " + self.get_name().capitalize() + " at " + self.get_path() class Database: __pokemon_list = [] __pokemon_dictionary = {} __directory = "" # The global location of the code. __MAX_ID = 493 # Highest possible Pokemon ID. __regions = ('kanto', 'johto', 'hoenn', 'sinnoh') def __init__(self): self.directory = os.path.dirname(os.path.realpath(__file__)) 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)) else: return self.pokemon_name_exists(pokemon) def __len__(self): return len(self.__pokemon_list) 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_regions(self): # Get all the supported regions. return self.__regions 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_extra(self): # Get all the Extra Pokemon images available. return self.__get_region(None) 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] 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 not isinstance(pokemon, (int, str)): raise Exception("The parameter Pokemon must be of type integer or string.") 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.") return self.__pokemon_list[identifier - 1] # Subtract 1 to convert to 0 base indexing. 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: for line in data_file: # Load everything but the Pokemon from the 'Extra' folder. identifier, _, name = line.strip().partition(' ') identifier = '{:03}'.format(int(identifier)) region = self.__determine_region(identifier) path = self.__determine_folder(identifier) + "/" + identifier + ".png" pokemon = Pokemon(identifier, name.lower(), region, path) 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. for file in os.listdir(self.directory + "/./Images/Extra"): if file.endswith(".png"): name = os.path.join("/Images/Extra", file).split('/')[-1][0:-4].lower() path = self.directory + "/./Images/Extra/" + name + ".png" pokemon = Pokemon(None, name, None, path) if name in self.__pokemon_dictionary: raise Exception("Duplicate names detected. " "The name of the file " + str(name) + ".png 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" else: raise Exception("Pokemon ID cannot be greater than 493.") 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"} suffix = suffix_dict.get(self.__determine_region(identifier)) return "{}/./Images/Generation {}".format(self.directory, suffix)