Pokémon zijn fictieve wezens die gevangen en getraind worden door mensen — in deze context Pokémon Trainers genaamd — om ze dan voor de sport tegen elkaar te laten vechten. Tijdens zo een gevecht kan een Pokémon die aanvalt een slag (技 waza) uitdelen aan zijn tegenstander om daarmee diens hoeveelheid HP (health points) tot nul te proberen herleiden, waarop de Pokémon bezwijkt (ひんし hinshi).

Pikachu
Pikachu, de starter-Pokémon van het Elektrisch type uit het spel Pokémon Yellow.

Het type (タイプ taipu) van een Pokémon is een belangrijke eigenschap die aangeeft wat zijn sterke en zwakke punten zijn. Het is een bepalende factor voor de effectiviteit van de slagen die hij aan tegenstanders kan uitdelen, als een soort uitbreiding op de onderlinge verhoudingen tussen de symbolen gebruikt bij het spelletje blad-steen-schaar. Het schoolvoorbeeld van deze onderlinge verhoudingen zijn deze tussen Grass, Fire en Water types: Grass is zwak tegen Fire, Fire is zwak tegen Water, Water is zwak tegen Grass, maar elk zijn ze vrij goed bestand tegen de andere types. Sommige Pokémon zijn ook volledig immuun tegen bepaalde soorten aanvallen, zoals bijvoorbeeld het Ghost type dat immuun is tegen slagen van de types Normal en Fighting. Deze zwakheden, weerstanden en immuniteiten kunnen ook gecombineerd worden als een Pokémon meerdere types heeft.

Momenteel bestaan er 802 verschillende soorten Pokémon en zijn er 18 verschillende Pokémontypes. Onderstaande tabel geeft een samenvatting van hun onderlinge verhoudingen:

onderlingen verhoudingen
Tabel met de onderlinge sterktes, zwaktes en immuniteiten tussen elk van de achttien Pokémontypes.

Bij een gevecht tussen twee Pokémon wordt diegene die een slag uitbrengt de aanvaller genoemd, en diegene die de slag incasseert de verdediger. Een slag heeft altijd een bepaald type en kan ofwel supereffectief zijn, gewoon, niet zeer effectief, of helemaal geen effect hebben op de verdediger. Deze vertalen respectievelijk naar een beschadigingsfactor van $$2\times$$, $$1\times$$, $$0.5\times$$ en $$0\times$$. Als een Pokémon meerdere types heeft, dan wordt de effectiviteit van een slag tegen die Pokémon bepaald als het product van de beschadigingsfactoren voor de individuele types.

Opgave

We gebruiken tekstbestanden waarin de onderlinge verhoudingen van verschillende Pokémontypes vastgelegd worden. Elke regel van het bestand bevat drie informatievelden die telkens van elkaar gescheiden worden door een tab: i) een type aanval, ii) een type verdediger en iii) de beschadigingsfactor (een floating point getal) van een slag die het type aanval uitdeelt aan het type verdediger. Enkel slagen die afwijken van de gewone effectiviteit (beschadigingsfactor $$1\times$$) worden in het bestand opgenomen.

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

Gevraagd wordt om op basis van de informatie uit zo een tekstbestand, de effectiviteit te bepalen van een slag die wordt uitgedeeld aan een Pokémon die meerdere types kan hebben. Hiervoor ga je als volgt te werk:

Voorbeeld

In onderstaande voorbeeldsessie gaan we ervan uit dat het tekstbestand verhoudingen.txt1 zich in de huidige directory bevindt.

>>> beschadigingsfactor('verhoudingen.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}}

>>> effectiviteit('fire', 'grass', 'verhoudingen.txt3')
2.0
>>> effectiviteit('fighting', 'ice rock', 'verhoudingen.txt4')
4.0
>>> effectiviteit('psychic', 'poison dark', 'verhoudingen.txt5')
0.0
>>> effectiviteit('water', 'normal', 'verhoudingen.txt6')
1.0
>>> effectiviteit('fire', 'rock', 'verhoudingen.txt7')
0.5

Epiloog

Dankzij het wereldwijde succes van het spelletje Pokémon Go8, spande Pokémon in 2016 de kroon als meest gebruikte zoekterm in Google9.