Learning Python

Learning Python II

Die nächste Aufgabe bei pythonfordesigners.com von Roberto Arista ist ein Schachbrettmuster.

PythonForDesigners screenshot
Screenshot of pythonfordesigners.com/how-to-make-choices/#workbook

Mit dieser zweiten Aufgabe hatte ich mich zuerst alleine gequält, bis ich irgendwann verzweifelt einen Freund angerufen habe, der mir sehr geduldig ein paar Kernpunkte erklärt hat. Damit konnte ich die Aufgabe lösen. Um das ganze nochmal zu rekapitulieren (und dabei zu lernen) versuche ich im Folgenden, Zeile für Zeile durch den Code zu navigieren und in meinen eigenen Worten zu beschreiben, was gerade passiert.

newPage(200, 200)    
length = 20
amount_columns = 0


while length * amount_columns < 200:
・・・・pos_x = length * amount_columns
・・・・amount_squares = 0
・・・・if amount_columns % 2:    #ungerade Spaltenzahl
・・・・・・・・while length * amount_squares < 200:
・・・・・・・・・・・・pos_y = 200 - length * (amount_squares + 1)
・・・・・・・・・・・・if amount_squares % 2:    #ungerade
・・・・・・・・・・・・・・・・fill(0) #schwarz
・・・・・・・・・・・・else:    #gerade
・・・・・・・・・・・・・・・・fill(1) #weiss
・・・・・・・・・・・・rect(pos_x, pos_y, length, length) 
・・・・・・・・・・・・amount_squares += 1

・・・・else: #gerade Spaltenzahl
・・・・・・・・while length * amount_squares < 200:
・・・・・・・・・・・・pos_y = 200 - length * (amount_squares + 1)
・・・・・・・・・・・・if amount_squares % 2:    #gerade
・・・・・・・・・・・・・・・・fill(1)
・・・・・・・・・・・・else:    #gerade
・・・・・・・・・・・・・・・・fill(0)
・・・・・・・・・・・・rect(pos_x, pos_y, length, length) 
・・・・・・・・・・・・amount_squares += 1

・・・・amount_columns += 1

Ich erzeuge eine neue Seite mit einer Größe von 200 × 200.
Dann setze ich eine Variable mit einer Kantenlänge 20, die ich später manuell verändern kann.
Eine weitere Variable setzt die Anzahl der Spalten auf 0.

Eine while-Schleife. Wenn das Produkt aus Kantenlänge (20) und Anzahl der Spalten (gerade noch 0) kleiner als 200 ist, dann …
Ja, das ist so. Wir liegen gerande bei 20 × 0, also 0, und das ist kleiner als 200.
Jetzt wird die x-Position des ersten Rechtecks (die sich dann zu einer Spalte stapeln sollen) berechnet, also Kantenlänge × Spaltenanzahl, das ergibt 0. Das bedeutet, das erste Rechteck „klebt“ sozusagen an der linken Seite. Die Variable der Anzahl der Rechtecke wird auf 0 gesetzt, es ist noch kein Rechteck gezeichnet.

