Basis

Deze pagina bevat uitvoerbare code.

Dit zijn de uitwerkingen van beide delen van de basis: De nacht van het nijlpaard en De uitslag van de schoolrun.

De nacht van het nijlpaard

Opdracht: De nacht van het nijlpaard

Stap 1: far_enough(a, b, distance)

def far_enough(a, b, distance):
    """Geeft True als plaats b minstens distance verder ligt dan plaats a."""
    return b - a >= distance


assert far_enough(1, 3, 2) == True
assert far_enough(2, 3, 2) == False
assert far_enough(3, 3, 1) == False
assert far_enough(5, 10, 5) == True

Stap 2: drop_too_close(place, places, distance)

Zodra één plaats ver genoeg ligt, stopt de recursie: de plaatsen daarna liggen nog verder weg.

def drop_too_close(place, places, distance):
    """Geeft places zonder de plaatsen aan het begin die te dicht bij place liggen."""
    if places == []:  # basisgeval
        return []
    elif far_enough(place, places[0], distance):  # basisgeval: ver genoeg
        return places
    else:  # recursief geval: de eerste plaats ligt te dichtbij
        return drop_too_close(place, places[1:], distance)


assert drop_too_close(1, [3, 7], 2) == [3, 7]
assert drop_too_close(3, [3, 5, 8], 4) == [8]
assert drop_too_close(1, [3, 5, 10, 12], 4) == [5, 10, 12]
assert drop_too_close(5, [6, 7], 3) == []
assert drop_too_close(5, [], 2) == []

Stap 3: hippo_dinner(distance, places)

def hippo_dinner(distance, places):
    """Geeft hoeveel nijlpaarden er hoogstens mee-eten op de plaatsen in places."""
    if places == []:  # basisgeval
        return 0

    first = places[0]
    rest = places[1:]

    use_it = 1 + hippo_dinner(distance, drop_too_close(first, rest, distance))
    lose_it = hippo_dinner(distance, rest)
    return max(use_it, lose_it)


assert hippo_dinner(1, [2, 3, 3]) == 2
assert hippo_dinner(2, [1, 3, 7]) == 3
assert hippo_dinner(4, [1, 3, 5, 10, 12]) == 3
assert hippo_dinner(3, [4]) == 1
assert hippo_dinner(3, []) == 0

De uitslag van de schoolrun

Opdracht: De uitslag van de schoolrun

De gegeven code uit de opgave:

RESULTS = [
    ["Noor", 17, 754],
    ["Sem", 19, 698],
    ["Lotte", 18, 698],
    ["Yara", 16, 812],
    ["Finn", 21, 745],
]

Stap 4: fastest(results)

def fastest(results):
    """Geeft de naam van de deelnemer met de kleinste tijd; results is niet leeg."""
    return min(results, key=lambda r: r[2])[0]


assert fastest(RESULTS) == "Sem"
assert fastest([["Ali", 20, 600]]) == "Ali"

Stap 5: ranking(results)

De sleutel [r[2], r[0]] vergelijkt eerst de tijd en bij een gelijke tijd de naam.

def ranking(results):
    """Geeft de namen van snel naar langzaam; bij gelijke tijd op alfabet."""
    return [r[0] for r in sorted(results, key=lambda r: [r[2], r[0]])]


assert ranking(RESULTS) == ["Lotte", "Sem", "Finn", "Noor", "Yara"]
assert ranking([["Bo", 30, 700], ["Ad", 25, 700]]) == ["Ad", "Bo"]
assert ranking([]) == []

Stap 6: select(results, test)

def select(results, test):
    """Geeft de deelnemers uit results waarvoor test True teruggeeft."""
    return [r for r in results if test(r)]


assert select(RESULTS, lambda r: r[1] < 18) == [["Noor", 17, 754], ["Yara", 16, 812]]
assert select(RESULTS, lambda r: r[2] < 700) == [["Sem", 19, 698], ["Lotte", 18, 698]]
assert select(RESULTS, lambda r: r[1] > 30) == []

