3. Schleifen und Sprünge

 

Bis jetzt können Sie Ihre Programme nur Schritt für Schritt abarbeiten, und um eine Anweisung z.B. 100-mal auszuführen, müssten Sie diese auch 100-mal eintippen. Dass dies sehr ineffizient ist, dürfte wahrscheinlich bereits klar sein. Besser ist es sicherlich, 100-mal zu einem Ausgangsunkt zurückspringen zu können, solange eine bestimmte Bedingung erfüllt ist, wie z.B. ein Zähler, der noch nicht einen bestimmten Wert erreicht hat.

 

3.1 Bedingte Sprünge mit FOR…NEXT und IF…THEN

 

Diese sogenannte bedingte Ausführung von Anweisungen gibt es in BASIC in Form von FOR und IF. Der Befehl FOR hat hier das folgende Format:

 

FOR [Zählvariable]=[Startwert] TO [Endwert] STEP [Schrittweite]

… Anweisungen …

NEXT [Zählvariable]

 

Für die Zählvariable kann ein beliebiger Variablenname eingesetzt werden, außer natürlich ein String (dieser kann keine Zahl enthalten). Der Startwert wird nun immer dann gesetzt, wenn FOR zum ersten Mal aufgerufen wird, und der Endwert ist dann der Wert, den der Zähler maximal erreichen muss, bevor BASIC die Schleife wieder verlässt. Mit STEP kann auch optional noch eine Schrittweite definiert werden.

Nach Erreichen des FOR-Schleifenkopfes führt BASIC dann wieder ganz normal Zeile für Zeile aus, diese Anweisungen, die FOR folgen, nennt man auch den Schleifenkörper. Dieser Schleifenkörper kann durchaus auch sehr viele Anweisungen enthalten, die auch in mehreren Zeilen stehen können. Trifft BASIC allerdings auf NEXT, wird die Zählvariable, die hinter NEXT steht, um den zuvor gespeicherten STEP-Wert erhöht (wird STEP weggelassen, ist dieser Wert 1). Anschließend schaut BASIC nach, ob die hinter NEXT angegebene Zählvariable den zuvor bei FOR angegebenen Endwert erreicht. Ist dies nicht der Fall, springt BASIC in die Zeile direkt hinter dem letzten FOR zurück. Ansonsten wird die Schleife verlassen und das Programm fährt mit der Zeile fort, die hinter NEXT steht. Stimmt die nach NEXT angegebene Zählvariable nicht mit dem zuvor bei FOR angegebenen Variablennamen überein, wird eine entsprechende Fehlermeldung, nämlich

 

?NEXT WITHOUT FOR  ERROR

 

ausgegeben. Schleifen können auch ineinander geschachtelt werden, allerdings dürfen sich die Zählvariablen nicht überkreuzen. Folgendes ist also nicht erlaubt:

 

10 FOR I=1 TO 10

20 FOR J=1 TO 10

30 PRINT “I=“;I;“J=“;J

40 NEXT J

50 NEXT I

 

Allerdings ist folgende Schachtelung erlaubt:

 

10 FOR I=1 TO 10

20 FOR J=1 TO 10

30 PRINT “I=“;I;“J=“;J

40 NEXT J

50 NEXT I

 

In dem letzten Beispiel wird immer die innere Schleife 10-mal ausgeführt, bevor die äußere Schleife erneut (auch insgesamt 10-mal) ausgeführt wird, das ergibt dann also 100 Durchläufe, und nicht 20! Wenn Sie allerdings die Ausführung einer bestimmten Anweisung von einer (durchaus auch komplexen) Bedingung abhängig machen wollen, dann ist FOR der falsche Weg und Sie müssen IF benutzen:

 

IF [Bedingung] THEN [Anweisung]

 

[Bedingung] ist hier ein beliebiger BASIC-Ausdruck, der durchaus auch mathematisch sein kann (also z.B. eine Berechnung enthalten kann). Dieser Ausdruck muss mathematisch korrekt sein, aber der Ausdruck muss nicht logisch wahr sein. Logisch wahr ist z.B. der folgende Ausdruck:

 

1+2+3=6

 

Logisch falsch ist dagegen der folgende Ausdruck, falls A=1 ist:

 

A=1+2+3

 