Nun eine if-Schleife. Wenn die Anzahl der Spalten ungerade ist … das wird durch einen Modulo ermittelt. (Ein Modulo berechnet den Rest einer Division; wenn Modulo 0 ist, dann ist die Zahl gerade.) Da wir eine Spaltenzahl von 0 haben, und diese einen Modulo von 0 hat, rutschen wir direkt in die else-Schleife. Diese beinhaltet eine neue while-Schleife, die zuerst die Anzahl der Recktecke prüft. Ist das Produkt aus Kantenlänge und Anzahl der Rechtecke kleiner als 200 — ja, das ist der Fall, wir sind gerade bei 20 × 0, also 0 — dann:
Die Position von y (der vertikale Startpunkt des ersten Rechtecks) soll so berechnet werden: Anzahl der Rechtecke + 1, das dann mit der Kantenlänge multiplizieren und von 200 abziehen. Also 1 × 20 = 20, und 200 – 20 = 180. Das ist deshalb so „umständlich“, weil das Schachbrettmuster von oben links beginnen soll. Der Nullpunkt deines Rechtecks ist übrigens links unten.
So, nun ist die Position meines ersten Rechtecks oben links definiert, gezeichnet ist es noch nicht.
Ist die Anzahl der Rechtecke ungerade, wird es weiß gefüllt, bei einer geraden Anzahl schwarz. Die Anzahl der Rechtecke ist gerade noch bei 0, also gerade, das bedeutet das folgende Rechteck, welches gezeichnet werden wird, — es wird das erste werden — wird schwarz gefüllt werden. Es liegt in der Zukunft, denn noch sind wir bei null.
Jetzt wird ein Rechteck gezeichnet, endlich. Die x-Position hatten wir auf 0 berechnet, es ist ganz links, die y-Position liegt bei 180, also ganz oben. Die Kantenlänge ist 20 Einheiten, gesetzt mittels der Variable in Zeile 2. Und voilà, erstes Rechteck!
Die Anzahl der Rechtecke wird auf 1 erhöht.

Wir springen zurück in Zeile 20, denn wir sind noch in der inneren while-Schleife. Kantenlänge (20) plus Anzahl der Rechtecke (1) ist 20, also kleiner als 200. Neuer Durchlauf. Die Position von y ist nun 160. Das Modulo ist nun 0,5, also nicht gerade, daher wird das folgende Rechteck weiß gefüllt. Es wird auf die Postion 0, 160 gezeichnet; die Anzahl der Rechtecke wird auf 2 erhöht.

Wir springen zurück in Zeile 20, denn wir sind noch in der inneren while-Schleife. Kantenlänge (20) plus Anzahl der Rechtecke (2) ist 40, also kleiner als 200. Neuer Durchlauf. Die Position von y ist nun 140. Das Modulo ist nun 0, also gerade, daher wird das folgende Rechteck schwarz gefüllt. Es wird auf die Postion 0, 140 gezeichnet; die Anzahl der Rechtecke wird auf 3 erhöht.

Wir springen zurück in Zeile 20, denn wir sind noch in der inneren while-Schleife, so lange bis die Bedingung Kantenlänge × Anzahl der Recktecke die 200 überschreitet; das passiert bei 10 Rechtecken. Wenn die Schleife also das zehnte mal angesteuert wird, ist das Produkt aus Kantenlänge (20) × Anzahl der Rechtecke (10) 200, das ist nicht mehr kleiner als 200, sondern gleich. Die while-loop wird abgebrochen.

Die Anzahl der Spalten, die die ganze Zeit bei 0 stand, wird nun auf 1 erhöht.

Nun starten wir die äußere while-Schleife erneut. Die Kantenlänge (20) × Spaltenanzahl (jetzt 1) ist 20, also kleiner als 200.
Die Position x ist die Kantenlänge (20) × Spaltenanzahl (jetzt 1), also 20.
Die Anzahl der Rechtecke wird wieder auf 0 gesetzt (wir starten mit einer neuen Spalte und fangen wieder oben an).

Nun sind wir im if-Zweig gelandet, da die Spaltenanzahl 1 und das Modulo aus 1 nicht gerade ist.
Neue while-Schleife. Die Position von y wird genauso „wie bei der letzten Spalte“ festgelegt (damit meine ich die vorige while-loop, die die Rechtecke gestapelt hat); wir fangen oben an, erster Wert ist 180. Jetzt sind allerdings die Füllungen vertauscht, d.h. wir beginnen damit, ein weißes Rechteck zu zeichnen.
Zehn mal werden wir die Schleife durchlaufen, bevor sie abbricht und die Spaltenanzahl um 1 auf 2 erhöht.

Wir hüpfen wieder in die äußere while-Schleife, die wir insgesamt neun mal durchlaufen (wir fangen ja bei 0 an, d.h. der erste Durchlauf ist 0, der zweite 1 etc) Beim zehnten Durchlauf der äußeren Schleife ist die Kantenlänge (20) mal die Anzahl der Spalten (10) 200, und das ist genauso groß wie 200, d.h. die Schleife bricht ab.
Unser Schachbrettmuster ist fertig.
Wird die Variable der Kantenlänge geändert, ändern sich entsprechend die Durchläufe der Schleifen.


