Basic optimieren - Teil 3
mad/os

Hier nun wie versprochen ein weiterer Teil meines kleinen Kurses für alle Basic-Programmierer. Die folgenden Tips sind, ähnlich wie beim ersten Teil, unabhängig voneinander anwendbar. Kleine Spezialitäten, Sonderbefehle und mathematische Raffinessen...

1. TALLY: Oft soll ganz einfach überprüft werden, ob ein String in einem anderen vorkommt. Die Funktion `INSTR(H$,T$)` bietet sich dafür besonders an. Eine weitere Möglichkeit stellt die Funktion `TALLY(H$,T$)` dar, die das Vorkommen von `T$` in `H$` zählt. Der Effekt in einer Bedingung ist identisch, da beide Befehle eine Null liefern, wenn `T$` nicht in `H$` vorhanden ist. Durch die Verwendung von `TALLY` wird die Programmdatei jedoch jedesmal etwa 150 Bytes verkleinert. Leider wird `TALLY` auch langsamer ausgeführt, vor allem bei langen Strings, in denen der gesuchte Teil mehrmals vorkommt. In den meisten Fällen dürfte das jedoch egal sein.

2. FIX: Wenn es darum geht, eine Zahl ihrer Nachkommastellen zu berauben, dann gibt es dafür zwei Wege. Die Einen bevorzugen die dafür bestimmte Funktion `FIX`, die Anderen verwenden lieber `INT`. Und seltsamerweise ist das auch egal. Ich konnte keinen einzigen Unterschied zwischen `FIX` und `INT` feststellen. Auch die Geschwindigkeit und Größe der erzeugten Programmdatei sind identisch.

3. SPACE$: Die Funktion `SPACE$` liefert einen String zurück, der aus einer wählbaren Anzahl Leerzeichen besteht. Diese Funktion sollte aber mit Bedacht eingesetzt werden. Wenn man zum Beispiel statt `PRINT SPACE$(3)` die Variante `PRINT "___"` verwendet, werden die Leerzeichen schneller ausgegeben und die Programmdatei wird ein wenig kleiner. `SPACE$` bringt also nur dort etwas, wo die Anzahl tatsächlich verändert werden soll.

4. PRINT: Und hier ein Tip, der nicht das Programm sondern die Eingabe beschleunigt. Schreibt statt des Befehles `PRINT` ganz einfach ein Fragezeichen! Zum Beispiel ist die Zeile `PRINT A$` identisch mit `? A$`, aber es müssen vier Zeichen weniger getippt werden.

5. NOT: Oft werden in einem Programm besondere Variablen verwendet, die zwischen zwei Zuständen hin und her springen sollen. So könnte die Variable `X` zum Beispiel anzeigen, ob eine Funktion ein- oder ausgeschaltet ist. Bisher habe ich so etwas mit der Zeile `IF X = 1 THEN X = 0 ELSE X = 1` realisiert.

Wesentlich eleganter und professioneller sind jedoch die Formen `X = 1 - X` und `X = NOT X`, die zudem noch schneller ausgeführt werden. (Ein herzliches Dankeschön an LeidPen für diesen Trick.) Diese Formen eignet sich jedoch ausschließlich für den Wechsel zwischen Null und Eins! Für andere Kombinationen habe ich die Lösung `X = A + B - X` ersonnen. Für `A` und `B` werden die beiden möglichen Zustände der Variablen `X` eingetragen. Diese Ausdrücke können natürlich auch in eine Konstante verrechnet werden. Außerdem muß `X` unbedingt mit einem der beiden Werte initialisiert werden! Ein Wechsel zwischen den Zahlen 25 und 50 könnte demnach so aussehen:

    X = 25
    DO
      PRINT X,
      X = 25 + 50 - X         'oder auch: X = 75 - X
    LOOP WHILE INKEY$=""

6. LINE INPUT: Der Befehl `INPUT` ist sehr unflexibel und in größeren Programmen praktisch nicht verwendbar. Die Variante `LINE INPUT` bietet schon etwas mehr Komfort, weil dann auch Kommas eingegeben werden können. Außerdem wird vor der Eingabe kein Fragezeichen angezeigt.