IF prüft nun den Ausdruck, der hinter IF steht darauf, ob er logisch wahr ist. Ist er dies, wird die Anweisung ausgeführt, die hinter THEN steht (fehlt das THEN, erscheint SYNTAX ERROR). Ansonsten fährt BASIC in der nächsten Zeile fort. Leider ist C64 sehr beschränkt in Bezug auf IF und THEN, und es gibt z.B. folgendes Konstrukt nicht, das es bei anderen BASIC-Versionen durchaus auch auf „alten Maschinen“ gibt:

 

IF [Bedingung]

… Anweisungen ….

ENDIF

 

Das heißt, IF besitzt nicht so etwas wie einen „Schleifenkörper“, und dies kann in der Tat zu „Spaghetticode“ in der folgenden Weise Führen:

 

IF … GOTO/GOSUB …

IF … GOTO/GOSUB …

IF … GOTO/GOSUB …

 

3.1.1 Der ON-Befehl

 

Eine kleine Abkürzung können Sie durch den ON-Befehl erreichen, der das folgende Format hat:

 

ON [Variable] GOTO/GOSUB [Zeile 1],…,[Zeile n]

 

ON betrachtet die hier angegebene Variable als Zähler und schaut nach, ob der Wert des Zählers zu der Aufzählung der Programmzeilen passt, die hinter GOTO bzw. GOSUB steht. Angefangen wird bei 0. Wenn also der Zähler 0 ist, wird der GOTO/GOSUB-Befehl mit der Zeile ausgeführt, den Sie als erstes angegeben haben, wenn der Zähler 1 ist, wird der GOTO/GOSUB-Befehl mit der Zeile ausgeführt, den Sie als zweites angegeben haben.

 

3.1.2 Logische Verknüpfungen mit AND,  OR und NOT

 

Mit IF können auch mehrere Bedingungen gleichzeitig geprüft werden. Hierzu dienen die Operatoren AND (und), OR (oder) und NOT (nicht). Werden nach IF mehrere Ausdrücke durch AND verknüpft, so muss jeder einzelne Ausdruck logisch wahr sein, damit die Anweisung, die zum IF gehört ausgeführt wird. So ist z.B. folgende Aussage logisch wahr:

 

A=10

IF A>5 AND A>9 THEN PRINT”A IST GROSS GENUG”

 

Allerdings wird die Anweisung nach IF nicht ausgeführt, wenn A=7 ist. Werden dagegen nach IF mehrere Ausdrücke durch OR verknüpft, so muss mindestens einer der Ausdrücke logisch wahr sein. Das heißt, wenn A=10 ist, dann ist der folgende Ausdruck logisch wahr, und die PRINT-Anweisung wird ausgeführt:

 

IF A<5 OR A>9 THEN PRINT”A HAT EINEN KORREKTEN WERT”

 

A darf hier also keine Werte im Intervall [5,9] annehmen. Wenn Sie einen Ausdruck zusätzlich negieren wollen, dann müssen Sie ein NOT voranstellen. So entspricht der folgende Ausdruck dem vorigen:

 

IF NOT (A>=5 AND A<=9) THEN PRINT”A HAT EINEN KORREKTEN WERT”

 

Also können AND, OR und NOT beliebig gemischt, und Ausdrücke auch durch Klammern gekapselt werden. Allerdings müssen sämtliche Ausdrücke mathematisch und syntaktisch korrekt sein, und eine BASIC-Zeile darf nicht mehr als 20 geöffnete Klammern enthalten.

 

3.1.3 Logische Ausdrücke im Vergleich zu Bit-Operationen

 

AND und OR sind in BASIC leider doppelt belegt. Im Zusammenhang mit IF verknüpfen AND und OR logische Aussagen. So ist z.B. der Ausdruck

 

IF 3<2 THEN PRINT“HALLO“

 

