Pokémon are fictional creatures which humans — known as Pokémon Trainers — catch and train to battle each other for sport. During such a battle, an attacking Pokémon makes a move (技 waza) to reduce his opponent's HP (health points) to zero, at which point the Pokémon faints (ひんし hinshi).
A Pokémon's type (タイプ taipu) is an elemental attribute determining the strengths and weaknesses of each Pokémon and their moves, offsetting each other in rock-paper-scissors relationships. The primary example of this elemental relationship is that between the Grass, Fire, and Water types: a Grass is weak to Fire, Fire is weak to Water, and Water is weak to Grass, with each resistant against the others. Elemental relationships where Pokémon are immune include Ghost types immune to Normal and Fighting moves. These weaknesses, resistances, and immunities can be combined if a Pokémon has multiple types.
The current franchise includes 802 species of Pokémon, and there exist eighteen Pokémon types. The following charts summarizes their elemental relationships:
In a battle between two Pokémon, the one making a move is called the attacker and the one targeted by the move is called the defender. A move always has a certain type and can be super effective, normal, not very effective or have no effect at all against another type. These translate respectively to $$2\times$$, $$1\times$$, $$0.5\times$$ and $$0\times$$ damage multiplication. If a Pokémon has multiple types, the effectiveness of a move against this Pokémon will be the product of the effectiveness of the move to its individual types.
We will process text files that define elemental relationships between different types of Pokémon. Each line of such a file contains three information fields that are separated from each other by a single tab: i) type of move, ii) type of defender and iii) damage multiplication factor (a floating point number) of the move with the given type against the given type of defender. Only moves having a damage multiplication factor that deviates from normal effectiveness (damage multiplication factor $$1\times$$) are contained in the file.
grass steel 0.5
steel rock 2.0
grass grass 0.5
dragon steel 0.5
fighting psychic 0.5
electric grass 0.5
ice ice 0.5
dark fighting 0.5
Your task is to use the information contained in such a text file to compute the effectiveness of a move against a Pokémon that may have multiple types. This is done in the following way:
Write a function damage that takes the location (str) of a text file defining the elemental relationships between different types of Pokémon. The function must return a dictionary (dict) whose keys are formed by all types of moves (str) contained in the given text file. Each type of move must be mapped onto a separate dictionary (dict), that maps all defender types (str) contained in the given text file onto the damage multiplication factor (float) of that type of move against that type of defender.
Write a function effectiveness that can be used to compute the effectiveness of a move against a Pokémon. The function takes three arguments: i) the type of the move (str), ii) the types of the defender (str; the types of the defending Pokémon are separated from each other by a single space) and iii) the location (str) of a text file defining elemental relationships between different types of Pokémon. The function must return the effectiveness (float) of the move. The function should take into account that if a Pokémon has multiple types, the effectiveness of a move against that Pokémon is computed as the product of the damage multiplication factors of the individual types, and that moves between individual types with damage multiplication factor $$1\times$$ are not explicitly contained in the given text file.
In the following interactive session, we assume the text file relationships.txt1 to be located in the current directory.
>>> damage('relationships.txt2') {'fairy': {'poison': 0.5, 'steel': 0.5, 'fire': 0.5, 'dark': 2.0, 'fighting': 2.0, 'dragon': 2.0}, 'fighting': {'fairy': 0.5, 'ghost': 0.0, 'steel': 2.0, 'flying': 0.5, 'ice': 2.0, 'poison': 0.5, 'bug': 0.5, 'normal': 2.0, 'dark': 2.0, 'psychic': 0.5, 'rock': 2.0}, 'steel': {'steel': 0.5, 'ice': 2.0, 'fairy': 2.0, 'electric': 0.5, 'water': 0.5, 'fire': 0.5, 'rock': 2.0}, 'ice': {'ground': 2.0, 'steel': 0.5, 'grass': 2.0, 'ice': 0.5, 'flying': 2.0, 'water': 0.5, 'dragon': 2.0, 'fire': 0.5}, 'water': {'ground': 2.0, 'fire': 2.0, 'grass': 0.5, 'water': 0.5, 'dragon': 0.5, 'rock': 2.0}, 'dark': {'ghost': 2.0, 'fighting': 0.5, 'dark': 0.5, 'psychic': 2.0, 'fairy': 0.5}, 'flying': {'steel': 0.5, 'bug': 2.0, 'fighting': 2.0, 'electric': 0.5, 'grass': 2.0, 'rock': 0.5}, 'grass': {'ground': 2.0, 'poison': 0.5, 'steel': 0.5, 'grass': 0.5, 'bug': 0.5, 'flying': 0.5, 'water': 2.0, 'fire': 0.5, 'dragon': 0.5, 'rock': 2.0}, 'rock': {'ground': 0.5, 'flying': 2.0, 'steel': 0.5, 'ice': 2.0, 'bug': 2.0, 'fighting': 0.5, 'fire': 2.0}, 'ground': {'poison': 2.0, 'steel': 2.0, 'fire': 2.0, 'bug': 0.5, 'flying': 0.0, 'electric': 2.0, 'grass': 0.5, 'rock': 2.0}, 'ghost': {'dark': 0.5, 'ghost': 2.0, 'psychic': 2.0, 'normal': 0.0}, 'poison': {'ground': 0.5, 'ghost': 0.5, 'steel': 0.0, 'poison': 0.5, 'fairy': 2.0, 'grass': 2.0, 'rock': 0.5}, 'fire': {'fire': 0.5, 'dragon': 0.5, 'ice': 2.0, 'steel': 2.0, 'bug': 2.0, 'water': 0.5, 'grass': 2.0, 'rock': 0.5}, 'normal': {'ghost': 0.0, 'steel': 0.5, 'rock': 0.5}, 'bug': {'ghost': 0.5, 'poison': 0.5, 'steel': 0.5, 'grass': 2.0, 'fairy': 0.5, 'flying': 0.5, 'fighting': 0.5, 'fire': 0.5, 'dark': 2.0, 'psychic': 2.0}, 'electric': {'ground': 0.0, 'grass': 0.5, 'electric': 0.5, 'flying': 2.0, 'water': 2.0, 'dragon': 0.5}, 'dragon': {'steel': 0.5, 'dragon': 2.0, 'fairy': 0.0}, 'psychic': {'fighting': 2.0, 'dark': 0.0, 'poison': 2.0, 'steel': 0.5, 'psychic': 0.5}} >>> effectiveness('fire', 'grass', 'relationships.txt3') 2.0 >>> effectiveness('fighting', 'ice rock', 'relationships.txt4') 4.0 >>> effectiveness('psychic', 'poison dark', 'relationships.txt5') 0.0 >>> effectiveness('water', 'normal', 'relationships.txt6') 1.0 >>> effectiveness('fire', 'rock', 'relationships.txt7') 0.5
Thanks to the worldwide success of the Pokémon Go8 game, Pokémon was Google's most trending search term in 20169.