Stap 7: winner(results, test)

def winner(results, test):
    """Geeft de naam van de snelste deelnemer waarvoor test True teruggeeft."""
    return fastest(select(results, test))


assert winner(RESULTS, lambda r: r[1] < 18) == "Noor"
assert winner(RESULTS, lambda r: r[1] >= 18) == "Sem"
assert winner(RESULTS, lambda r: r[0][0] == "Y") == "Yara"

Stap 8: een jeugdpodium

Eén mogelijke uitwerking. Deze aanpak gebruikt de bestaande selectie en ranglijst, en neemt daarna de eerste drie namen. De leeftijdsgrens wordt bij de selectie gecontroleerd.

def youth_podium(results, age_limit):
    """Geeft maximaal drie namen onder age_limit, op tijd en daarna op alfabet."""
    return ranking(select(results, lambda participant: participant[1] < age_limit))[:3]


assert youth_podium(RESULTS, 18) == ["Noor", "Yara"]
assert youth_podium(RESULTS, 16) == []
assert youth_podium([], 18) == []
assert youth_podium([["Bo", 17, 700]], 18) == ["Bo"]
assert youth_podium([["Bo", 18, 600], ["Ad", 17, 700]], 18) == ["Ad"]
assert youth_podium(
    [["Daan", 17, 700], ["Cato", 16, 700], ["Bo", 17, 600], ["Ad", 15, 500]], 18
) == ["Ad", "Bo", "Cato"]

Opdracht 1: dezelfde regel bij gelijke tijden

  1. fastest kiest de snelste naam; ranking ordent alle namen; select filtert deelnemers; winner kiest de snelste uit de gefilterde deelnemers.

  2. winner geeft test door aan select, dat test per deelnemer aanroept. Daarna roept winner fastest aan. fastest geeft een lambda aan min; ranking geeft een lambda aan sorted. Deze functies roepen de lambda aan om de vergelijkingssleutel te krijgen.

  3. Verander in fastest de sleutel van r[2] naar [r[2], r[0]]. Dat vergelijkt eerst tijd en dan naam. winner gebruikt fastest na select en krijgt de nieuwe regel dus zonder eigen wijziging. ranking heeft die sleutel al; select blijft dezelfde deelnemers in dezelfde volgorde doorgeven.

  4. Bij RESULTS verandert fastest van Sem naar Lotte, en de volwassen winnaar ook. De jeugdwinnaar blijft Noor. Bij Bo en Ad verandert zowel fastest als de jeugdwinnaar van Bo naar Ad; ranking blijft Ad, Bo en jeugdselectie blijft Bo, Ad. Zonder gelijke tijden verandert niets. Alleen de bestaande assertions fastest(RESULTS) en de volwassen winner(RESULTS, ...) moeten Sem door Lotte vervangen. De overige blijven geldig, ook alle assertions voor ranking en select.

TIED = [["Bo", 16, 700], ["Ad", 17, 700]]
assert fastest(TIED) == "Bo"
assert winner(TIED, lambda r: r[1] < 18) == "Bo"


def fastest(results):
    """Geeft de snelste naam; bij gelijke tijd op alfabet; results is niet leeg."""
    return min(results, key=lambda r: [r[2], r[0]])[0]


assert fastest(TIED) == "Ad"
assert winner(TIED, lambda r: r[1] < 18) == "Ad"
assert ranking(TIED) == ["Ad", "Bo"]
assert select(TIED, lambda r: r[1] < 18) == TIED
assert fastest(RESULTS) == "Lotte"
assert winner(RESULTS, lambda r: r[1] >= 18) == "Lotte"
assert winner(RESULTS, lambda r: r[1] < 18) == "Noor"
assert ranking(RESULTS) == ["Lotte", "Sem", "Finn", "Noor", "Yara"]
assert select(RESULTS, lambda r: r[2] < 700) == [["Sem", 19, 698], ["Lotte", 18, 698]]
assert fastest([["Ali", 20, 600], ["Bo", 16, 700]]) == "Ali"