logisch falsch, und der Text „HALLO“ wird nicht ausgegeben. Außerhalb von IF…THEN…-Konstrukten besitzen jedoch AND und OR eine andere Bedeutung: Es werden nun die einzelnen Bits der entsprechenden Zahlen, die sich hinter den einzelnen Ausdrücken verbergen, miteinander verknüpft. In der BASIC-Befehlsreferenz wird noch ausgiebig auf logische Operationen und Bitoperationen eingegangen. Nur so viel vorab: Die Bitoperation AND verknüpft die einzelnen Bits zweier Zahlen n und m derart, dass das Bit im Ergebnis immer dann gesetzt (=1) ist, wenn dasselbe Bit sowohl bei n, als auch bei m gesetzt ist. Die Bitoperation OR verknüpft die einzelnen Bits zweier Zahlen n und m derart, dass das Bit im Ergebnis immer dann gesetzt (=1) ist, wenn dasselbe Bit entweder bei n, oder bei m, oder bei n und m gesetzt ist. Leider gibt es beim C64-BASIC keine XOR-Operation, die bewirkt, dass ein gesetztes Bit bei n und m zu einem gelöschten Bit im Ergebnis führt.

NOT entspricht auch bei den Bits einem „nicht“, allerdings bezogen auf die einzelnen Bits. Das heißt, NOT 1234 dreht sämtliche Bits der Zahl 1234 um. Allerdings erhalten Sie bei NOT 1234 das Ergebnis -1235, was daran liegt, dass das oberste Bit einer Zahl stets als Vorzeichen-Bit gewertet wird, zumindest, wenn Sie keine zusätzlichen Operatoren benutzen, die dies verhindern.

Für die Bit-Operationen gilt, dass jeder Ausdruck wahr ist, der nicht das Ergebnis 0 hat.

 

3.2 Nichtbedingte direkte Sprünge mit GOTO und GOSUB

 

Nichtbedingte Sprünge, auch als direkte Sprünge bezeichnet, sind nicht abhängig von einer Bedingung und werden immer sofort ausgeführt. Sprünge in BASIC springen stets zu einer bestimmten Programmzeile und setzen auch die Ausführung direkt dort fort. Wollen Sie zu einer bestimmten Programmzeile springen, müssen Sie GOTO benutzen:

 

GOTO [Programmzeile]

 

GOTO kann durchaus auch (und so wird es auch häufig so benutzt) direkt hinter THEN stehen- in diesem Fall kann dann auch GOTO (aber nur zusammen mit IF…THEN…) für einen bedingten Sprung „missbraucht“ werden. GOTO alleine springt aber immer ohne Wenn und Aber.

Wenn Sie dagegen GOSUB verwenden (das Sie für bedingte Sprünge auch wieder direkt hinter THEN stellen können), merkt sich BASIC vorher die Stelle, von der aus Sie gesprungen sind. Mit GOSUB rufen Sie also Unterprogramme auf, die bestimmte häufig benötigte Routinen enthalten, wie z.B. die Anzeige der Bestenliste oder des aktuellen Punktestands. Unterprogramme können durchaus sehr viele BASIC-Zeilen enthalten, müssen aber stets mit RETURN beendet werden. Im Endeffekt entspricht RETURN dem C-Pendant return, allerdings benutzt das C64-BASIC keine lokalen Variablen und kann auch keine Parameter zurückgeben. Wenn also ein Unterprogramm Variablen verändert, dann ist diese Änderung auch außerhalb des Unterprogramms sichtbar.

 

3.3 Beispiele

 

Weil Sie jetzt Variablen, Arrays, bedingte und direkte Sprünge beherrschen, und auch schon Schleifen programmieren können, wird es jetzt höchste Zeit für Beispiele, die diese Konstrukte auch benutzen. Diese Beispiele sind noch einfach gehalten, tun aber schon etwas Sinnvolles, das Sie später dann auch weiterverwenden können.

 

3.3.1 Laufschrift 1

 

04-LAUFSCHRIFT 1

10 POKE 53280,0:POKE 53281,0

20 PRINT"[WHT][SHIFT+CLR/HOME]"

30 A$="…………………………………." (die 40 Punkte sind hier Leerzeichen)

40 A$=A$+"EINE LAUFSCHRIFT ZU PROGRAMMIEREN IST GARNICHT SO SCHWER."

50 A$=A$+" MAN MUSS NUR MIT DER MID$-FUNKTION RICHTIG UMGEHEN KOENNEN."

80 A$=A$+"…………………………………." (die 40 Punkte sind hier Leerzeichen)

90 J=LEN(A$)-40

100 FOR I=1 TO J

110 PRINT"[CLR/HOME][12*Cursor unten]";

120 PRINT MID$(A$,I,40)

130 FOR K=1 TO 100:NEXT K

140 NEXT I

150 GOTO 100

 

