ProjektBaut auf Katas: Listen auf
image: teaser.webp:25:50 image_alt: "Ein Strichcode mit den Ziffern 4 260111 020434 auf einem weißen Etikett, daneben das Struktogramm der Funktion check_digit mit einer Zählschleife von 0 bis 11." kind: projekt duration: 2 Doppelstunden languages: [ruby, python] curriculum: "Sek I: Algorithmisches Problemlösen (Eigenschaften und Darstellung von Algorithmen, Implementieren von Algorithmen), Information und Daten (Codierung: Strichcode); Oberstufe: Algorithmen und Softwareentwicklung (Struktogramm, Pseudocode)" topics: [fehlererkennung, codierung, darstellung] age: Sek I requires: [kata-lists] reference: [struktogramme]

Prüfziffern: erst planen, dann programmieren

Warum piept die Kasse, wenn jemand eine Ziffer eines Strichcodes falsch eintippt? Du rechnest eine Prüfziffer von Hand aus, liest Struktogramme und übersetzt sie in Code. Dann planst du selbst, mit Kommentaren im Code, bevor du programmierst, und findest heraus, welche Tippfehler die Kasse übersieht.

1. Die Geschichte

Samstagvormittag im Supermarkt. Auf einer Packung Nudeln ist der Strichcode zerknittert, und der Scanner piept nicht. Die Kassiererin tippt die dreizehn Ziffern unter den Strichen von Hand ein:

Dreizehn Ziffern sind viele, und beim Abtippen passiert schnell ein Fehler. Dann stünde auf dem Kassenbon eine andere Ware mit einem anderen Preis.

Vermutung 1Eine Ziffer falsch

Die Kassiererin tippt statt der dritten Ziffer eine andere ein, sonst stimmt alles. Was macht die Kasse?

Eine Ziffer falsch

2. Der Strichcode

Der Code heißt EAN-13 (European Article Number, heute GTIN-13); er steht auf fast jeder Ware im Laden. Die ersten zwölf Ziffern sagen, aus welchem Land die Nummer kommt, welche Firma sie vergeben hat und welche Ware es ist. Die dreizehnte ist keine Information über die Ware, sondern eine Prüfziffer: Sie wird aus den anderen zwölf berechnet, nach einer Regel, die die Organisation GS1 festgelegt hat:

  1. Multipliziere die zwölf Ziffern abwechselnd mit 1 und mit 3, mit 1 beginnend. Die Zahl, mit der eine Ziffer multipliziert wird, heißt ihr Gewicht.
  2. Addiere die Produkte.
  3. Die Prüfziffer ist, was bis zur nächsten durch 10 teilbaren Zahl fehlt. Ist die Summe schon durch 10 teilbar, ist sie 0.

Für die Ziffern 4 001234 56789 sieht das so aus:

Ziffer 4 0 0 1 2 3 4 5 6 7 8 9
Gewicht 1 3 1 3 1 3 1 3 1 3 1 3
Produkt 4 0 0 3 2 9 4 15 6 21 8 27

Die Summe ist 99; bis 100 fehlt 1, also ist der ganze Code 4 001234 567891.

Aufgabe 2Von Hand gerechnet

Berechne die Prüfziffer zu den ersten zwölf Ziffern 4 260111 02043, von Hand oder mit dem Taschenrechner.

Tipp

Schreib die zwölf Ziffern untereinander und daneben abwechselnd 1 und 3, mit 1 beginnend. Multipliziere jede Ziffer mit ihrem Gewicht.

Nächster Tipp

Die Produkte sind 4, 6, 6, 0, 1, 3, 1, 0, 2, 0, 4, 9.

Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.

Die Kasse rechnet genauso, mit den zwölf Ziffern, die eingetippt wurden. Passt das Ergebnis nicht zur dreizehnten Ziffer, piept sie.

Und warum merkt sie jede einzelne falsche Ziffer? Ändert sich eine Ziffer mit dem Gewicht 1 um 1 bis 9, ändert sich die Summe um 1 bis 9. Ändert sich eine mit dem Gewicht 3, ändert sich die Summe um 3, 6, 9, …, 27, aber nie um 10, 20 oder 30. In beiden Fällen ist danach eine andere Prüfziffer nötig.

