In een toernooi strijden $$2^n$$ ($$n \in \mathbb{N}$$) landen om de overwinning. Er wordt gewerkt met een knockoutsysteem dat loopt over $$n$$ ronden. In elke ronde worden alle landen aan een ander land gekoppeld: het eerst land speelt een wedstrijd tegen het tweede land, het derde land tegen het vierde land, enzoverder. De winnaar van elke wedstrijd gaat door naar de volgende ronde en voor de verliezer is het toernooi voorbij. Op die manier wordt het aantal landen bij elke ronde gehalveerd, en blijft er na $$n$$ ronden nog één land over. Dat land wint het toernooi.

In een knockoutsysteem moet elke wedstrijd een winnaar opleveren. Tijdens de reguliere speeltijd van een wedstrijd behaalt elk land een score: hoe hoger de score hoe beter. Als er na de reguliere speeltijd nog geen winnaar is, dan kunnen beide landen in de extra speeltijd hun score nog verhogen. Als er na de extra speeltijd nog altijd geen winnaar is, dan moeten penalties uitmaken wie de wedstrijd wint.

In onderstaand voorbeeld wordt de score na de reguliere speeltijd van elke wedstrijd aangegeven in het geel, en de score na de extra speeltijd in het grijs. In dit geval werd geen enkele wedstrijd beslist na het nemen van penalties.

knockout
Voorbeeld van het verloop van een toernooi tussen 8 landen, waarin wordt gewerkt met een knockoutsysteem. Voor elke wedstrijd wordt de score na de reguliere speeltijd aangegeven in het geel, en de score na de extra speeltijd in het grijs. In dit geval werd geen enkele wedstrijd beslist na het nemen van penalities.

Als land $$a$$ (met hoofdstad $$h_a$$) een wedstrijd speelt tegen land $$b$$ (met hoofdstad $$h_b$$) dan gebruiken we een vaste procedure om de winnaar te bepalen. Na de reguliere speeltijd is de score voor land $$a$$ gelijk aan het aantal overeenkomstige letters met hoofdstad $$h_b$$. Analoog is de score voor land $$b$$ gelijk aan het aantal overeenkomstige letters met hoofdstad $$h_a$$. Dit is inclusief dubbele letters. Enkele voorbeelden:

In de extra tijd doen alle letters die potentieel overeenkomstig zijn ook mee. Dat is het makkelijkst uit te leggen aan de hand van enkele voorbeelden:

Bij de penalties wint het land dat alfabetisch het eerst komt. In het laatste voorbeeld wint Australia dus op penalties tegen Grenada.

score
Voorbeeld van de procedure om de score te berekenen na de reguliere speeltijd en na de extra speeltijd, in een wedstrijd die gespeeld wordt tussen Austria (Vienna) en Lithuania (Vilnius). Lithuania wint de wedstrijd na de extra tijd.

Opgave

Schrijf een functie letterfrequenties waaraan een string $$s$$ (str) moet doorgegeven worden. De functie moet een dictionary teruggeven die alle letters die voorkomen in $$s$$ afbeeldt op hun aantal voorkomens. Bij het tellen van het aantal voorkomens mag geen onderscheid gemaakt worden tussen hoofdletters en kleine letters, en in de dictionary moeten de letters als hoofdletter voorgesteld worden. Indien $$s$$ karakters bevat die geen letter zijn, dan moeten die genegeerd worden.

Definieer daarnaast ook nog een klasse Knockout waarmee de knockoutfase van een landentoernooi kan gesimuleerd worden op basis van het scoresysteem uit de inleiding. Bij het aanmaken van een object van de klasse Knockout moet de locatie van een CSV-bestand1 doorgegeven worden. Elke regel van dit bestand bevat zes velden met informatie over een land, die van elkaar gescheiden worden door komma's: i) naam van het land, ii) naam van de hoofdstad, iii) breedtegraad van de hoofdstad, iv) lengtegraad van de hoofdstad, v) landcode en vi) naam van het werelddeel. De klasse Knockout moet minstens de volgende methoden ondersteunen:

De methoden mogen geen onderscheid maken tussen hoofdletters en kleine letters bij het verwerken van de landen die eraan doorgegeven worden, en ook niet bij het verwerken van hun hoofdsteden. Als er aan een methode een land wordt doorgegeven dat niet voorkomt in het gegeven CSV-bestand, dan moet een AssertionError opgeworpen worden met de boodschap onbekend land.

Voorbeeld

In onderstaand voorbeeldsessie gaan we ervan uit dat het CSV-bestand landen.csv2 zich in de huidige directory bevindt.

>>> letterfrequenties('Russia')
{'R': 1, 'U': 1, 'S': 2, 'I': 1, 'A': 1}
>>> letterfrequenties('Moscou')
{'M': 1, 'O': 2, 'S': 1, 'C': 1, 'U': 1}
>>> letterfrequenties('Puerto Rico')
{'P': 1, 'U': 1, 'E': 1, 'R': 2, 'T': 1, 'O': 2, 'I': 1, 'C': 1}
>>> letterfrequenties('Guinea-Bissau')
{'G': 1, 'U': 2, 'I': 2, 'N': 1, 'E': 1, 'A': 2, 'B': 1, 'S': 2}

>>> toernooi = Knockout('landen.csv3')
>>> toernooi.hoofdstad('Switzerland')
'Bern'
>>> toernooi.hoofdstad('Estonia')
'Tallinn'
>>> toernooi.reguliere_tijd('Switzerland', 'Estonia')
(5, 2)
>>> toernooi.reguliere_tijd('Belgium', 'Denmark')
(2, 2)
>>> toernooi.reguliere_tijd('Portugal', 'Austria')
(1, 2)
>>> toernooi.reguliere_tijd('Netherlands', 'Lithuania')
(3, 3)
>>> toernooi.extra_tijd('Belgium', 'Denmark')
(3, 2)
>>> toernooi.extra_tijd('Netherlands', 'Lithuania')
(4, 5)
>>> toernooi.wedstrijd('Switzerland', 'Estonia')
'Switzerland'
>>> toernooi.wedstrijd('Belgium', 'Denmark')
'Belgium'
>>> toernooi.wedstrijd('Portugal', 'Austria')
'Austria'
>>> toernooi.wedstrijd('Netherlands', 'Lithuania')
'Lithuania'
>>> toernooi.winnaar(['Switzerland', 'Estonia', 'Belgium', 'Denmark', 'Portugal', 'Austria', 'Netherlands', 'Lithuania'])
'Switzerland'