Zeile 10 stellt erst einmal mit POKE einen schwarzen Bildschirm ein. Damit man die Laufschrift später gut lesen kann, wird die Farbe in Zeile 20 auf Weiß gestellt. Allerdings muss nach dem Farbwechsel der Schrift der Bildschirm gelöscht werden, damit nachher auch sämtliche Zeichen Weiß sind. In den Zeilen 30-80 wird nun der String A$ definiert, der die Laufschrift enthält. Allerdings ist A$ mehr als 80 Zeichen lang, deshalb muss A$ dann auch stückweise zusammengesetzt werden: Erst 40 Leerzeichen, dann der eigentliche Text, und dann wieder 40 Leerzeichen. Die Laufschrift selbst wird dann in einer FOR-Schleife (Zeile 100-140) angezeigt, allerdings muss vorher der Zähler J auf die Position des ersten Zeichens in A$ gesetzt werden, das kein Leerzeichen enthält. Dies kann mit der LEN-Funktion erreicht werden: LEN liefert hier die Länge von A$ zurück, und von dieser wird nachher 40 abgezogen.

Die Schleife, die die Laufschrift darstellt, zählt nun von 1 bis J (=LEN(A$)-40). Innerhalb der Schleife wird nun zunächst der Cursor zurück an den Anfang der 12. Bildschirmzeile gesetzt (per PRINT-Anweisung in Zeile 110). Nun wird die Laufschrift in Zeile 120 ausgegeben, und zwar so: Es werden mit der MID$-Funktion ab der Position I 40 Zeichen von A$ ausgegeben, und dies ist immer genau eine ganze Zeile. Dadurch werden die schon vorhandenen Zeichen gelöscht. Auf diese Weise erklärt sich auch der „Vorlauf“ und „Nachlauf“ von jeweils 40 Zeichen in A$: Der eigentliche Laufschrift-Text muss den Bildschirm erst vollständig auf der linken Seite verlassen, ehe er rechts wieder hineinlaufen kann. Bevor aber die Schleife in Zeile 140 verlassen werden kann, die die Laufschrift anzeigt, muss in Zeile 130 noch eine kleine Schleife eingefügt werden, die eigentlich nichts tut, außer den Zähler J 100-mal hochzuzählen. Diese klassische Form der Warteschleife sorgt dafür, dass Sie den Text auch wirklich lesen können, ohne dass dieser sehr schnell „vorbeiflimmert“.

Wenn die gesamte Schrift „durchgelaufen“ ist, springt das Programm in Zeile 150 wieder zurück zu Zeile 100 und zeigt dadurch die Laufschrift erneut an. Leider führt dies dazu, dass Sie das Programm nur noch mit RUN/STOP unterbrechen können.

 

3.3.2 Laufschrift 2

 

05-LAUFSCHRIFT 2

10 POKE 53280,0:POKE 53281,0

20 PRINT"[WHT][SHIFT+CLR/HOME]"

30 A$="…………………………………." (die 40 Punkte sind hier Leerzeichen)

40 A$=A$+"EINE LAUFSCHRIFT ZU PROGRAMMIEREN IST GARNICHT SO SCHWER."

50 A$=A$+" MAN MUSS NUR MIT DER MID$-FUNKTION RICHTIG UMGEHEN KOENNEN."

80 A$=A$+"…………………………………." (die 40 Punkte sind hier Leerzeichen)

90 J=LEN(A$)-40

100 FOR I=1 TO J

110 PRINT"[CLR/HOME][12*Cursor unten]";

120 PRINT MID$(A$,I,40)

130 FOR K=1 TO 20

140 GET K$:IF K$<>"" THEN GOTO 190

150 NEXT K

160 GET K$:IF K$<>"" THEN GOTO 190

170 NEXT I

180 GOTO 100

190 PRINT"[COMMODORE+BLU][SHIFT+CLR/HOME]"

200 POKE 53280,14:POKE 53281,6

 