Diese Herangehensweise ist umständlich. Ich habe von meinem freundlichen wissenden Helfer einen sehr viel kürzeren Code bekommen, der das gleiche Ergebnis zaubert. Diesen werde ich das nächste Mal erklären.


Weiter am 27. Mai 2019

Wie vor ein paar Tagen versprochen … der kürzere Code, der das gleiche Ergebnis zaubern kann, sieht so aus:

x_width = 10
y_height = x_width

x_count = 10
y_count = x_count

newPage(x_count * x_width, y_count * y_height)

x_ind = 0

while x_ind < x_count:
・・・・y_ind = 0
・・・・while y_ind < y_count:
・・・・・・・・if x_ind % 2:
・・・・・・・・・・・・if y_ind % 2:
・・・・・・・・・・・・・・・・fill(1)
・・・・・・・・・・・・else:
・・・・・・・・・・・・・・・・fill(0)
・・・・・・・・else:
・・・・・・・・・・・・if y_ind % 2:
・・・・・・・・・・・・・・・・fill(0)
・・・・・・・・・・・・else:
 ・・・・・・・・・・・・・・・・fill(1)
・・・・rect(x_ind * x_width, y_ind * y_height, x_width, y_height)
・・・・・・・・y_ind += 1
・・・・x_ind += 1

Allerdings ist die Herangehensweise etwas anders. Unterschiede, die nicht genau der ursprünglichen Aufgabenstellung folgen wären einmal, dass die Quadrate sich von unten nach oben stapeln, und nicht von oben beginnen, und dass die Seitengröße nicht vorgegeben ist, d.h. diese ist relativ zur Größe der Quadrate. Trotzdem funktioniert es natürlich und man kann daraus lernen.

Kurz in meinen eigenen Worten erklärt:
Die Quadratbreite wird festgelegt (und ist veränderbar). Die Quadrathöhe entspricht der Quadratbreite.
Die Anzahl der Quadrate in x-Richtung wird festgelegt (und ist veränderbar). Die Anzahl der Quadrate in y-Richtung entspricht der Anzahl der Quadrate in x-Richtung.
Die Seitengröße wird berechnet durch die Quadrat-breite und -anzahl in jeweils x- und y-Richtung.

Die Anzahl der Quadrate in x-Richtung entspricht (gerade) 0.

Eine while-Schleife: Solange die Anzahl der gezählten Quadrate in x-Richtung kleiner als die Anzahl der gewünschten Quadrate in x-Richtung ist …

Die Anzahl der Quadrate in y-Richtung entspricht (gerade) 0.

Eine weitere while-Schleife: Solange die Anzahl der gezählten Quadrate in y-Richtung kleiner als die Anzahl der gewünschten Quadrate in y-Richtung ist …

Der if-Zweig: Falls das Modulo von x ungerade ist, und falls das Modulo von y auch ungerade ist, dann fülle mir das Quadrat bitte weiß, ansonsten schwarz. Und ansonsten: Falls das Modulo von x gerade war und das Modulo von y nun ungerade ist, bitte schwarz, ansonsten weiß.

Nun zeichne ein Quadrat mit der entsprechenden Füllung, Position wie folgt: x-Richtung: Anzahl der Quadrate mal Quadratbreite, y-Richtung genauso. Höhe und Breite wurden in Zeile 1 und 2 festgelegt.

Jetzt erhöhe die Anzahl der Quadrate in y-Richtung um 1 und springe zurück in die innere while-Schleife, solange bis die Anzahl der gewünschten Quadrate der Anzahl der gezählten Quadrate gleich ist. Wenn gleich, springe zurück in die äußere while-Schleife, die bei jedem Durchlauf die Anzahl der gezählten Quadrate in y-Richtung um eines erhöht.

Ist doch ganz logisch, oder?