Quels conseils généraux avez-vous pour jouer au golf dans QBasic? Je cherche des idées qui peuvent être appliquées aux problèmes de golf de code en général qui sont au moins quelque peu spécifiques à QBasic (par exemple, "supprimer les commentaires" n'est pas une réponse).
Les conseils relatifs à l' émulateur QB64 sont également les bienvenus. Il a des fonctionnalités supplémentaires qui ne sont pas dans Microsoft QBasic.
Réponses:
Connaissez vos constructions en boucle
QBasic a plusieurs constructions de boucle:
FOR ... NEXT
,WHILE ... WEND
, etDO ... LOOP
. Vous pouvez également utiliserGOTO
ou (dans certaines situations)RUN
pour boucler.FOR ... NEXT
est assez bon dans ce qu'il fait. Contrairement à Python, il est presque toujours plus court que l'équivalentWHILE
ou laGOTO
boucle, même quand il devient un peu plus sophistiqué:Notez que vous n'avez pas besoin de répéter le nom de la variable après
NEXT
, et vous pouvez éliminer l'espace entre les nombres et la plupart des mots-clés suivants.WHILE ... WEND
est bon lorsque vous avez une boucle qui peut avoir besoin d'être exécutée 0 fois. Mais si vous savez que la boucle s'exécutera au moins une fois, elleGOTO
pourrait être plus courte d'un octet:DO ... LOOP
pour des boucles infinies (sauf oùRUN
peut être utilisé à la place). Bien qu'il coûte le même nombre de caractères qu'un inconditionnelGOTO
, il est un peu plus intuitif à lire. (Notez que "boucle infinie" peut inclure des boucles que vous ne pouvez pas utiliser avec aGOTO
.) La syntaxeDO WHILE
/DO UNTIL
/LOOP WHILE
/LOOP UNTIL
est trop verbeuse; il vaut mieux utiliserWHILE
ouGOTO
selon le cas.GOTO
est, comme mentionné ci-dessus, la manière générale la plus courte d'écrire une boucle do / while. Utilisez des numéros de ligne à un chiffre au lieu d'étiquettes. Notez que lorsque aGOTO
est la seule chose dans laTHEN
partie d'uneIF
instruction, deux syntaxes de raccourcis également concises sont disponibles:GOTO
peut également être utilisé pour créer des flux de contrôle plus compliqués . Les opposants appellent cela du "code spaghetti", mais c'est du code golf: l'illisibilité est presque une vertu!GOTO
fierté!RUN
est utile lorsque vous devez sauter à un endroit fixe du programme et que vous n'avez pas besoin de conserver les valeurs des variables.RUN
par lui-même redémarrera le programme par le haut; avec une étiquette ou un numéro de ligne, il redémarrera à cette ligne. Je l'ai principalement utilisé pour créer des boucles infinies sans état .la source
Utilisez des raccourcis pour
PRINT
etREM
Vous pouvez utiliser à la
?
place dePRINT
et'
au lieu deREM
(commentaire).'
peut également s'avérer utile lors du polyglotage avec des langages qui prennent'
en charge la syntaxe char ou string.la source
Test de divisibilité
Dans les programmes qui vous demandent de tester si un entier est divisible par un autre, la manière la plus évidente est d'utiliser
MOD
:Mais un moyen plus court consiste à utiliser la division entière:
Autrement dit,
x
int-div3
est égal àx
float-div3
.Notez que ces deux approches reviendront
0
pour falsey et-1
pour true, vous devrez donc peut-être annuler le résultat ou le soustraire au lieu de l'ajouter.Si vous avez besoin de la condition opposée (c'est-à
x
- dire qu'elle n'est pas divisible par3
), l'approche évidente consiste à utiliser l'opérateur non égal:Mais s'il
x
est garanti d'être non négatif, nous pouvons enregistrer un octet. La division entière tronque le résultat, il sera donc toujours inférieur ou égal à la division flottante. Par conséquent, nous pouvons écrire la condition comme suit:De même, s'il
x
est garanti négatif, la troncature augmente le résultat et nous pouvons écrirex\3>x/3
. Si vous ne connaissez pas le signe dex
, vous devrez vous y tenir<>
.la source
Abus de scanner
Comme dans de nombreuses langues, il est important de savoir quels caractères peuvent et ne peuvent pas être supprimés.
IF""=a$THEN?0
FOR i=1TO 10STEP 2
. Il existe quelques différences entre QBasic 1.1 (disponible sur archive.org ) et QB64 :?123x
devientPRINT 123; x
. Les exceptions à ce qui précède sont des séquences comme1e2
et1d+3
, qui sont traitées comme une notation scientifique et étendues à100!
et1000#
(simple et double précision, respectivement).d
,e
ou pasf
du tout, sauf s'ils font partie d'un littéral de notation scientifique bien formé. (Par exemple, vous ne pouvez pas omettre l'espace après le numéro de ligne dans1 FOR
ou9 END
, comme vous le pouvez dans QBasic proprement dit.) Il n'infère les points-virgules dans les instructions d'impression que si l'une des expressions est une chaîne:?123"abc"
fonctionne, mais pas?TAB(5)123
ou?123x
.PRINT
instruction qui se termine par un appel àTAB
ouSPC
. (QB64 ne fonctionne pas.)0
peut être omis avant ou après le point décimal (.1
ou1.
), mais pas les deux (.
).ENDIF
est équivalent àEND IF
.la source
endif
fonctionne réellement dans QB64, voir cette réponseCombiner des
Next
déclarationsPeut être condensé jusqu'à
où les itérateurs pour les
For
boucles sonti
,j
etk
- dans cet ordre.Par exemple ci-dessous (69 octets)
Peut être condensé jusqu'à 65 octets
Et en ce qui concerne la façon dont cela affecte la mise en forme et l'indentation, je pense que la meilleure approche pour gérer cela est d'aligner la prochaine déclaration avec la plus externe pour la déclaration. Par exemple.
la source
Connaissez vos méthodes de saisie
QBasic a plusieurs façons d'obtenir l' entrée du clavier de l' utilisateur:
INPUT
,LINE INPUT
,INPUT$
etINKEY$
.INPUT
est votre instruction d'entrée polyvalente standard. Le programme arrête ce qu'il fait, affiche un curseur et permet à l'utilisateur de taper une entrée, terminée par Enter.INPUT
peut lire des nombres ou des chaînes, et il peut lire plusieurs valeurs séparées par des virgules. Vous pouvez spécifier une chaîne comme invite, vous pouvez utiliser l'invite de point d'interrogation par défaut et vous pouvez même (je viens de l'apprendre ce soir) supprimer complètement l'invite. Quelques exemples d'appels:INPUT x$,y
Utilise l'
?
invite par défaut et lit une chaîne et un nombre séparés par des virgules.INPUT"Name";n$
Demande
Name?
et lit une chaîne.INPUT"x=",x
Invite avec
x=
(pas de point d'interrogation! Notez la virgule dans la syntaxe) et lit un nombre.INPUT;"",s$
Supprime l'invite (en utilisant la syntaxe de virgule ci-dessus avec une chaîne d'invite vide), lit une chaîne et ne passe pas à la ligne suivante lorsque l'utilisateur frappe Entrée (c'est ce que fait le point-virgule après
INPUT
). Par exemple, si vousPRINT s$
immédiatement après cela, votre écran ressembleraUser_inputUser_input
.INPUT
est que vous ne pouvez pas lire une chaîne avec une virgule, carINPUT
utilise la virgule comme séparateur de champ. Pour lire une seule ligne de caractères arbitraires (ASCII imprimables), utilisezLINE INPUT
. Il a les mêmes options de syntaxe queINPUT
, sauf qu'il prend exactement une variable qui doit être une variable de chaîne. L'autre différence est qu'ilLINE INPUT
n'affiche pas d'invite par défaut; si vous en voulez un, vous devrez le spécifier explicitement.INPUT$(n)
n'affiche ni invite ni curseur, mais attend simplement que l'utilisateur entre desn
caractères, puis renvoie une chaîne contenant ces caractères. Contrairement àINPUT
ouLINE INPUT
, l'utilisateur n'a pas besoin d'appuyer Enterpar la suite, et Enterpeut en fait être l'un des caractères (il donnera le caractère ASCII 13, connu sous le nom de langages de type C\r
).Le plus souvent, cela est utile car
INPUT$(1)
, généralement en boucle.INPUT$
est bon dans les programmes interactifs où les touches uniques font des choses . Malheureusement, cela ne fonctionne qu'avec des clés qui ont des codes ASCII; cela inclut des choses comme Escet Backspace, mais pas les touches fléchées, Insertet Delete, et d'autres.C'est là
INKEY$
qu'intervient. Il est similaire auINPUT$(1)
fait qu'il renvoie les résultats d'une seule touche 1 , mais différent en ce que:INKEY$
ne prend aucun argument.Bien qu'il
INPUT$(n)
arrête l'exécution jusqu'à ce que l'utilisateur entre desn
caractères, ilINKEY$
n'arrête pas l'exécution. Si l'utilisateur appuie actuellement sur une touche,INKEY$
renvoie une chaîne représentant cette touche; sinon, il revient""
. Cela signifie que si vous souhaitez utiliserINKEY$
pour obtenir la touche suivante, vous devez l'encapsuler dans une boucle d' attente occupée : 2Les deux
INPUT$
etINKEY$
renvoient des caractères ASCII pour les clés qui correspondent aux caractères ASCII (y compris les caractères de contrôle comme d'échappement, tabulation et retour arrière). Cependant,INKEY$
peut également gérer certaines clés qui n'ont pas de codes ASCII. Pour ceux-ci (selon le fichier d'aide), "INKEY $ renvoie une chaîne de 2 octets composée du caractère nul (ASCII 0) et du code de numérisation du clavier."Clair comme de la boue? Voici quelques exemples. Si vous utilisez la
INKEY$
boucle ci-dessus pour capturer une pression sur la touche fléchée gauche,k$
contiendra la chaîne"␀K"
(avec leK
code de balayage représentatif 75). Pour la flèche droite, c'est"␀M"
(77). La page suivante est"␀Q"
(81). F5 est"␀?"
(63).Toujours aussi limpide que de la boue? Ouais. Ce n'est pas la chose la plus intuitive au monde. Le fichier d'aide a un tableau de codes de numérisation, mais j'écris toujours un petit programme pour imprimer les résultats
INKEY$
et j'appuie sur un tas de touches pour trouver les bonnes valeurs. Une fois que vous savez quels caractères correspondent à quelles touches, vous pouvez utiliserRIGHT$(k$,1)
etLEN(k$)
faire la distinction entre tous les différents cas que vous pouvez rencontrer.En bout de ligne?
INKEY$
est bizarre, mais c'est la seule façon de procéder si votre programme nécessite une entrée non bloquante ou doit utiliser les touches fléchées .1 Non compris Shift, Ctrl, Alt, PrntScr, Caps Locket similaire. Ça ne compte pas. : ^ P
2 L'
WHILE ... WEND
idiome ici est ce que j'ai appris dans mes livres QBasic. Pour le golf, cependant, uneGOTO
boucle est plus courte .la source
LOCATE peut être vraiment puissant
L'
LOCATE
instruction vous permet de placer le curseur n'importe où sur l'écran (dans les limites habituelles de l'espace de 80 x 40 caractères) et d'imprimer quelque chose à cet endroit. Cette réponse à un défi le montre vraiment (et est également combinée avec de nombreux autres conseils de ce sujet).Le défi nous demande de sortir chaque caractère sur lequel un utilisateur a appuyé dans une grille 16x6. Avec
LOCATE
c'est simplement une question de div et de mod sur le code ASCII (a
dans ce code):Et puis imprimer le caractère:
la source
Dans QBasic, il est habituel d'utiliser l'
DIM
instruction pour créer des variables, en leur donnant un nom et un type. Cependant, ce n'est pas obligatoire, QBasic peut également dériver un type par le suffixe du nom de la variable. Comme vous ne pouvez pas déclarer et initialiser une variable en même temps, il est souvent sage d'ignorer leDIM
codegolf. Deux extraits fonctionnellement identiques *:* Notez que cela crée deux noms de variables différents.
Nous pouvons spécifier le type de la variable en ajoutant
$
à la fin d'un nom de variable pour les chaînes,!
pour les nombres en simple précision et%
pour les doubles. Les simples sont supposés quand aucun type n'est spécifié.Notez que cela vaut également pour les tableaux. Habituellement, un tableau est défini comme:
Mais les tableaux n'ont pas non plus besoin d'être
DIM
traités:a$
est maintenant un tableau pour les chaînes avec 11 emplacements: de l'index 0 à l'index 10. Ceci est fait parce que QBasic a une option qui permet l'indexation basée sur 0 et basée sur 1 pour les tableaux. Un type de tableau par défaut prend en charge les deux de cette façon.Rappelez-vous le tableau à vingt emplacements que nous avons
DIM
cité ci-dessus? Cela a en fait 21 emplacements, car le même principe s'applique aux tableaux atténués et non atténués.la source
raccourcissant
IF
déclarationsIF
les instructions sont assez chères, et les jouer au golf peut économiser beaucoup d'octets.Considérez ce qui suit (adapté d'une réponse d'Erik l'Outgolfer):
La première chose que nous pouvons faire est d'enregistrer le
ENDIF
en utilisant uneIF
instruction sur une seule ligne :Cela fonctionne tant que vous n'essayez pas de le mettre sur la même ligne que n'importe quoi d'autre. En particulier, si vous avez des
IF
instructions imbriquées , seule la plus interne peut être unilatérale.Mais dans ce cas, nous pouvons éliminer
IF
entièrement les mathématiques. Considérez ce que nous voulons réellement:RND<.5
est vrai (-1
), nous voulons:x
diminuer de 1y
rester le mêmea(i)
devenir 1RND<.5
est false (0
), nous voulons:x
rester le mêmey
diminuer de 1a(i)
devenir 0Maintenant , si nous gagnons le résultat du conditionnel dans une variable (
r=RND<.5
), nous pouvons calculer les nouvelles valeursx
,y
eta(i)
:r
est-1
,x=x-1
; quandr
est0
,x=x+0
.r
est-1
,y=y+0
; quandr
est0
,y=y-1
.r
est-1
,a(i)=1
; quandr
est0
,a(i)=0
.Notre code final ressemble donc à:
économiser un énorme 20 octets (40%) sur la version originale.
L'approche mathématique peut être appliquée de manière surprenante souvent, mais lorsqu'il y a une différence de logique entre les deux cas (par exemple lorsque vous devez saisir quelque chose dans un cas mais pas dans l'autre), vous devrez toujours utiliser
IF
.la source
Parfois, vous devez éviter les tableaux
Les tableaux dans QBasic, lorsqu'ils sont instanciés sans,
DIM
n'ont que 11 emplacements. Si un défi nécessite plus de 11 emplacements (ou N emplacements, où N peut être supérieur à 11), vous devez utiliserDIM
le tableau. Supposons également que nous voulons remplir ce tableau avec des données:Même au golf, cela peut prendre beaucoup de place. Dans de telles occasions, cela peut être moins cher en octets:
Ici, nous plaçons tout dans une chaîne concaténée. Plus tard, nous y accédons comme suit:
Pour cette approche, il est important que toutes les valeurs soient de longueur égale. Prenez la valeur la plus longue et supprimez toutes les autres:
Vous n'avez pas besoin de remplir la dernière valeur et vous pouvez même ignorer les guillemets de clôture! Si le défi spécifie que l'espace blanc n'est pas autorisé dans la réponse, utilisez
RTRIM$()
pour corriger cela.Vous pouvez voir cette technique en action ici .
la source
PRINT
(?
) a quelques bizarreriesLes nombres sont imprimés avec un espace de début et de fin.
L'impression ajoute un saut de ligne. Ce comportement peut être modifié en ajoutant une virgule à la fin de l'instruction pour insérer un onglet à la place, ou un point-virgule pour éviter toute insertion:
Il n'est pas nécessaire d'utiliser
&
ou;
entre des opérations distinctes lors de l'impression, par exemple.?1"x"s$
imprime le numéro1
, avec des espaces de chaque côté, la lettrex
et le contenu dus$
Les sorties
L'impression d'un saut de ligne peut être effectuée avec juste
?
la source
-
est imprimé. Un espace est également imprimé après le numéro. La meilleure façon que j'ai découverte pour se débarrasser de ces espaces estPRINT USING
--dunno si vous voulez ajouter cela à cette réponse ou s'il doit s'agir d'une réponse distincte.WRITE
peut être utile à la place dePRINT
PRINT
est généralement la façon dont vous voudrez faire la sortie, car il est assez flexible et a le?
raccourci. Cependant, laWRITE
commande peut vous faire économiser des octets dans des situations spécifiques:WRITE
place entre guillemets doubles ("
). Si vous avez besoin d'une sortie avec des guillemets doubles, elleWRITE s$
est beaucoup plus courte que?CHR$(34);s$;CHR$(34)
. Voir, par exemple, le quine QBasic connu le plus court .WRITE
n'ajoute pas d'espaces avant et après comme il lePRINT
fait.WRITE n
est beaucoup plus court que?MID$(STR$(n),2)
. Voir, par exemple, FizzBuzz dans QB64 .WRITE
séparez-les par des virgules:WRITE 123,"abc"
sorties123,"abc"
. Je ne peux pas penser à un scénario où cela serait utile, mais cela ne signifie pas qu'il n'y en a pas.Limitations de
WRITE
:PRINT a;b
.LOCATE
, mais cela coûte beaucoup d'octets.)la source
Parfois, QBasic modifie les entrées des fonctions. Abusez ça!
Il y a quelques fonctions qui fonctionnent sur les caractères au lieu des chaînes, mais il n'y a pas de
char
type de données dans QBasic, il n'y a que lestring ($)
type. Prenons par exemple laASC()
fonction, qui renvoie le code-clé ASCII d'un caractère. Si nous voulions entrerseul le premier
l
serait pris en compte par QBasic. De cette façon, nous n'avons pas à nous soucier de couper une chaîne jusqu'à la longueur 1.Un autre exemple vient de cette question où la
STRING$()
fonction est utilisée dans l'une des réponses.Notez que QBasic, lorsqu'il propose une chaîne multi-caractères et ne nécessitant qu'un seul caractère, prend automatiquement le premier caractère et ignore le reste.
la source