Schleifen


FOR-Schleifen

Wir haben während der vergangenenen Kapitel immer wieder im Programm etwas durchzählen müssen. Das ist eine sehr häufige Aufgabe. Führe etwas dreimal oder zehnmal oder tausendmal durch. Bis jetzt haben wir uns immer mit einer GOTO-Konstruktion beholfen:

10 LET I=0
20 REM TUE ETWAS
30 LET I=I+1
40 IF I<99 THEN GOTO 20

Der C16 bietet hierfür eine elegantere Lösung, die Anweisung FOR. Man schreibt vor die Befehle, die man N-mal ausführen lassen möchte, die Anweisung FOR I=1 TO N. Und dahinter die Anweisung NEXT N:

10 FOR I=0 TO 99
20 REM TUE ETWAS
30 NEXT I
40 PRINT "FERTIG"

Den Rest übernimmt die FOR-Anweisung selbst: Die Initialisierung der Zählvariable I (es kann auch eine andere Variable sein, z.B. J oder BUMPF) und das Weiterzählen. LET I=0 und LET I=I+1 können also entfallen. Der Computer beginnt bei Zeile 10, I mit 0 zu besetzen. Dann führt er Zeile 20 aus. Bei Zeile 30 springt er zur Zeile 10 zurück (jeweils ein FOR und NEXT gehören immer zusammen!), erhöht I um 1, prüft, ob es kleiner gleich 99 ist. Wenn ja, geht er wieder zur Zeile 20, wenn Nein, dann macht er hinter dem FOR-NEXT-Block, also bei Zeile 40 weiter.

Wenn so ein mehrmaliges "im-Kreis-Gehen" in einem Programm vorkommt, ein Teil des Programms also mehrmals wiederholt wird, nennt man das eine "Schleife". Die FOR-Anweisung ermöglicht es, schnell und elegant Zählschleifen zu programmieren.

Beispiele brauchen wir hier eigentlich nicht mehr zu geben, es kamen schon genügend in der vorangegangenen Kapiteln vor. Hier noch das Beispiel aller ASCII-Zeichen mit FOR-Schleife:

10 FOR I=32 TO 127
20 PRINT I,CHR$(I)
30 NEXT I

Verschachtelte Schleifen

Man kann auch mehrere Schleifen ineinanderschachteln:

10 REM SUCHE PRIMZAHLEN BIS 1000
20 FOR I=1 TO 1000
30 FOR J=2 TO I/2
40 IF INT(I/J)=I/J THEN GOTO 70
50 NEXT J
60 PRINT I
70 NEXT I

Im obigen Beispiel lernen wir gleich auch noch etwas anderes: Schleifen abzubrechen. Es können Situationen entstehen, in denen es nicht sinnvoll oder notwendig ist, alle Schleifen voll zu durchlaufen. In diesem Fall kann man die Schleife abbrechen, indem man einfach hinausspringt, wie es in Zeile 40 geschieht.

WHILE/UNTIL-Schleifen

Der C16 beherrscht noch eine weitaus mächtigere Schleifenart, die WHILE-, bzw. UNTIL-Schleifen. Das Abbruchkriterium ist hier nicht eine Zählervariable, sondern es kann eine beliebige Bedingung sein. Die WHILE-Schleifen beginnen mit DO WHILE und enden mit dem Schlüsselwort LOOP anstelle von NEXT.

10 LET A$="A"
20 DO WHILE A$<>"E"
30 INPUT "GEBEN SIE EINEN STRING EIN",A$
40 LOOP

Dieses Progrämmchen macht nichts anderes, als vom Benutzer andauernd eine Stringeingabe abzuverlangen. Es bricht ab, sobald der Benutzer "E" eingibt, da es nur weitermacht, solange A$<>E ist. In Zeile 10 mussten wir A$ auf einen Wert <>"E" initialisieren, damit die WHILE-Schleife überhaupt betreten wird.

Wir können das noch optimieren, indem wir aus der WHILE-Schleife eine UNTIL-Schleife machen. Beide sind sehr verwandt. Es ist ein bisschen die Frage des Programmierstils, ob man eher die eine oder die andere Variante einsetzt. Bei der UNTIL-Schleife kommt die Schleifenbedingung an den Schluss und bezeichnet nicht die Bedingung zur Fortsetzung der Schleife, sondern die Bedingung für den Abbruch.

