Basis

Deze pagina bevat uitvoerbare code.

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

is_digit

kijken of één teken een cijfer is

2

digit_at

één cijfer uit het nummer halen

3

weighted_sum

de negen cijfers maal hun gewicht optellen

4

has_nine_digits

controleren of het nummer de goede vorm heeft

5

is_valid

vorm en elfproef combineren tot één oordeel

6

check

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

is_digit("7")

True

is_digit("x")

False

# 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

digit_at("999000032", 0)

9

digit_at("999000032", 7)

3

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

weighted_sum("999000032")

220

weighted_sum("999000023")

217

weighted_sum("123456789")

147

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

has_nine_digits("999000032")

True

has_nine_digits("99900003")

False

has_nine_digits("99900003x")

False

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

is_valid("999000032")

True

is_valid("999999990")

True

is_valid("999000023")

False

is_valid("123456789")

False

is_valid("99900003")

False

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

check("999000032")

"geldig"

check("99900003")

"geen negen cijfers"

check("999000023")

"mislukt op de elfproef"

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