7. INKEY$: Für professionelle Programme muß man leider selbst eine komfortable Eingabefunktion schreiben. Entweder verwendet man dafür den Befehl `INPUT$` oder die wirklich universelle Lösung `INKEY$`.

    SUB Eingabe (Zeile, Spalte, L, Text$)
    E$ = Text$
    DO
      LOCATE Zeile, Spalte: PRINT SPACE$(L);
      LOCATE Zeile, Spalte, 1: PRINT E$;
      I$ = "": WHILE I$ = "": I$ = INKEY$: WEND
      SELECT CASE I$
        CASE CHR$(32) TO CHR$(254)
          E$ = LEFT$(E$ + I$, L)
        CASE CHR$(8)
          E$ = LEFT$(E$, ABS(LEN(E$) - 1))
        CASE CHR$(13): Text$ = E$: EXIT DO
        CASE CHR$(27): EXIT DO
      END SELECT
    LOOP: LOCATE , , 0
    END SUB

Dieses Unterprogramm stellt einen vollwertigen Ersatz für den Befehl `INPUT` dar. Zusätzlich wird durch die Variable `L` die mögliche Länge der Eingabe begrenzt. Weitere Funktionen, wie zum Beispiel eine Editierfunktion die auch auf die Pfeiltasten reagiert, sind mit geringfügig höherem Aufwand ebenso realisierbar.

8. ASCII: Die Zuordnung, welche Taste welchen Code verursacht, ist nicht immer logisch. Mit einem kleinen Programm kann man das aber jederzeit selbst ausprobieren.

    DO
      I$ = "": WHILE I$ = "": I$ = INKEY$: WEND
      PRINT ASC(I$)
      IF LEN(I$)1 THEN ? , ASC(MID$(I$, 2))
    LOOP UNTIL I$ = CHR$(27)

Tasten mit normalen Zeichen liefern per `INKEY$` einen einzelnen ASCII-Code zurück, der diesem Zeichen entspricht. Bei Sondertasten wie zum Beispiel den Pfeilen werden jedoch zwei Codes geliefert. Davon ist der erste immer eine Null. Innerhalb des Programmes kann das sehr einfach durch einen Befehl wie zum Beispiel `IF I$=CHR$(0,59) THEN ...` oder `CASE CHR$(0,75)` abgefragt werden.

9. INP(&H60): Vor allem bei Spielen ist die Abfrage der Tastatur mit `INKEY$` sehr unbefriedigend. Eine mögliche Alternative bietet der Port &H60, der die Scancodes der Tastatur direkt abfragt. Diese Variante hat neben dem Vorteil, daß keine Verzögerungen auftreten, auch mehrere Nachteile. So muß zum Beispiel sichergestellt werden, daß der Tastaturpuffer nicht überläuft. Außerdem kann sich ein mangelhaftes Programm sehr leicht in einer Endlosschleife verfangen. Und weil die Signale der Tastatur vom Programm abgefangen werden, läßt es sich nicht mehr abbrechen! Weder `Strg+Untbr` noch die Notlösung `Strg+Alt+Entf` funktionieren dann noch!

    DEFINT A-Z: CLS
    DO
      A=INP(&H60)                             'Tastaturport auslesen
      WHILE LEN(INKEY$): WEND
      IF AB THEN
        SELECT CASE A
          CASE 224: COLOR 14                   'das Vorsatzbyte gelb
          CASE 127: COLOR 2          'losgelassene Tasten dunkelgrün
          CASE ELSE: COLOR 10             'gedrückte Tasten hellgrün
        END SELECT
        ? RIGHT$("00000000"+BIN$(A), 8), A
        B=A
      END IF
    LOOP UNTIL A=1            'mit Esc wird das Programm abgebrochen

Dieses Beispielprogramm zeigt die Scancodes der gedrückten und losgelassenen Tasten am Bildschirm an. Wenn es unter QBasic laufen soll, muß lediglich der Befehl `BIN$` entfernt werden. Hellgrüne Zahlen zeigen an, daß gerade eine Taste gedrückt wurde. Dunkelgrüne Tasten wurden gerade losgelassen. Und das Vorsatzbyte vieler Sondertasten wird gelb angezeigt.

mad/os