Extra¶
Een toernooi op de spelletjesavond¶
Opdracht: Een toernooi op de spelletjesavond
De gegeven code uit de opgave:
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
Stap 1: players(results)¶
def players(results):
"""Geeft de set van alle spelers in results."""
firsts = {first for first, _, _, _ in results}
seconds = {second for _, second, _, _ in results}
return firsts | seconds
assert players(results) == {"Anne", "Bram", "Cas", "Daan"}
assert players([("Anne", "Bram", 2, 1)]) == {"Anne", "Bram"}
assert players([]) == set()
Twee set comprehensions en een unie. De _ staat voor de delen van de tuple die
hier niet meedoen. Een speler die in beide posities voorkomt, staat door de set
maar één keer in het resultaat.
Stap 2: points_per_player(results)¶
def points_per_player(results):
"""Geeft per speler de lijst van zijn punten per gespeelde wedstrijd."""
return {
player: [points(result, player) for result in results if player in result[:2]]
for player in players(results)
}
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([]) == {}
De waarde bij elke speler is een list comprehension in de dict comprehension.
result[:2] is het deel van de tuple met de twee spelers. Over drie regels
verdeeld leest hij nog in één keer: buiten de spelers, binnen de wedstrijden.
Omdat players een set teruggeeft, kan de volgorde van de sleutels
verschillen; de lijsten zelf volgen de volgorde van results.
Stap 3: standings(results)¶
def standings(results):
"""Geeft per speler zijn totaal aantal punten."""
per_player = points_per_player(results)
return {player: sum(scores) for player, scores in per_player.items()}
assert standings(results) == {"Anne": 5, "Bram": 6, "Cas": 4, "Daan": 1}
assert standings([]) == {}
Stap 4: match_points(results, a, b)¶
def match_points(results, a, b):
"""Geeft de punten van a in de wedstrijd tegen b, of 0 als die er niet is."""
scores = [points(result, a) for result in results if set(result[:2]) == {a, b}]
return sum(scores)
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
set(result[:2]) == {a, b} vergelijkt twee sets, en bij een set doet de
volgorde niet mee. Zo vind je de wedstrijd, of a nu als eerste of als tweede
staat. De lijst scores heeft één element, of geen als a en b niet tegen
elkaar speelden; sum maakt daar in beide gevallen het goede getal van.
Stap 5: cross_table(results, names)¶
def cross_table(results, names):
"""Geeft de kruistabel van het toernooi als lijst van lijsten."""
return [
[match_points(results, a, b) if a != b else "-" for b in names] for a in names
]
assert cross_table(results, names) == [
["-", 3, 1, 1],
[0, "-", 3, 3],
[1, 0, "-", 3],
[1, 0, 0, "-"],
]
assert cross_table([], []) == []
De buitenste comprehension maakt een rij per speler a, de binnenste een
waarde per speler b. De conditionele expressie kiest per vakje, en laat niets
weg: elke rij is even lang als names.
Stap 6: print_table(table, names)¶
def print_table(table, names):
"""Drukt de kruistabel af, met voor elke rij de naam van de speler."""
for name, row in zip(names, table):
print(name, row)
print_table(cross_table(results, names), names)
Anne ['-', 3, 1, 1]
Bram [0, '-', 3, 3]
Cas [1, 0, '-', 3]
Daan [1, 0, 0, '-']