10 DO 
20 INPUT "GEBEN SIE EINEN STRING EIN",A$
30 LOOP UNTIL A$="E"

Randbemerkung: Der C16 lässt auch die Variante DO UNTIL ... LOOP und DO ...LOOP WHILE zu. Da diese aber keine Entsprechung in anderen Programmiersprachen haben und nicht notwendig für die Vollständigkeit einer Programmiersprache sind, werden sie hier weggelassen. In allen "klassischen" Programmiersprachen, von PASCAL über C++ bis Java gibt es die drei Schleifentypen FOR, WHILE und DO-UNTIL.

Übungsaufgabe: Schreiben Sie ein "Game of Life". Das ist die Simulation eines Biosystems, in dem Tiere einen Vorrat von Pflanzen auffressen. Gibt es keine Pflanzen mehr, pflanzen sich die Tiere nicht mehr fort und verhungern. Dann können sich die Pflanzen wieder vermehren. Dann gibt es wieder genug zu fressen und die Tiere können sich auch wieder vermehren. Wir realisieren diese Simulation, indem wir den Bildschirm des C16 in ein Biotop mit Pflanzen und Tieren verwandeln: Jede Zelle, in die ein Buchstabe kommt, ist ein Tier oder eine Pflanze. Tiere sind rot, Pflanzen sind grün. Wir malen also ein grünes oder rotes Viereck. Wir haben also 40 mal 25 Vierecke. Die äusserste Schleife ist die Zeitschleife. In jedem Zeitschritt geht der Computer alle Zeilen (Zeilenschleife) und alle Spalten (Spaltenschleife) durch und schaut nach jeder Zelle. Ist die Zelle rot, dann muss nach den Nachbarzellen geschaut werden, denn das Tier braucht was zum Fressen. Gibt es ein grünes Nachbarfeld, wird dieses rot gemacht (Tier frisst und pflanzt sich fort), ansonsten wird es grün. (Tier stirbt und eine neue Pflanze entsteht dort, da hier kein Pflanzenfresser mehr existiert.) Am Anfang müssen Tiere und Pflanzen zufällig gestreut werden.

Damit Sie wissen, welche Zelle grün und welche rot ist, sollten Sie folgendes Unterprogramm verwenden:

1000 REM GETCOLOR OF X,Y-POSITION
1010 REM COL=COLOR
1020 REM LUM=LUMISCENCE
1030 IF (X<0) THEN PRINT "ERROR IN GETCOLOR()":STOP
1040 IF (X>39) THEN PRINT "ERROR IN GETCOLOR()":STOP
1050 IF (Y<0) THEN PRINT "ERROR IN GETCOLOR()":STOP
1060 IF (Y>23) THEN PRINT "ERROR IN GETCOLOR()":STOP
1070 LET H=PEEK(2048+Y*40+X)
1080 LET LUM=INT(H/16)
1090 LET COL=H-LUM*16+1
1100 RETURN

Sie müssen also in X und Y Spalte und Zeile der gesuchten Zelle eingeben und erhalten in COL und LUM Farbe und Helligkeit zurück. Zeile 1070 können Sie nicht verstehen. Die Funktion "PEEK" ist für Ihre weitere Programmierkarriere aber auch nicht wichtig. Ansonsten finden Sie aber einige andere interessante "Figuren": Sie sehen, wie ich den Routinenkopf gestaltet habe: Funktionsbeschreibung der Routine und die Beschreibung der Ausgabevariablen. Sie sehen dann vier Zeilen mit Prüfungen der Eingabevariablen X und Y. Diese könnten ja falsch sein. Wenn sie ausserhalb der gültigen Wertebereichs sind, gibt das Programm eine Fehlermeldung mit einer ungefähren Ortsangabe aus und stoppt. Da in der IF-Anweisung jeweils zwei Befehle stehen müssen und um sich grossartige GOTO-Orgien zu ersparen, habe ich den zweiten Befehl mit einem Doppelpunkt hinter den ersten gehängt und damit gebündelt.

So, nun haben Sie das Rüstzeug für Ihr "Game of Life"! Viel Spass damit!