3. Wie die Striche die Ziffern tragen

Der Scanner liest keine Ziffern, sondern hell und dunkel. Ein Strichcode ist in 95 gleich breite Streifen geteilt, die Module. Jedes Modul ist dunkel oder hell, also eine 1 oder eine 0; ein breiter Strich sind mehrere dunkle Module nebeneinander.

Der Strichcode der Nudeln, 4 260111 020434, auf einem weißen Etikett. Farbige Flächen hinter den Strichen zeigen die Teile: am linken und rechten Rand je drei Module »Rand« und in der Mitte fünf Module »Mitte«, orange, dazwischen links und rechts je »sechs Ziffern, je 7 Module«, blau. Die Striche von Rand und Mitte reichen weiter nach unten als die anderen. Darunter eine Klammer über den ganzen Code: 95 Module, 3 + 6 · 7 + 5 + 6 · 7 + 3.

Am Rand und in der Mitte stehen feste Muster: 101 links und rechts, 01010 in der Mitte. Ihre Striche reichen weiter nach unten als die anderen. An ihnen erkennt der Scanner, wo der Code anfängt, wo seine Mitte ist und wie breit ein Modul ist, egal wie weit die Packung vom Scanner entfernt ist. Dazwischen stehen links und rechts je sechs Ziffern mit je sieben Modulen.

Jede Ziffer besteht aus genau zwei dunklen und zwei hellen Abschnitten. Welches Muster zu welcher Ziffer gehört, legt GS1 in einer Tabelle fest, und zwar in drei Fassungen, L, G und R. So sieht die 4 in allen dreien aus:

Die Ziffer 4 in drei Fassungen, je sieben Kästchen, dunkel für 1 und hell für 0. L, links: 0100011, 3 dunkle Module, ungerade. G, links: 0011101, 4 dunkle Module, gerade. R, rechts: 1011100, 4 dunkle Module, gerade.

R ist L mit vertauschtem Hell und Dunkel, G ist R von hinten nach vorne gelesen. Darum genügt die Tabelle für L:

Ziffer 0 1 2 3 4 5 6 7 8 9
L 0001101 0011001 0010011 0111101 0100011 0110001 0101111 0111011 0110111 0001011

Rechts von der Mitte steht jede Ziffer in R. Links steht sie in L oder in G, und L hat immer eine ungerade Zahl dunkler Module, G eine gerade.

Aufgabe 3Eine Ziffer aus Strichen

Rechts von der Mitte steht eine Ziffer mit dem Muster 1000010. Welche Ziffer ist es?

Tipp

Rechts steht jede Ziffer in R, und R ist L mit vertauschtem Hell und Dunkel.

Nächster Tipp

Aus 1000010 wird mit vertauschten 0 und 1 0111101.

Zähl die Ziffern unter dem Code: Links und rechts von der Mitte stehen je sechs, die 4 ganz vorne hat keine eigenen Striche. Sie steckt in der Auswahl der Fassungen in der linken Hälfte. Bei den Nudeln stehen die Ziffern 2 6 0 1 1 1 in den Fassungen L G L L G G, und dieses Muster bedeutet die 4:

Erste Ziffer Linke Hälfte
0 L L L L L L
1 L L G L G G
2 L L G G L G
3 L L G G G L
4 L G L L G G
5 L G G L L G
6 L G G G L L
7 L G L G L G
8 L G L G G L
9 L G G L G L

Die erste Ziffer links steht dabei immer in L. Liest der Scanner einen Code von rechts nach links, etwa weil die Packung auf dem Kopf liegt, trifft er zuerst auf eine Ziffer mit einer geraden Zahl dunkler Module. Daran merkt er, dass er rückwärts liest, und dreht die Ziffern um.

Aufgabe 4Die versteckte erste Ziffer

Auf einer anderen Ware stehen die sechs Ziffern links von der Mitte in den Fassungen L G G L L G. Mit welcher Ziffer beginnt ihr Code?

Tipp

Die erste Ziffer hat keine eigenen Striche; sie steckt im Muster der Fassungen links.

Nächster Tipp

Such das Muster L G G L L G in der Tabelle der ersten Ziffern.