Das Listing LAUFSCHRIFT 2 ist identisch mit dem Listing LAUFSCHRIFT 1. Allerdings wurde innerhalb der Schleife, die die Laufschrift darstellt, noch eine GET-Anweisung eingefügt. GET schaut nach, ob gerade eine Taste gedrückt ist. Ist dies der Fall, wird diese Taste an den String K$ als ASCII-Zeichen weitergereicht. Ist keine Taste gedrückt, wird an K$ ein leerer String zurückgegeben. Deshalb wird nun innerhalb der Warteschleife (Zähler K) zusätzlich GET K$ ausgeführt, und wenn K$ (K ist hier die Abkürzung von „keyboard“) nicht leer ist (A$<>““), dann wird der entsprechende GOTO-Befehl zu Zeile 190 ausgeführt. Aber auch direkt vor NEXT I (Zeile 170) wird noch einmal nachgeschaut, ob nicht doch eine Taste gedrückt wurde.

Wurde nun eine Taste gedrückt, fährt das Programm mit Zeile 190 und 200 fort, und beendet sich dann. Zeile 190 und 200 stellen den Bildschirm wieder auf die normalen Farben ein und löschen anschließend den Bildschirm. Auf diese Weise kann das Programm LAUFSCHRIFT 2 im Gegensatz zum Programm LAUFSCHRIFT 1 vom Benutzer beendet werden.

 

3.3.3 Laufschrift 3

 

06-LAUFSCHRIFT 3

10 POKE 53280,0:POKE 53281,0

20 PRINT"[WHT][SHIFT+CLR/HOME]":

F$="[CTL+BLK][CTL+WHT][CTL+RED][CTL+CYN][CTL+PUR][CTL+GRN][CTL+BLU][CTR+YEL][CMD+BLK][CMD+WHT][CMD+RED]

    [CMD+CYN][CMD+PUR][CMD+GRN][CMD+BLU][CMD+YEL]”:CO=0 (CTL=CTRL,CMD=COMMODORE)

30 A$="…………………………………."

40 A$=A$+"EINE LAUFSCHRIFT ZU PROGRAMMIEREN IST GARNICHT SO SCHWER."

50 A$=A$+" AUCH ZUSAETZLICHE EFFEKTE SIND GAR NICHT SO SCHWER UMZUSETZEN."

80 A$=A$+"…………………………………."

90 J=LEN(A$)-40

100 FOR I=1 TO J

110 PRINT"[CLR/HOME][12*Cursor unten]";

115 PRINT MID$(F$,CO+1,1);:CO=(CO+1) AND 15

120 PRINT MID$(A$,I,40)

130 FOR K=1 TO 20

140 GET K$:IF K$<>"" THEN GOTO 190

150 NEXT K

160 GET K$:IF K$<>"" THEN GOTO 190

170 NEXT I

180 GOTO 100

190 PRINT"[COMMODORE+BLU][SHIFT+CLR/HOME]"

200 POKE 53280,14:POKE 53281,6

 

Dieses Listing, das einen zusätzlichen Farbwechsel der Laufschrift einbaut, ist nun nicht mehr so schwer zu verstehen, wenn man bedenkt, dass auch Strings (hier F$) Steuerzeichen (hier für die Textfarbe) enthalten können, die anschließend auch mit PRINT korrekt ausgegeben werden können (Zeile 115). Der Zähler, der das entsprechende Farbzeichen auswählt, befindet sich in der Variable CO (Abkürzung für „color“). CO wird nach jeder Ausgabe der aktualisierten Laufschrift um 1 erhöht, doch der zusätzliche AND-Befehl (CO=(CO+1) AND 15) bewirkt, dass CO nur Werte zwischen 0 und 15 annehmen kann (mehr gültige Farbwerte gibt es auch nicht auf dem C64).

 

3.3.4 Labyrinth 1

 

07-LABYRINTH 1

10 PRINT"[SHIFT+CLR/HOME]BITTE EINE TASTE DRUECKEN"

20 GET A$:IF A$="" THEN 20:REM GET-FUNKTION LIEST EINE TASTE

30 IN=RND(0):REM ZUFALLSGENERATOR NEU INITIALISIEREN

40 PRINT"[WHT][SHIFT+CLR/HOME]":POKE 53280,11:POKE 53281,0

50 FOR I=1 TO 250:REM BARRIEREN ZEICHNEN

60 X=INT(40*RND(1)):REM 40 ZEILEN

70 Y=INT(25*RND(1)):REM 25 SPALTEN

80 AD=1024+(40*Y)+X

90 POKE AD,102:REM ASCII-CODE BARRIERE

100 NEXT I

110 POKE 1024+40*RND(1),30

120 X=INT(40*RND(1))

130 Y=24

140 AD=1024+(40*Y)+X

