Extra¶
Een toernooi op de spelletjesavond¶
Vier vrienden houden een toernooi Vier op een rij. Iedereen speelt één keer tegen iedereen, en elke wedstrijd bestaat uit een paar potjes. Aan het eind van de avond willen ze weten hoe het ervoor staat: wie heeft hoeveel punten, en hoe ging elke wedstrijd?
Dit is een ander soort gegevens dan de teksten van de basis. Het toernooi zit in een lijst van tuples, en de antwoorden worden sets, dictionaries met lijsten erin en een lijst van lijsten. Dat vraagt comprehensions die meer dan één vorm combineren.
De uitslagen¶
Elke wedstrijd is een tuple van vier: de twee spelers, en hoeveel potjes elk
van de twee won. ("Anne", "Bram", 2, 1) betekent dat Anne twee potjes won en
Bram één. De punten gaan zo:
Uitslag voor een speler |
Punten |
|---|---|
meer potjes gewonnen dan de tegenstander |
3 |
evenveel |
1 |
minder |
0 |
Na die wedstrijd heeft Anne dus 3 punten en Bram 0.
In de cel hieronder staan de uitslagen van het toernooi in results, de namen
op een vaste volgorde in names, en een functie points(result, player) die de
punten van één speler in één wedstrijd teruggeeft. Voer die cel eerst uit.
results = [
("Anne", "Bram", 2, 1),
("Cas", "Daan", 3, 1),
("Anne", "Cas", 2, 2),
("Bram", "Daan", 2, 0),
("Anne", "Daan", 1, 1),
("Bram", "Cas", 3, 2),
]
names = ["Anne", "Bram", "Cas", "Daan"]
def points(result, player):
"""Geeft de punten van player in de wedstrijd result: 3, 1 of 0."""
first, _, wins_first, wins_second = result
if player == first:
own, other = wins_first, wins_second
else:
own, other = wins_second, wins_first
if own > other:
return 3
elif own == other:
return 1
else:
return 0
Wat je gaat maken¶
Stap |
Functie |
Doet |
Resultaat |
|---|---|---|---|
1 |
|
alle spelers van het toernooi |
set |
2 |
|
per speler de punten van elke wedstrijd |
dictionary van lijsten |
3 |
|
per speler het totaal |
dictionary |
4 |
|
de punten van de ene speler tegen de andere |
getal |
5 |
|
alle wedstrijden in één tabel |
lijst van lijsten |
6 |
|
die tabel afdrukken |
niets |
Stap 1 tot en met 5 zijn elk één comprehension of één uitdrukking.
Stap 1: players(results)¶
Geeft de set van alle spelers die in results voorkomen.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
|
|
Hint
Een tuple van vier pak je uit in vier variabelen. Wat je niet nodig hebt, heet
_: for first, _, _, _ in results. Maak zo één set met de eerste spelers en
één met de tweede, en neem de unie uit week 1.
# jouw oplossing
assert players(results) == {"Anne", "Bram", "Cas", "Daan"}
assert players([("Anne", "Bram", 2, 1)]) == {"Anne", "Bram"}
assert players([]) == set()
Stap 2: points_per_player(results)¶
Geeft een dictionary die elke speler koppelt aan de lijst van zijn punten, één
getal per gespeelde wedstrijd, in de volgorde van results.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
|
|
Hint
Dit is een dict comprehension over de spelers uit stap 1. De waarde bij elke
speler is zelf een list comprehension over results, met een filter op de
wedstrijden waarin die speler meedeed.
# jouw oplossing
assert points_per_player(results) == {
"Anne": [3, 1, 1],
"Bram": [0, 3, 3],
"Cas": [3, 1, 0],
"Daan": [0, 0, 1],
}
assert points_per_player([]) == {}
Stap 3: standings(results)¶
Geeft een dictionary die elke speler koppelt aan zijn totaal aantal punten.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
Hint
Loop het resultaat van stap 2 langs met .items().
# jouw oplossing
assert standings(results) == {"Anne": 5, "Bram": 6, "Cas": 4, "Daan": 1}
assert standings([]) == {}
Stap 4: match_points(results, a, b)¶
Geeft de punten die speler a haalde in zijn wedstrijd tegen speler b, of 0
als ze niet tegen elkaar speelden.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
|
|
Hint
set(result[:2]) is de set van de twee spelers van een wedstrijd. Vergelijk je
die met {a, b}, dan vind je de wedstrijd tussen a en b, ongeacht wie er
eerst staat. Neem de som van een list comprehension. Er is hoogstens één
wedstrijd die past, dus de som is de punten uit die wedstrijd, of 0.
# jouw oplossing
assert match_points(results, "Anne", "Bram") == 3
assert match_points(results, "Bram", "Anne") == 0
assert match_points(results, "Cas", "Anne") == 1
assert match_points(results, "Anne", "Eva") == 0
Stap 5: cross_table(results, names)¶
Een kruistabel zet alle wedstrijden in één overzicht. Er is een rij en een
kolom voor elke speler, in de volgorde van names. In rij a en kolom b
staan de punten die a tegen b haalde. Tegen zichzelf speelt niemand; daar
staat "-".
Geeft de kruistabel als lijst van lijsten. Voor het toernooi is dat:
Anne |
Bram |
Cas |
Daan |
|
|---|---|---|---|---|
Anne |
|
3 |
1 |
1 |
Bram |
0 |
|
3 |
3 |
Cas |
1 |
0 |
|
3 |
Daan |
1 |
0 |
0 |
|
Hint
Dit is een geneste comprehension: een rij per speler a, en in elke rij een
waarde per speler b. Die waarde kies je met een conditionele expressie: "-"
als a en b dezelfde zijn, en anders match_points(results, a, b).
# jouw oplossing
assert cross_table(results, names) == [
["-", 3, 1, 1],
[0, "-", 3, 3],
[1, 0, "-", 3],
[1, 0, 0, "-"],
]
assert cross_table([], []) == []
Stap 6: print_table(table, names)¶
Drukt de kruistabel af, met voor elke rij de naam ervoor. Geeft niets terug.
Anne ['-', 3, 1, 1]
Bram [0, '-', 3, 3]
Cas [1, 0, '-', 3]
Daan [1, 0, 0, '-']
Dit wordt een lus, want afdrukken levert geen nieuwe verzameling op. Gebruik
zip om elke naam bij zijn rij te zetten.
# jouw oplossing
print_table(cross_table(results, names), names)
Tot slot¶
Bram heeft de meeste punten, al won Anne haar wedstrijd tegen hem. In de kruistabel zie je waarom: Bram won zijn andere twee wedstrijden, Anne speelde er twee gelijk. Tel je de getallen in een rij van de kruistabel op, dan krijg je het totaal uit stap 3.
Vooruitblik: de ranglijst
standings zegt hoeveel punten iedereen heeft, maar zet de spelers niet op
volgorde. Voor een ranglijst moet je sorteren op het aantal punten. Met wat je
nu kent, kost dat een flinke lus. In week 4 van Programmeren 2 leer je hoe het
korter kan. Zo ziet
het eruit:
totals = standings(results)
ranking = sorted(totals, key=totals.get)
sorted zet de spelers op volgorde, van weinig naar veel punten. key= zegt
waarop: op wat totals.get bij elke speler teruggeeft, dus zijn punten.
totals.get staat er zonder haakjes. Je roept de methode niet zelf aan, maar
geeft haar mee aan sorted, die haar bij elke speler aanroept. Een functie als
argument meegeven is het onderwerp van week 4 van Programmeren 2. Je hoeft het
hier niet te schrijven.