4. Ein Algorithmus, drei Schreibweisen

Die Regel in Worten ist kurz, aber ein Computer braucht es genauer: Wo fängt das Zählen an? Was heißt »bis zur nächsten durch 10 teilbaren Zahl«? Bevor du programmierst, schreibst du einen Algorithmus darum so auf, dass er genau ist und trotzdem in keiner Programmiersprache: als Pseudocode oder als Struktogramm. Beides steht im Handbuch unter Pseudocode und Struktogramme, mit einem Feld zum Ausprobieren.

Ein Struktogramm lesen

Ein Struktogramm liest man von oben nach unten. Jeder Kasten ist eine Anweisung; eine Schleife hat links einen Balken, und was rechts daneben steht, wiederholt sie, solange ihre Bedingung oben wahr ist. n mod 10 ist der Rest bei der Division durch 10, n div 10 das ganzzahlige Ergebnis.

mystery(n):
    s ← 0
    while n > 0:
        s ← s + n mod 10
        n ← n div 10
    return s
Vermutung 5Ein Struktogramm lesen

Was gibt mystery(4021) zurück? Geh das Struktogramm Zeile für Zeile durch und schreib dir die Werte von n und s auf.

Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.

n mod 10 ist die letzte Ziffer von n, und n div 10 streicht sie: Aus 4021 wird 402, dann 40, dann 4, dann 0. mystery addiert also alle Ziffern, das ist die Quersumme. Mit mod und div kommt man an die Ziffern einer Zahl, und mit mod sagt man, was übrig bleibt, wenn eine Zahl nicht aufgeht.

Die Prüfziffer als Struktogramm

So sieht die Regel von GS1 als Struktogramm aus. digits ist eine Liste der zwölf Ziffern; die erste hat den Index 0. weight(i) ist das Gewicht der Ziffer mit dem Index i, also 1 oder 3.

check_digit(digits):
    total ← 0
    for i from 0 to 11:
        total ← total + weight(i) * digits[i]
    return (10 - total mod 10) mod 10

total mod 10 ist der Rest, und 10 - total mod 10 ist, was bis zur nächsten durch 10 teilbaren Zahl fehlt.

Aufgabe 6Wozu das zweite mod?

Die Prüfziffer ist (10 - total mod 10) mod 10. Wann ändert das zweite mod 10 etwas am Ergebnis?

Wozu das zweite mod?

5. Vom Struktogramm zum Code

Einrichten

Lege im Workspace einen Ordner und darin eine Datei für die Funktionen an:

mkdir -p ~/check-digits
cd ~/check-digits
touch check_digits.rb

Öffne check_digits.rb im Editor. Ausprobieren kannst du deine Funktionen in irb, das die Datei vorher lädt:

irb -r ./check_digits.rb

Dort tippst du einen Aufruf wie weight(3) und siehst, was er zurückgibt. Nach einer Änderung an der Datei beendest du irb mit StrgD und startest es neu.

Lege im Workspace einen Ordner und darin eine Datei für die Funktionen an:

mkdir -p ~/check-digits
cd ~/check-digits
touch check_digits.py

Öffne check_digits.py im Editor. Ausprobieren kannst du deine Funktionen in Python selbst, das die Datei vorher ausführt:

python3 -i check_digits.py

Dort tippst du einen Aufruf wie weight(3) und siehst, was er zurückgibt. Nach einer Änderung an der Datei beendest du Python mit StrgD und startest es neu.

Das Gewicht

Die Ziffern mit geradem Index (0, 2, 4, …) haben das Gewicht 1, die mit ungeradem Index das Gewicht 3.

Jetzt bist du dran: Schreib die Funktion weight(index), die für einen Index das Gewicht zurückgibt.
Tipp

Ob eine Zahl gerade ist, sagt der Rest bei der Division durch 2: index % 2 ist 0 oder 1. Ruby hat dafür auch index.even?.

Nächster Tipp

Als Struktogramm ist es eine Verzweigung mit zwei Spalten, in jeder ein return:

weight(index):
    if index mod 2 == 0:
        return 1
    else:
        return 3
Lösung anzeigen
def weight(index)
  if index.even?
    1
  else
    3
  end
end
Tipp