150 POKE AD,24:XO=X:YO=Y

160 GET A$:IF A$="" THEN 160

170 IF A$="[Cursor oben]" THEN Y=Y-1

180 IF A$="[Cursor unten]" THEN Y=Y+1

190 IF A$="[Cursor links]" THEN X=X-1

200 IF A$="[Cursor rechts]" THEN X=X+1

210 IF X<0 THEN X=0

220 IF X>39 THEN X=39

230 IF Y<0 THEN Y=0

240 IF Y>24 THEN Y=24

250 AO=1024+(40*YO)+XO

260 AD=1024+(40*Y)+X

270 POKE AO,32

280 IF PEEK(AD)=102 THEN GOTO 350

290 IF PEEK(AD)=30 THEN GOTO 320

300 XO=X:YO=Y:POKE AD,24

310 GOTO 160

320 PRINT"[SHIFT+CLR/HOME]SIE HABEN GEWONNEN!"

330 PRINT"SIE HABEN DEN AUSGANG GEFUNDEN!"

340 END

350 PRINT"[SHIFT+CLR/HOME]SIE SIND TOT!"

360 PRINT"SIE SIND VOR EINE ELEKTRISCHE BARRIERE"

370 PRINT"GELAUFEN!"

380 END

 

Das Listing LABYRINTH 1 ist ein kleines Labyrinth-Spiel, in dem Sie den Ausgang (dargestellt durch einen Pfeil nach oben) finden müssen. Allerdings wird Ihnen der Weg durch elektrische Barrieren verbaut. Wenn Sie diese Barrieren berühren, sind Sie tot, und das Spiel wird beendet. Der Einfachheit halber haben Sie nur ein einziges Leben, und auch nur einen einzigen Level (Ziel ist es also, den Ausgang zu finden).

Da die Barrieren per Zufall gesetzt werden, werden Sie in Zeile 10 erst einmal dazu aufgefordert, eine Taste zu drücken. Wie lange dies genau dauert, können wahrscheinlich nicht einmal Sie genau sagen. Wenn Sie dann eine Taste gedrückt haben, wird in Zeile 20 der Zufallsgenerator mit RND(0) neu initialisiert, und dies geschieht anhand der Computeruhr. Es werden also am Anfang nicht immer die gleichen Barrieren gesetzt - das soll aber auch so sein.

