Welche allgemeinen Tipps haben Sie zum Golfen in QBasic? Ich bin auf der Suche nach Ideen, die sich auf Code-Golf-Probleme im Allgemeinen anwenden lassen, die zumindest etwas spezifisch für QBasic sind (z. B. "Kommentare entfernen" ist keine Antwort).
Tipps zum QB64- Emulator sind ebenfalls willkommen. Es verfügt über einige zusätzliche Funktionen, die nicht in Microsoft QBasic enthalten sind.
Antworten:
Kennen Sie Ihre Schleifenkonstrukte
QBasic hat mehrere looping Konstrukte:
FOR ... NEXT
,WHILE ... WEND
, undDO ... LOOP
. Sie können auchGOTO
oder (in bestimmten Situationen)RUN
zum Schleifen verwenden.FOR ... NEXT
ist ziemlich gut darin, was es tut. Anders als in Python ist es fast immer kürzer als das ÄquivalentWHILE
oder dieGOTO
Schleife, auch wenn es etwas schicker wird:Beachten Sie, dass Sie den Variablennamen nicht wiederholen müssen
NEXT
, und Sie können Leerzeichen zwischen Zahlen und den meisten folgenden Schlüsselwörtern entfernen.WHILE ... WEND
eignet sich für Schleifen, die 0-mal ausgeführt werden müssen. Wenn Sie jedoch wissen, dass die Schleife mindestens einmal ausgeführt wird, ist sieGOTO
möglicherweise ein Byte kürzer:DO ... LOOP
für Endlosschleifen (außer woRUN
kann stattdessen verwendet werden). Es kostet zwar die gleiche Anzahl von Zeichen wie eine unbedingteGOTO
, ist jedoch etwas intuitiver zu lesen. (Beachten Sie, dass "Endlosschleife" Schleifen enthalten kann, bei denen Sie die Verwendung von a unterbrechenGOTO
.) Die Syntax vonDO WHILE
/DO UNTIL
/LOOP WHILE
/LOOP UNTIL
ist zu ausführlich. Sie sind besser dran mitWHILE
oderGOTO
als angemessen.GOTO
ist, wie oben erwähnt, der kürzeste allgemeine Weg, eine do / while-Schleife zu schreiben. Verwenden Sie einstellige Zeilennummern anstelle von Beschriftungen. Beachten Sie, dass, wenn aGOTO
das einzige Element inTHEN
einerIF
Anweisung ist, zwei ebenso knappe Verknüpfungssyntaxen verfügbar sind:GOTO
kann auch verwendet werden, um kompliziertere Steuerungsabläufe zu erstellen . Die Neinsager bezeichnen dies als "Spaghetti-Code", aber dies ist Code-Golf: Unlesbarkeit ist fast eine Tugend!GOTO
Stolz!RUN
Dies ist nützlich, wenn Sie zu einer festen Stelle im Programm springen müssen und keine der Variablenwerte beibehalten müssen.RUN
startet das Programm von oben neu; mit einem Label oder einer Zeilennummer wird es in dieser Zeile neu gestartet. Ich habe es hauptsächlich verwendet, um zustandslose Endlosschleifen zu erstellen .quelle
Verwenden Sie Kurzbefehle für
PRINT
undREM
Sie können
?
anstelle vonPRINT
und'
anstelle vonREM
(comment) verwenden.'
Dies kann auch nützlich sein, wenn Sie mit Sprachen arbeiten, die'
Zeichen- oder Zeichenfolgensyntax unterstützen.quelle
Teilbarkeitsprüfung
In Programmen, in denen Sie testen müssen, ob eine Ganzzahl durch eine andere teilbar ist, ist die Verwendung der folgenden Methode naheliegend
MOD
:Ein kürzerer Weg ist die Verwendung der Ganzzahldivision:
Das heißt,
x
int-div3
istx
float-div3
.Beachten Sie, dass beide Ansätze
0
für falsch und-1
für wahrheitsgemäß zurückkehren. Sie müssen daher möglicherweise das Ergebnis negieren oder subtrahieren, anstatt es zu addieren.Wenn Sie die entgegengesetzte Bedingung müssen (dh
x
ist nicht teilbar durch3
), ist der offensichtliche Ansatz die die Verwendung nicht-gleich Operator:Wenn dies
x
jedoch garantiert nicht negativ ist, können wir ein Byte speichern. Die Ganzzahldivision schneidet das Ergebnis ab, sodass es immer kleiner oder gleich der Gleitdivision ist. Daher können wir die Bedingung schreiben als:In ähnlicher Weise erhöht das
x
Abschneiden das Ergebnis und wir können schreiben , wenn garantiert ist, dass es negativ ist . Wenn Sie das Zeichen von nicht kennen , müssen Sie bei bleiben .x\3>x/3
x
<>
quelle
Scanner-Missbrauch
Wie in vielen Sprachen ist es wichtig zu wissen, welche Zeichen entfernt werden können und welche nicht.
IF""=a$THEN?0
FOR i=1TO 10STEP 2
. Es gibt einige Unterschiede zwischen QBasic 1.1 (verfügbar unter archive.org ) und QB64 :?123x
wirdPRINT 123; x
. Ausnahmen sind Sequenzen wie1e2
und1d+3
, die als wissenschaftliche Notation behandelt und auf100!
und1000#
(Einfach- bzw. Doppelgenauigkeit) erweitert werden.d
,e
oderf
überhaupt , wenn sie Teil einer wohlgeformten wissenschaftliche Schreibweise wörtliche sind. (Sie können beispielsweise das Leerzeichen nach der Zeilennummer in1 FOR
oder nicht weglassen9 END
, wie dies auch in QBasic der Fall ist.) In print-Anweisungen werden nur Semikolons eingefügt, wenn einer der Ausdrücke ein String ist:?123"abc"
works, aber not?TAB(5)123
or?123x
.PRINT
Anweisung hinzugefügt, die mit einem Aufruf vonTAB
oder endetSPC
. (QB64 nicht.)0
kann vor oder nach dem Komma weggelassen werden (.1
oder1.
), aber nicht beide (.
).ENDIF
ist äquivalent zuEND IF
.quelle
endif
funktioniert tatsächlich in QB64, siehe diese Antwortkombinieren Sie
Next
StatementsDarf bis auf kondensiert werden
wo die Iteratoren für die
For
Schleifen sindi
,j
undk
- in dieser Reihenfolge.Zum Beispiel die unten (69 Bytes)
Kann auf 65 Bytes komprimiert werden
Und was die Auswirkungen auf Formatierung und Einrückung angeht, ist es meiner Meinung nach am besten, die nächste Anweisung an der äußersten for-Anweisung auszurichten. Z.B.
quelle
Kennen Sie Ihre Eingabemethoden
QBasic hat mehr Möglichkeiten , Benutzertastatureingabe zu erhalten:
INPUT
,LINE INPUT
,INPUT$
, undINKEY$
.INPUT
ist Ihre Standard-Mehrzweck-Eingabeanweisung. Das Programm stoppt, was es tut, zeigt einen Cursor an und lässt den Benutzer eine Eingabe eingeben, die durch beendet wird Enter.INPUT
kann Zahlen oder Zeichenfolgen lesen und mehrere Werte durch Kommas trennen. Sie können eine Zeichenfolge als Eingabeaufforderung angeben, die Standard-Fragezeichen-Eingabeaufforderung verwenden und die Eingabeaufforderung sogar ganz unterdrücken (ich habe das erst heute Abend gelernt). Einige Beispielaufrufe:INPUT x$,y
Verwendet die Standardeingabeaufforderung
?
und liest eine Zeichenfolge und eine Zahl, die durch Kommas getrennt sind.INPUT"Name";n$
Fordert zum
Name?
Lesen einer Zeichenfolge auf.INPUT"x=",x
Fordert mit
x=
(kein Fragezeichen! Beachten Sie das Komma in der Syntax) und liest eine Zahl.INPUT;"",s$
Unterdrückt die Eingabeaufforderung (unter Verwendung der obigen Kommasyntax mit einer leeren Eingabeaufforderungszeichenfolge), liest eine Zeichenfolge und wechselt nicht in die nächste Zeile, wenn der Benutzer die Eingabetaste
INPUT
drückt (das ist, was das Semikolon danach tut). Wenn Sie sichPRINT s$
unmittelbar danach befinden, sieht Ihr Bildschirm beispielsweise so ausUser_inputUser_input
.INPUT
ist, dass Sie keine Zeichenfolge mit einem Komma darin lesen können, daINPUT
Komma als Feldtrennzeichen verwendet wird. Verwenden Sie zum Lesen einer einzelnen Zeile beliebiger (druckbarer ASCII-) ZeichenLINE INPUT
. Es hat die gleichen Syntaxoptionen wieINPUT
, außer dass es genau eine Variable braucht, die eine String-Variable sein muss. Der andere Unterschied besteht darin, dassLINE INPUT
standardmäßig keine Eingabeaufforderung angezeigt wird. Wenn Sie eines möchten, müssen Sie es explizit angeben.INPUT$(n)
Zeigt keine Eingabeaufforderung oder keinen Cursor an, sondern wartet einfach, bis der Benutzern
Zeichen eingibt , und gibt dann eine Zeichenfolge zurück, die diese Zeichen enthält. Im Gegensatz zuINPUT
oderLINE INPUT
muss der Benutzer nicht Enterdanach drücken und Enterkann tatsächlich eines der Zeichen sein (es wird das ASCII-Zeichen 13 vergeben, das in C-ähnlichen Sprachen als bekannt ist\r
).Am häufigsten ist dies nützlich
INPUT$(1)
, normalerweise in einer Schleife.INPUT$
ist gut in interaktiven Programmen, in denen einzelne Tastendrücke Dinge tun . Leider funktioniert es nur mit Schlüsseln, die ASCII-Codes haben. Dazu gehören Dinge wie Escund Backspace, aber nicht die Pfeiltasten Insertund Deleteund andere.Hier
INKEY$
kommt was rein. Es ist ähnlich,INPUT$(1)
dass es die Ergebnisse eines einzelnen Tastendrucks 1 zurückgibt , aber darin unterscheidet es sich:INKEY$
nimmt kein Argument.Während
INPUT$(n)
stoppt die Ausführung bis zum Benutzer gibtn
Zeichen,INKEY$
halt nicht die Ausführung. Wenn der Benutzer gerade eine Taste drückt, wirdINKEY$
eine Zeichenfolge zurückgegeben, die diese Taste darstellt. Wenn nicht, kehrt es zurück""
. Das heißt, wenn SieINKEY$
den nächsten Tastendruck erhalten möchten , müssen Sie ihn in eine Besetzt-Warteschleife einbinden: 2Beide
INPUT$
undINKEY$
geben ASCII-Zeichen für Schlüssel zurück, die ASCII-Zeichen entsprechen (einschließlich Steuerzeichen wie Escape, Tabulator und Rücktaste). AllerdingsINKEY$
können auch einige Tasten behandeln, die keine ASCII - Codes. Für diese (so die Hilfedatei) gibt "INKEY $ eine 2-Byte-Zeichenfolge aus dem Null-Zeichen (ASCII 0) und dem Tastatur-Scan-Code zurück."Klar wie Schlamm? Hier sind einige Beispiele. Wenn Sie in der
INKEY$
obigen Schleife die linke Pfeiltaste drücken,k$
wird die Zeichenfolge"␀K"
(mit dem entsprechendenK
Scan-Code 75) angezeigt. Für den rechten Pfeil ist es"␀M"
(77). Bild ab ist"␀Q"
(81). F5 ist"␀?"
(63).Immer noch klar wie Schlamm? Ja. Es ist nicht die intuitivste Sache der Welt. Die Hilfedatei enthält eine Tabelle mit Scan-Codes, aber ich schreibe immer nur ein kleines Programm, um die Ergebnisse auszudrucken,
INKEY$
und drücke eine Reihe von Tasten, um herauszufinden, welche Werte richtig sind. Wenn Sie wissen, welche Zeichen welchen Tasten entsprechen, können Sie mitRIGHT$(k$,1)
undLEN(k$)
zwischen den verschiedenen Fällen unterscheiden, die auftreten können.Endeffekt?
INKEY$
ist komisch, aber es ist der einzige Weg, wenn Ihr Programm nicht blockierende Eingaben erfordert oder die Pfeiltasten verwenden muss .1 Nicht einschließlich Shift, Ctrl, Alt, PrntScr, Caps Lock, und ähnliches. Die zählen nicht. : ^ P
2 Das
WHILE ... WEND
Idiom hier ist das, was ich in meinem QBasic Buch gelernt. Für Golfzwecke ist eineGOTO
Schleife jedoch kürzer .quelle
LOCATE kann sehr mächtig sein
Mit dieser
LOCATE
Anweisung können Sie den Cursor an einer beliebigen Stelle auf dem Bildschirm platzieren (innerhalb der üblichen 80 x 40 Zeichen) und an dieser Stelle etwas ausdrucken. Diese Antwort auf eine Herausforderung ist ein echter Beweis dafür (und wird auch mit vielen anderen Tipps aus diesem Thema kombiniert).Die Herausforderung besteht darin, jedes Zeichen, das ein Benutzer gedrückt hat, in einem 16x6-Raster auszugeben. Mit
LOCATE
dieser ist einfach eine Frage der div und mod über den ASCII - Code (a
in diesem Code):Und dann das Zeichen drucken:
quelle
In QBasic ist es üblich, die
DIM
Anweisung zum Erstellen von Variablen zu verwenden und ihnen einen Namen und einen Typ zu geben. Dies ist jedoch nicht zwingend erforderlich. QBasic kann einen Typ auch durch das Suffix des Variablennamens ableiten. Da Sie eine Variable nicht gleichzeitig deklarieren und initialisieren können, ist es oftDIM
ratsam, das Codegolf zu überspringen . Zwei Schnipsel, die funktional identisch sind *:* Beachten Sie, dass dadurch zwei verschiedene Variablennamen erstellt werden.
Sie können den Variablentyp angeben, indem Sie
$
am Ende eines Variablennamens Zeichenfolgen,!
Zahlen mit einfacher Genauigkeit und%
doppelte Werte hinzufügen . Singles werden angenommen, wenn kein Typ angegeben ist.Beachten Sie, dass dies auch für Arrays gilt. Normalerweise ist ein Array wie folgt definiert:
Arrays müssen aber auch nicht
DIM
med sein:a$
ist jetzt ein Array für Strings mit 11 Slots: von Index 0 bis einschließlich Index 10. Dies geschieht, weil QBasic über eine Option verfügt, die sowohl eine 0-basierte als auch eine 1-basierte Indizierung für Arrays ermöglicht. Eine Standard-Array-Art unterstützt beides.Erinnern Sie sich an das Array mit zwanzig Steckplätzen, das wir
DIM
oben angegeben haben? Das hat tatsächlich 21 Steckplätze, da das gleiche Prinzip sowohl für gedimmte als auch für nicht gedimmte Arrays gilt.quelle
Verkürzende
IF
AussagenIF
Anweisungen sind ziemlich teuer, und wenn Sie sie ablegen, können viele Bytes gespart werden.Betrachten Sie Folgendes (nach einer Antwort von Erik dem Outgolfer):
Das erste, was wir tun können, ist das Speichern
ENDIF
mit einer einzeiligenIF
Anweisung:Dies funktioniert, solange Sie nicht versuchen, es in die gleiche Zeile wie irgendetwas anderes zu setzen. Insbesondere wenn Sie verschachtelte
IF
Anweisungen haben, kann nur die innerste einzeilig sein.Aber in diesem Fall können wir die
IF
Verwendung von Mathematik vollständig eliminieren . Überlegen Sie, was wir eigentlich wollen:RND<.5
wahr ist (-1
), wollen wir:x
um 1 verringerny
gleich bleibena(i)
1 werdenRND<.5
false (0
) ist:x
gleich bleibeny
um 1 verringerna(i)
zu 0 werdenNun , wenn wir das Ergebnis der bedingten in einer Variablen (speichern
r=RND<.5
), können wir die neuen Werte von berechnenx
,y
unda(i)
:r
ist-1
,x=x-1
; wennr
ist0
,x=x+0
.r
ist-1
,y=y+0
; wennr
ist0
,y=y-1
.r
ist-1
,a(i)=1
; wennr
ist0
,a(i)=0
.Unser endgültiger Code sieht also so aus:
Satte 20 Bytes (40%) mehr als in der Originalversion.
Der mathematische Ansatz kann überraschend oft angewendet werden, aber wenn es einen logischen Unterschied zwischen den beiden Fällen gibt (z. B. wenn Sie in einem Fall etwas eingeben müssen, in dem anderen jedoch nicht), müssen Sie ihn trotzdem verwenden
IF
.quelle
Manchmal sollten Sie Arrays vermeiden
Arrays in QBasic haben, wenn sie ohne instanziiert werden
DIM
, nur 11 Slots. Wenn eine Herausforderung mehr als 11 Steckplätze erfordert (oder N Steckplätze, wobei N größer als 11 sein kann), sollten SieDIM
das Array verwenden. Nehmen wir außerdem an, wir möchten dieses Array mit Daten füllen:Auch beim Golfen kann dies viel Platz in Anspruch nehmen. In solchen Fällen kann es billiger sein, dies in Bytes zu tun:
Hier platzieren wir alles in 1 verketteten String. Später greifen wir wie folgt darauf zu:
Für diesen Ansatz ist es wichtig, dass alle Werte gleich lang sind. Nehmen Sie den längsten Wert und füllen Sie alle anderen aus:
Sie müssen nicht den letzten Wert auffüllen, und Sie können sogar die abschließenden Anführungszeichen überspringen! Wenn die Abfrage angibt, dass in der Antwort kein Leerraum zulässig ist
RTRIM$()
, beheben Sie diesen Fehler.Sie können diese Technik hier in Aktion sehen .
quelle
PRINT
(?
) hat einige MackenZahlen werden mit einem führenden und einem hinteren Leerzeichen gedruckt.
Beim Drucken wird ein Zeilenumbruch eingefügt. Dieses Verhalten kann geändert werden, indem am Ende der Anweisung ein Komma hinzugefügt wird, um stattdessen einen Tabulator einzufügen, oder ein Semikolon, um Einfügungen zu vermeiden:
Es ist nicht erforderlich, beim Drucken
&
oder;
zwischen verschiedenen Vorgängen zu wechseln, z.?1"x"s$
druckt die Zahl1
mit Leerzeichen auf jeder Seite, den Buchstabenx
und den Inhalt vons$
Ausgänge
Das Drucken eines Zeilenumbruchs kann mit nur erfolgen
?
quelle
-
gedruckt. Nach der Nummer wird ein Leerzeichen gedruckt. Der beste Weg, diese Leerzeichen zuPRINT USING
entfernen, ist --keine Angabe, ob Sie dies zu dieser Antwort hinzufügen möchten oder ob es sich um eine separate Antwort handeln sollte.WRITE
kann anstelle von nützlich seinPRINT
PRINT
In der Regel ist dies die Art und Weise, wie Sie die Ausgabe durchführen möchten, da sie ziemlich flexibel ist und die?
Verknüpfung enthält. Mit demWRITE
Befehl können Sie jedoch in bestimmten Situationen Bytes sparen:WRITE
Sie ihn in doppelte Anführungszeichen ("
). Wenn Sie eine Ausgabe mit doppelten Anführungszeichen benötigen,WRITE s$
ist sie viel kürzer als?CHR$(34);s$;CHR$(34)
. Siehe zum Beispiel die kürzeste bekannte QBasic-Quine .WRITE
keine Leerzeichen vor und nach dieser einPRINT
.WRITE n
ist viel kürzer als?MID$(STR$(n),2)
. Siehe zum Beispiel FizzBuzz in QB64 .WRITE
Trennen Sie bei der Ausgabe mehrerer Werte diese durch Kommas:WRITE 123,"abc"
Outputs123,"abc"
. Ich kann mir kein Szenario vorstellen, in dem dies nützlich wäre, aber das heißt nicht, dass es keines gibt.Einschränkungen von
WRITE
:PRINT a;b
.LOCATE
, aber das kostet eine Menge Bytes.)quelle
Manchmal führt QBasic Eingaben in Funktionen aus. Missbrauch das!
Es gibt einige Funktionen, die Zeichen anstelle von Zeichenfolgen verarbeiten, aber
char
in QBasic gibt es keinen Datentyp , sondern nur denstring ($)
Typ. Nehmen Sie zum Beispiel dieASC()
Funktion, die den ASCII-Schlüsselcode für ein Zeichen zurückgibt. Wenn wir eintreten würdennur der erste
l
würde von QBasic berücksichtigt. Auf diese Weise müssen wir uns nicht darum kümmern, eine Saite auf Länge 1 zu kürzen.Ein weiteres Beispiel stammt aus dieser Frage, in der die
STRING$()
Funktion in einer der Antworten verwendet wird.Beachten Sie, dass QBasic, wenn ein String mit mehreren Zeichen angeboten wird und nur ein Zeichen benötigt, automatisch das erste Zeichen verwendet und den Rest ignoriert.
quelle