Extra

Deze pagina bevat uitvoerbare code.

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, '-']