In Zeile 30 und 40 wird dann der Bildschirm auf Schwarz gestellt, die Schrift auf Weiß und der Bildschirm gelöscht. In Zeile 50-100 werden nun 250 Barriere-Zeichen (ASCII-Code 102, Schleifenzähler I) in den Bildschirmspeicher geschrieben. Da der Bildschirmspeicher 40*25 Zeichen beinhaltet (40 Spalten, 25 Zeilen), und die Koordinaten (X,Y) der Barrieren auch per Zufall (also mit der RND-Funktion gesetzt werden, so ist die Formel für die Koordinaten eine Barriere:

 

X=INT(40*RND(1)), Y=INT(25*RND(1))

 

RND(1) initialisiert nun den Zufallsgenerator nicht noch einmal neu, was RND(1) aber dennoch tut, ist für das Ergebnis nur Zahlen zwischen 0 und 1 zu benutzen. Da aber X zwischen 0 und 39 und Y zwischen 0 und 24 liegen muss, und X und Y nur ganze Zahlen enthalten sollen, müssen Sie das Ergebnis zuerst mit einem entsprechenden Faktor skalieren, und anschließend mit INT in eine Ganzzahl umwandeln. Erst jetzt kann in Zeile 80 die entsprechende Speicheradresse durch die Formel

 

AD=1024+(40*Y)+X

 

ermittelt und in Zeile 90 mit dem Wert 102 beschrieben werden. Es werden auf diese Weise 250 Barrieren gezeichnet. Anschließend wird dann noch in Zeile 110-150 die Position des Spielers (Variablen X und Y) und das Zeichen für den Ausgang (Pfeil nach oben) per Zufall bestimmt.

Der Spieler (ein Kreuz in Form eines X) soll nun mit den Cursortasten gesteuert werden. Hierzu dienen die GET-Anweisungen in Zeile 160-200: Zunächst wird auf eine Taste gewartet, und anschließend wird geschaut, welche Cursortaste gedrückt wurde. Entsprechend wird dann auch die Variable X oder Y geändert. Achten Sie hier beim Abtippen des Listings unbedingt darauf, die Cursortasten richtig einzugeben, und auch wirklich z.B. [SHIFT+CURSOR OBEN] einzutippen (also beide Tasten gleichzeitig zu drücken).

Zeile 210-240 dient nun dazu, X und Y daraufhin zu prüfen, ob der Spieler eventuell das Spielfeld verlassen könnte, und dieses ggf. durch Korrektur von X und Y zu verhindern. Dies geschieht natürlich durch entsprechende IF-Anweisungen.

Nun hat sich der Spieler tatsächlich bewegt, aber von wo nach wo muss nun das Kreuz gesetzt werden? Wo befand sich der Spieler vor dem aktuellen Spielzug? Um dies herauszufinden, dienen die Variablen XO (X old) und YO (Y old), die stets die alte Position vor dem letzten Tastendruck enthalten. Auf diese Weise kann immer die Speicheradresse ermittelt werden, an der sich das Kreuz vor dem aktuellen Spielzug befand, der stets X und Y verändert. In Zeile 250-270 wird nun das alte Kreuz entfernt (an die alte Position wird der Wert 32 in den Bildschirmspeicher geschrieben), was einem Leerzeichen entspricht, und die neue Adresse, an der das Kreuz nun erscheinen soll, wird in der Variablen AD gespeichert. Bevor aber das neue Kreuz gesetzt wird, muss erst noch festgestellt werden, ob sich an der neuen Position eine Barriere (Zeichen-Code 102) oder der Ausgang (Zeichen-Code 30) befindet (hier wird übrigens von POKE PETSCII, und nicht ASCII benutzt). Wenn keine der beiden Bedingungen eintritt, befindet sich an der neuen Position ein Leerzeichen, und in Zeile 300 wird dann das Kreuz erneut in die Adresse AD geschrieben. Anschließend wird durch die GOTO-Anweisung in Zeile 310 die Hauptspielschleife erneut ausgeführt.

Wenn allerdings die IF-Bedingung in Zeile 280 zutrifft, dann sind Sie vor eine Barriere gelaufen, und das Spiel wird mit der Meldung beendet, dass Sie tot sind. Dies wird durch ein GOTO in die Zeile 350 erreicht. Wenn aber die IF-Bedingung in Zeile 290 zutrifft, dann haben Sie den Ausgang erreicht, und das entsprechende GOTO in die Zeile 320 bewirkt, dass die Meldung angezeigt wird, dass Sie das Spiel gewonnen haben.

Das Labyrinth-Spiel ist noch nicht sehr spannend. Außer, dass Sie den Ausgang irgendwann erreicht haben, bekommen Sie keine Belohnung, und es gibt auch nur einen einzigen Level. Wenn Sie dann etwas geübt haben, gewinnen Sie fast immer, und das Spiel verliert seinen Reiz. Ein gutes Spiel enthält dagegen stets zwei Elemente:

 

·       Das Spiel muss mit der Zeit schwieriger werden (denn sonst beginnt sich Ihr Gehirn zu langweilen und verliert die Freude)

·       Im Spiel muss es mehr Belohnungen geben, als nur eine kleine Erfolgsmeldung am Ende (auch bei fehlenden Belohnungen beginnt sich Ihr Gehirn zu langweilen, und verliert die Freude am Spiel).

 

Genau deshalb werde ich nun zwei Dinge einfügen: Erstens gibt es mehrere Level und in jedem Level erscheinen mehr Barrieren (steigende Anforderungen an den Spieler verhindern die Langeweile), und zweitens können Sie, bevor Sie den Ausgang erreichen, Gold einsammeln (fortwährende Belohnungen halten die Freude am Spiel aufrecht). Das nächste Listing enthält nun die verbesserte Version.

 

3.3.5 Labyrinth 2

 

08-LABYRINTH 2

10 PRINT"[SHIFT+CLR/HOME]BITTE EINE TASTE DRUECKEN"

20 GET A$:IF A$="" THEN 20:REM GET-FUNKTION LIEST EINE TASTE

30 IN=RND(0):REM ZUFALLSGENERATOR NEU INITIALISIEREN

40 PRINT"[WHT][SHIFT+CLR/HOME]":POKE 53280,11:POKE 53281,0:LV=1:GD=0

50 GOSUB 1000:REM BARRIEREN SETZEN

60 GOSUB 2000:REM GOLD SETZEN

70 GOSUB 3000:REM SCORELINE ANZEIGEN

80 POKE 1064+40*RND(1),30:REM AUSGANG

120 X=INT(40*RND(1))

130 Y=23

140 AD=1064+(40*Y)+X

150 POKE AD,24:XO=X:YO=Y

160 GET A$:IF A$="" THEN 160

170 IF A$="[Cursor oben]" THEN Y=Y-1

180 IF A$="[Cursor unten]" THEN Y=Y+1

190 IF A$="[Cursor links]" THEN X=X-1

200 IF A$="[Cursor rechts]" THEN X=X+1

210 IF X<0 THEN X=0

220 IF X>39 THEN X=39

230 IF Y<0 THEN Y=0

240 IF Y>23 THEN Y=23

250 AO=1064+(40*YO)+XO:POKE AO,32

260 AD=1064+(40*Y)+X

270 IF PEEK(AD)=102 THEN GOTO 350

280 IF PEEK(AD)=81 THEN GD=GD+1:GOSUB 3000

290 IF PEEK(AD)=30 THEN GOTO 320

300 XO=X:YO=Y:POKE AD,24

310 GOTO 160

320 PRINT"[SHIFT+CLR/HOME]SIE HABEN DEN AUSGANG GEFUNDEN!":LV=LV+1

330 PRINT"DER NAECHSTE LEVEL IST LEVEL";LV

335 GET A$:IF A$="" THEN 335

340 PRINT"[SHIFT+CLR/HOME]":GOTO 50

350 PRINT"[SHIFT+CLR/HOME]SIE SIND TOT!"

360 PRINT"SIE SIND VOR EINE ELEKTRISCHE BARRIERE"

370 PRINT"GELAUFEN!"

380 PRINT"[Cursor unten]ANZAHL GOLDKLUMPEN :";GD

390 PRINT"NEUES SPIEL (J/N)";:INPUT A$

400 IF A$="J" THEN GOTO 30

410 PRINT"[COMMODORE+BLU][SHIFT+CLR/HOME]DAS SPIEL WURDE BEENDET"

420 POKE 53280,6:POKE 53281,14

430 END

1000 REM *** BARRIEREN ***

1010 FOR I=1 TO 50*LV:REM BARRIEREN ZEICHNEN

1020 X=INT(40*RND(1)):REM 40 ZEILEN

1030 Y=INT(24*RND(1)):REM 25 SPALTEN

1040 AD=1064+(40*Y)+X

1050 POKE AD,102:REM ASCII-CODE BARRIERE

1060 NEXT I

1070 RETURN

2000 REM *** GOLD ***

2010 FOR I=1 TO 50:REM GOLDKLUMPEN ZEICHNEN

2020 X=INT(40*RND(1)):REM 40 ZEILEN

2030 Y=INT(24*RND(1)):REM 25 SPALTEN

2040 AD=1064+(40*Y)+X

2050 POKE AD,81:REM ASCII-CODE GOLDKLUMPEN

2060 NEXT I

2070 RETURN

3000 REM *** SCORELINE ***

3010 PRINT"[CLR/HOME]……………" (Punkte sind 15 Leerzeichen)

3020 PRINT"[CLR/HOME]GOLD";GD

3030 RETURN

 

Versuchen Sie, nun als kleine Abschlussübung, das Listing LABYRINTH 2 einmal selbständig zu verstehen. Und das können Sie, denn es enthält keine neuen Dinge, die über POKE, GET, FOR, IF, PRINT, GOTO, GOSUB und die Erzeugung von ganzzahligen Zufallszahlen hinausgehen. Sie können das letzte Labyrinth-Spiel auch mit dem Joystick steuern, wenn Sie die folgenden Zeilen wie folgt abändern:

 

160 PO=56320

170 IF NOT PEEK(PO) AND 1 THEN Y=Y-1

180 IF NOT PEEK(PO) AND 2 THEN Y=Y+1

190 IF NOT PEEK(PO) AND 4 THEN X=X-1

200 IF NOT PEEK(PO) AND 8 THEN X=X+1

 

Setzen Sie für PO den Wert 56321 ein, dann benutzen Sie den Joystickport 1 anstatt Port 2.