Ob eine Zahl gerade ist, sagt der Rest bei der Division durch 2: index % 2 ist 0 oder 1.

Nächster Tipp

Als Struktogramm ist es eine Verzweigung mit zwei Spalten, in jeder ein return:

weight(index):
    if index mod 2 == 0:
        return 1
    else:
        return 3
Lösung anzeigen
def weight(index):
    if index % 2 == 0:
        return 1
    else:
        return 3
Aufgabe 7Das Gewicht

Schreib in check-digits/check_digits.rb die Funktion weight(index): Sie gibt für einen geraden Index 1 zurück und für einen ungeraden 3. Die Prüfung ruft weight(0), weight(1), weight(4) und weight(11) auf.

Aufgabe 7Das Gewicht

Schreib in check-digits/check_digits.py die Funktion weight(index): Sie gibt für einen geraden Index 1 zurück und für einen ungeraden 3. Die Prüfung ruft weight(0), weight(1), weight(4) und weight(11) auf.

Die Prüfziffer

Jetzt bist du dran: Übersetze das Struktogramm von check_digit von oben in Code, Kasten für Kasten, unter weight in dieselbe Datei.
Tipp

Wie die Bausteine in Ruby heißen, steht im Handbuch unter Vom Pseudocode zum Code: ← ist =, mod ist %, und for i from 0 to 11 ist (0..11).each do |i|.

Lösung anzeigen
def check_digit(digits)
  total = 0
  (0..11).each do |i|
    total = total + weight(i) * digits[i]
  end
  (10 - total % 10) % 10
