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).

Pikachu
Pikachu, the Electric-type Starter Pokémon of the Pokémon Yellow game.

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:

elemental relationships
Chart showing the current eighteen Pokémon types and their strengths, weaknesses and immunities against each other.

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.

Assignment

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:

Example

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

Epilogue

Thanks to the worldwide success of the Pokémon Go8 game, Pokémon was Google's most trending search term in 20169.