Basis¶
Het burgerservicenummer¶
Een systeem dat een burgerservicenummer aanneemt, moet een typefout kunnen herkennen voordat er iets wordt opgeslagen of doorgestuurd. Dat kan zonder ergens iets op te zoeken, want de controle zit in het nummer zelf ingebouwd.
De elfproef¶
Een BSN heeft negen cijfers. Vermenigvuldig elk cijfer met het gewicht van zijn positie en tel de uitkomsten op. Is die som deelbaar door elf, dan is het nummer geldig.
Positie |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
|---|---|---|---|---|---|---|---|---|---|
Gewicht |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
-1 |
Let op het laatste gewicht: dat is min één.
Voor 999000032:
9×9 + 9×8 + 9×7 + 0×6 + 0×5 + 0×4 + 0×3 + 3×2 + 2×-1
81 + 72 + 63 + 0 + 0 + 0 + 0 + 6 + -2 = 220
220 = 20 × 11, dus dit nummer is geldig.
Verwissel de laatste twee cijfers en je krijgt 999000023, met som 217. Dat is
niet deelbaar door elf, dus de proef ziet de verwisseling.
Pak je eigen BSN erbij en reken het na. Verander daarna één cijfer en reken opnieuw: de som klopt dan niet meer.
Wat je gaat maken¶
Zes functies, elk met één taak. De latere gebruiken de eerdere.
Stap |
Functie |
Doet |
|---|---|---|
1 |
|
kijken of één teken een cijfer is |
2 |
|
één cijfer uit het nummer halen |
3 |
|
de negen cijfers maal hun gewicht optellen |
4 |
|
controleren of het nummer de goede vorm heeft |
5 |
|
vorm en elfproef combineren tot één oordeel |
6 |
|
dat oordeel omzetten in een leesbaar antwoord |
Stap 1: is_digit(c)¶
Geeft True als het teken c een cijfer is.
Python heeft hiervoor een kant en klare verzameling. Zet bovenaan je notebook:
from string import digits
digits is de string "0123456789", en met de operator in vraag je of een
teken daarin voorkomt.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
# jouw oplossing
assert is_digit("7") is True
assert is_digit("0") is True
assert is_digit("x") is False
Stap 2: digit_at(bsn, i)¶
Geeft het cijfer op positie i terug als getal. De eerste positie is 0.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
Hint
bsn[i] geeft een string van één teken. Met int() maak je daar een getal van.
# jouw oplossing
assert digit_at("999000032", 0) == 9
assert digit_at("999000032", 7) == 3
assert digit_at("999000032", 8) == 2
Stap 3: weighted_sum(bsn)¶
Geeft de som van de negen cijfers, elk vermenigvuldigd met het gewicht van zijn positie.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
|
|
Hint
Je hebt nog geen lussen gehad, dus schrijf de negen termen uit. Gebruik
digit_at uit stap 2, dan hoef je nergens twee keer hetzelfde te doen.
# jouw oplossing
assert weighted_sum("999000032") == 220
assert weighted_sum("999000023") == 217
assert weighted_sum("123456789") == 147
Stap 4: has_nine_digits(bsn)¶
Geeft True als bsn uit precies negen tekens bestaat en die allemaal cijfers
zijn.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
|
|
Hint
Eerst de lengte met len(), en daarna negen keer is_digit uit stap 1, met
and aan elkaar geregen.
Ja, dat is negen keer bijna hetzelfde. Onthoud dat gevoel: volgende week ben je ervan af.
# jouw oplossing
assert has_nine_digits("999000032") is True
assert has_nine_digits("99900003") is False
assert has_nine_digits("99900003x") is False
Stap 5: is_valid(bsn)¶
Geeft True als bsn negen cijfers heeft en de gewogen som deelbaar is door
elf.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
|
|
|
|
|
|
Hint
Roep hier je eerdere functies aan. Zet de controle op negen cijfers vooraan: als
die faalt mag weighted_sum niet meer aan de beurt komen, want die rekent op
negen posities.
# jouw oplossing
assert is_valid("999000032") is True
assert is_valid("999999990") is True
assert is_valid("999000023") is False
assert is_valid("123456789") is False
assert is_valid("99900003") is False
Stap 6: check(bsn)¶
Geeft een string terug die zegt wat er aan de hand is.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
|
|
Dit is de functie die een echt systeem zou aanroepen. Een gebruiker die een cijfer vergeet, wil iets anders horen dan een gebruiker die er twee heeft omgedraaid.
# jouw oplossing
assert check("999000032") == "geldig"
assert check("99900003") == "geen negen cijfers"
assert check("999000023") == "mislukt op de elfproef"
Uitproberen¶
Haal je eigen nummer door check heen, en daarna een versie met twee cijfers
omgedraaid. Je hebt nu in zes kleine stappen gebouwd wat elk aanmeldformulier in
Nederland doet.
Laat het er niet in staan
Haal je eigen nummer eruit voordat je dit notebook inlevert of deelt. Een BSN hoort niet in code die je weggeeft, ook niet in een oefening.
Tot slot¶
Twee keer heb je in deze opgave negen dingen uitgeschreven die bijna hetzelfde
zijn: negen termen in weighted_sum en negen aanroepen in has_nine_digits.
Dat kan, omdat een BSN altijd negen cijfers lang is.
Een IBAN is dat niet. Een Nederlandse heeft achttien tekens, een Maltese eenendertig. Dezelfde aanpak zou daar functies van eenendertig regels opleveren, en voor elk land een andere.
Volgende week zie je hoe je dat in een paar regels schrijft, ongeacht de lengte.
Functies schrijven¶
Leerdoel: Schrijven van simpele functies
Deze opgave bestaat uit het maken van verschillende functies. Vergeet niet elke functie te testen met assertions en vergeet de docstrings niet.
Opdracht 1¶
Schrijf de functie tpl(x) die een getal als argument accepteert en drie keer de waarde van dat argument teruggeeft.
In : tpl(4)
Out: 12
In: tpl("hoi")
Out: "hoihoihoi"
# jouw oplossing
Opdracht 2¶
a. Schrijf de functie min_two(a, b) die twee getallen als argument accepteert en de kleinste waarde teruggeeft.
b. Schrijf de functie min_three(a, b, c) die drie getallen als argument accepteert en de kleinste waarde teruggeeft.
# jouw oplossing
Opdracht 3¶
Schrijf de functie absolute(x, y) die twee getallen accepteert en de afstand berekent tussen de twee getallen.
In : absolute(3, 10)
Out: 7
In: absolute(-3, 10)
Out: 13
# jouw oplossing