end
Ausprobieren: Ruf in irb check_digit([4, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) auf; heraus kommt die 1 aus der Tabelle oben. Nimm dann das letzte % 10 weg, starte neu und ruf check_digit([4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]) auf. Achte darauf, ob das Ergebnis noch eine Ziffer ist, und setz das % 10 danach wieder ein.
Tipp

Wie die Bausteine in Python heißen, steht im Handbuch unter Vom Pseudocode zum Code: ← ist =, mod ist %, und for i from 0 to 11 ist for i in range(0, 12), denn range hört eins vor dem Ende auf.

Lösung anzeigen
def check_digit(digits):
    total = 0
    for i in range(0, 12):
        total = total + weight(i) * digits[i]
    return (10 - total % 10) % 10
Ausprobieren: Ruf in Python check_digit([4, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) auf; heraus kommt die 1 aus der Tabelle oben. Nimm dann das letzte % 10 weg, starte neu und ruf check_digit([4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]) auf. Achte darauf, ob das Ergebnis noch eine Ziffer ist, und setz das % 10 danach wieder ein.
Aufgabe 8Die Prüfziffer

Schreib check_digit(digits) nach dem Struktogramm. digits ist eine Liste von zwölf Zahlen. Die Prüfung ruft die Funktion mit den Ziffern von 4 260111 02043 auf, mit zwölf Nullen und mit [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2].

Aufgabe 8Die Prüfziffer

Schreib check_digit(digits) nach dem Struktogramm. digits ist eine Liste von zwölf Zahlen. Die Prüfung ruft die Funktion mit den Ziffern von 4 260111 02043 auf, mit zwölf Nullen und mit [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2].

6. Erst planen, dann programmieren

Bisher stand der Plan schon da, und du hast ihn übersetzt. Ab jetzt planst du selbst, und zwar gleich dort, wo der Code hinkommt: Du legst die Funktion an und schreibst als Kommentare hinein, was sie Schritt für Schritt tun soll, noch ohne eine Zeile Code. Dabei klärst du drei Fragen: Was bekommt die Funktion, und was gibt sie zurück? Welche Fälle gibt es, auch solche, die nicht vorkommen sollten? Und in welcher Reihenfolge geschieht was?

Dann ersetzt du einen Kommentar nach dem anderen durch Code und probierst nach jedem Schritt aus. Die Kommentare dürfen stehen bleiben: Wer den Code später liest, sieht so, wofür jeder Teil da ist. Genauso planen viele, die beruflich programmieren; der Plan ist Pseudocode, nur eben in der Datei.

Ist der Code gültig?

Die Kasse bekommt, was die Kassiererin getippt hat, als Text, und will wissen: Ist das ein gültiger Code? Er ist es, wenn er aus genau 13 Ziffern besteht und die letzte die Prüfziffer der ersten zwölf ist.

Jetzt bist du dran: Leg die Funktion valid_ean?(code) an und schreib zuerst deinen Plan als Kommentare hinein, dann den Code dazu. Sie gibt true oder false zurück und benutzt check_digit.
Tipp

Was macht einen Code sicher ungültig, bevor man rechnet? Wenn er zu kurz oder zu lang ist, und wenn ein Zeichen keine Ziffer ist. Prüf das zuerst und gib dann gleich false zurück.

Nächster Tipp

Ein Plan, dem noch der Code fehlt:

def valid_ean?(code)
  # nicht genau 13 Zeichen: false
  # ein Zeichen ist keine Ziffer: false
  # die 13 Zeichen als Zahlen
  # gültig, wenn die Prüfziffer der ersten zwölf gleich der dreizehnten ist
end
Nächster Tipp

Für die Einzelheiten in Ruby: code.length ist die Zahl der Zeichen, code.chars die Liste der Zeichen, ('0'..'9').include?(c) sagt, ob c eine Ziffer ist, c.to_i macht aus '7' die Zahl 7, und digits[0..11] sind die ersten zwölf Elemente einer Liste.

Lösung anzeigen
def valid_ean?(code)
  # nicht genau 13 Zeichen: false
  return false unless code.length == 13
  # ein Zeichen ist keine Ziffer: false
  return false unless code.chars.all? { |c| ('0'..'9').include?(c) }

  # die 13 Zeichen als Zahlen
  digits = code.chars.map(&:to_i)
  # gültig, wenn die Prüfziffer der ersten zwölf gleich der dreizehnten ist
  check_digit(digits[0..11]) == digits[12]
end
Jetzt bist du dran: Leg die Funktion is_valid_ean(code) an und schreib zuerst deinen Plan als Kommentare hinein, dann den Code dazu. Sie gibt True oder False zurück und benutzt check_digit.
Tipp

Was macht einen Code sicher ungültig, bevor man rechnet? Wenn er zu kurz oder zu lang ist, und wenn ein Zeichen keine Ziffer ist. Prüf das zuerst und gib dann gleich False zurück.

Nächster Tipp

Ein Plan, dem noch der Code fehlt. Damit Python die Funktion schon jetzt annimmt, steht am Ende pass, das nichts tut:

def is_valid_ean(code):
    # nicht genau 13 Zeichen: False
    # ein Zeichen ist keine Ziffer: False
    # die 13 Zeichen als Zahlen
    # gültig, wenn die Prüfziffer der ersten zwölf gleich der dreizehnten ist
    pass
Nächster Tipp

Für die Einzelheiten in Python: len(code) ist die Zahl der Zeichen, c in '0123456789' sagt, ob c eine Ziffer ist, int(c) macht aus '7' die Zahl 7, und digits[0:12] sind die ersten zwölf Elemente einer Liste.

Lösung anzeigen
def is_valid_ean(code):
    # nicht genau 13 Zeichen: False
    if len(code) != 13:
        return False
    # ein Zeichen ist keine Ziffer: False
    if not all(c in '0123456789' for c in code):
        return False
    # die 13 Zeichen als Zahlen
    digits = [int(c) for c in code]
    # gültig, wenn die Prüfziffer der ersten zwölf gleich der dreizehnten ist
    return check_digit(digits[0:12]) == digits[12]
Aufgabe 9Ist der Code gültig?

Schreib valid_ean?(code): Sie bekommt einen Code als String und gibt true zurück, wenn er aus genau 13 Ziffern besteht und die letzte die richtige Prüfziffer ist, sonst false. Die Prüfung ruft sie mit gültigen und ungültigen Codes auf, auch mit zu kurzen, zu langen und solchen mit Buchstaben.

Aufgabe 9Ist der Code gültig?

Schreib is_valid_ean(code): Sie bekommt einen Code als String und gibt True zurück, wenn er aus genau 13 Ziffern besteht und die letzte die richtige Prüfziffer ist, sonst False. Die Prüfung ruft sie mit gültigen und ungültigen Codes auf, auch mit zu kurzen, zu langen und solchen mit Buchstaben.

Bücher: die ISBN

Bücher tragen eine ISBN (International Standard Book Number). Bis 2007 hatte sie zehn Zeichen, etwa 3-499-12304-5; die Bindestriche trennen nur Gruppen und zählen nicht mit. Ihre Prüfung geht anders als beim Strichcode:

  1. Multipliziere die zehn Ziffern mit den Gewichten 10, 9, 8, … bis 1: die erste mit 10, die letzte mit 1.
  2. Addiere die Produkte.
  3. Die ISBN ist gültig, wenn die Summe durch 11 teilbar ist.

Die letzte Ziffer ist also so gewählt, dass die Summe aufgeht. Manchmal müsste sie dafür 10 sein, und das ist keine Ziffer: Dann steht dort ein X, wie die römische Zehn. Ein X gibt es nur an dieser Stelle.

Für 3-499-12304-5 ist die Summe 3 · 10 + 4 · 9 + 9 · 8 + 9 · 7 + 1 · 6 + 2 · 5 + 3 · 4 + 0 · 3 + 4 · 2 + 5 · 1 = 242 = 22 · 11; die ISBN ist gültig.

Diesmal steht kein Plan auf der Seite. Leg valid_isbn?(isbn) an und schreib deinen Plan als Kommentare hinein, bevor du Code schreibst: Was geschieht mit den Bindestrichen, was mit einem X, was mit einem Zeichen, das weder Ziffer noch X ist?

Diesmal steht kein Plan auf der Seite. Leg is_valid_isbn(isbn) an und schreib deinen Plan als Kommentare hinein, bevor du Code schreibst: Was geschieht mit den Bindestrichen, was mit einem X, was mit einem Zeichen, das weder Ziffer noch X ist?

Aufgabe 10Dein Plan für die ISBN

Kopier die Kommentare deines Plans für valid_isbn? hierher, bevor du den Code dazu schreibst. Deine Lehrkraft sieht sie.

Mindestens 15 Wörter. Nur du und deine Lehrkraft können die Antwort lesen.
Aufgabe 10Dein Plan für die ISBN

Kopier die Kommentare deines Plans für is_valid_isbn hierher, bevor du den Code dazu schreibst. Deine Lehrkraft sieht sie.

Mindestens 15 Wörter. Nur du und deine Lehrkraft können die Antwort lesen.
Aufgabe 11Bücher prüfen

Schreib valid_isbn?(isbn) nach deinem Plan. Die Prüfung ruft sie mit ISBNs mit und ohne Bindestriche auf, mit einem X am Ende, mit einem X an der falschen Stelle und mit falschen Ziffern.

Aufgabe 11Bücher prüfen

Schreib is_valid_isbn(isbn) nach deinem Plan. Die Prüfung ruft sie mit ISBNs mit und ohne Bindestriche auf, mit einem X am Ende, mit einem X an der falschen Stelle und mit falschen Ziffern.

7. Was die Prüfziffer findet

Ein häufiger Fehler beim Abtippen ist nicht die falsche Ziffer, sondern der Zahlendreher: zwei benachbarte Ziffern in der falschen Reihenfolge.

Vermutung 12Zahlendreher

Die Kassiererin vertauscht zwei benachbarte Ziffern, die verschieden sind, etwa 42 statt 24. Merkt die Kasse das?

Zahlendreher

Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.

Ausrechnen kannst du es mit einem kleinen Programm, das alle Möglichkeiten ausprobiert. Für zwei verschiedene Ziffern a und b gibt es 10 · 9 = 90 Paare. Es genügt, jedes Paar an den Anfang eines Codes zu stellen, den Rest mit Nullen zu füllen und die Prüfziffer anzuhängen; dann ist der Code gültig. Vertauscht man nun die ersten beiden Ziffern: Ist der Code danach immer noch gültig, hat die Kasse den Zahlendreher nicht bemerkt.

Jetzt bist du dran: Schreib in eine neue Datei swaps.rb ein Programm, das die 90 Paare durchgeht und zählt, wie viele Zahlendreher valid_ean? nicht bemerkt. Die erste Zeile require_relative 'check_digits' holt deine Funktionen dazu.
Tipp

Zwei Schleifen ineinander gehen alle Paare durch: außen a von 0 bis 9, innen b von 0 bis 9; ist a == b, geht es mit dem nächsten weiter (next).

Nächster Tipp

Für ein Paar: digits = [a, b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dann ist code = (digits + [check_digit(digits)]).join ein gültiger Code. code[1] + code[0] + code[2..] ist derselbe Code mit vertauschten ersten Ziffern.

Lösung anzeigen
require_relative 'check_digits'

missed = 0
(0..9).each do |a|
  (0..9).each do |b|
    next if a == b

    digits = [a, b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    code = (digits + [check_digit(digits)]).join
    swapped = code[1] + code[0] + code[2..]
    missed = missed + 1 if valid_ean?(swapped)
  end
end
puts "Unbemerkt: #{missed} von 90"
ruby swaps.rb
Jetzt bist du dran: Schreib in eine neue Datei swaps.py ein Programm, das die 90 Paare durchgeht und zählt, wie viele Zahlendreher is_valid_ean nicht bemerkt. Die erste Zeile from check_digits import check_digit, is_valid_ean holt deine Funktionen dazu.
Tipp

Zwei Schleifen ineinander gehen alle Paare durch: außen a von 0 bis 9, innen b von 0 bis 9; ist a == b, geht es mit dem nächsten weiter (continue).

Nächster Tipp

Für ein Paar: digits = [a, b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dann ist code = ''.join(str(d) for d in digits + [check_digit(digits)]) ein gültiger Code. code[1] + code[0] + code[2:] ist derselbe Code mit vertauschten ersten Ziffern.

Lösung anzeigen
from check_digits import check_digit, is_valid_ean

missed = 0
for a in range(0, 10):
    for b in range(0, 10):
        if a == b:
            continue
        digits = [a, b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        code = ''.join(str(d) for d in digits + [check_digit(digits)])
        swapped = code[1] + code[0] + code[2:]
        if is_valid_ean(swapped):
            missed = missed + 1
print(f"Unbemerkt: {missed} von 90")
python3 swaps.py
Aufgabe 13Wie viele merkt sie nicht?

Wie viele der 90 Zahlendreher aus zwei verschiedenen Ziffern merkt valid_ean? nicht?

Aufgabe 13Wie viele merkt sie nicht?

Wie viele der 90 Zahlendreher aus zwei verschiedenen Ziffern merkt is_valid_ean nicht?

Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.

Unbemerkt bleiben genau die Paare, deren Ziffern sich um 5 unterscheiden, etwa 05 und 50. Beim Vertauschen tauschen die beiden Ziffern ihre Gewichte 1 und 3; die Summe ändert sich dadurch um das Doppelte ihres Unterschieds. Ist der Unterschied 5, ändert sie sich um 10, und die Prüfziffer bleibt dieselbe.

Vermutung 14Und bei Büchern?Extra

Wie viele Zahlendreher aus zwei verschiedenen Ziffern merkt die ISBN nicht?

Und bei Büchern?

8. Wie geht es weiter? Extra

Ein Extra für Schnelle. Wer es auslässt, springt zu Zum Nachschlagen.

  • Bücher heute: Seit 2007 hat die ISBN dreizehn Ziffern, beginnt mit 978 oder 979 und ist selbst ein EAN-13-Code: Auf der Rückseite eines Buchs steht sie als Strichcode, mit derselben Prüfziffer wie auf den Nudeln. Probier deine Funktion für Strichcodes an einem Buch aus deinem Regal aus.
  • Mehr als Fehler finden: Ein QR-Code findet Fehler nicht nur, er repariert sie. Er trägt so viel zusätzliche Information, dass ein Handy ihn auch dann noch liest, wenn ein Teil verdeckt oder verschmutzt ist, je nach Stufe der Fehlerkorrektur bis zu 30 Prozent. Kleb ein Stück Papier über eine Ecke eines QR-Codes und scann ihn.
  • Kontonummern: Auch eine IBAN hat Prüfziffern, die dritte und vierte Stelle; gerechnet wird mit dem Rest bei der Division durch 97.

9. Zum Nachschlagen