¿Qué consejos generales tienes para jugar al golf en QBasic? Estoy buscando ideas que puedan aplicarse a los problemas de código de golf en general que sean al menos algo específicos de QBasic (por ejemplo, "eliminar comentarios" no es una respuesta).
Consejos sobre el emulador QB64 también son bienvenidos. Tiene algunas características adicionales que no están en Microsoft QBasic.

Respuestas:
Conozca sus construcciones en bucle
QBasic tiene varias construcciones de bucle:
FOR ... NEXT,WHILE ... WEND, yDO ... LOOP. También puede usarGOTOo (en algunas situaciones)RUNpara hacer un bucle.FOR ... NEXTes bastante bueno en lo que hace. A diferencia de Python, casi siempre es más corto que el equivalenteWHILEo elGOTObucle, incluso cuando se vuelve un poco más elegante:Tenga en cuenta que no necesita repetir el nombre de la variable después
NEXT, y puede eliminar el espacio entre los números y la mayoría de las siguientes palabras clave.WHILE ... WENDes bueno para cuando tienes un ciclo que podría necesitar ejecutarse 0 veces. Pero si sabe que el bucle se ejecutará al menos una vez,GOTOpodría ser un byte más corto:DO ... LOOPpara bucles infinitos (excepto dondeRUNse puede usar en su lugar). Si bien cuesta la misma cantidad de caracteres que un incondicionalGOTO, es un poco más intuitivo de leer. (Tenga en cuenta que "bucle infinito" puede incluir bucles de los que se salga usando aGOTO.) La sintaxisDO WHILE/DO UNTIL/LOOP WHILE/LOOP UNTILes demasiado detallada; es mejor usarloWHILEoGOTOsegún corresponda.GOTOes, como se mencionó anteriormente, la forma general más corta de escribir un bucle do / while. Use números de línea de un solo dígito en lugar de etiquetas. Tenga en cuenta que cuando aGOTOes lo único en laTHENparte de unaIFdeclaración, hay dos sintaxis de acceso directo igualmente concisas disponibles:GOTOTambién se puede utilizar para crear flujos de control más complicados . Los detractores se refieren a esto como "código de espagueti", pero esto es golf de código: ¡la imposibilidad de leer es casi una virtud!GOTO¡orgullo!RUNes útil cuando necesita saltar a un lugar fijo en el programa y no necesita mantener ninguno de los valores de las variables.RUNpor sí solo reiniciará el programa desde arriba; con una etiqueta o número de línea, se reiniciará en esa línea. Lo he usado principalmente para crear bucles infinitos sin estado .fuente
Use atajos para
PRINTyREMPuede usar en
?lugar dePRINT, y en'lugar deREM(comentario).'También puede ser útil cuando se poliglota con lenguajes que son compatibles'como parte de la sintaxis char o string.fuente
Prueba de divisibilidad
En los programas que requieren que pruebe si un entero es divisible por otro, la forma obvia es usar
MOD:Pero una forma más corta es usar la división de enteros:
Es decir,
xint-div3es igual axfloat-div3.Tenga en cuenta que ambos enfoques volverán
0para falsey y-1para verdadero, por lo que es posible que deba negar el resultado o restarlo en lugar de sumar.Si necesita la condición opuesta (
xes decir, no es divisible por3), el enfoque obvio es utilizar el operador no igual:Pero si
xse garantiza que no es negativo, podemos guardar un byte. La división entera trunca el resultado, por lo que siempre será menor o igual que la división flotante. Por lo tanto, podemos escribir la condición como:Del mismo modo, si
xse garantiza que es negativo, el truncamiento aumenta el resultado y podemos escribirx\3>x/3. Si no conoce el signo dex, deberá atenerse<>.fuente
Abuso del escáner
Como en muchos idiomas, es importante saber qué caracteres pueden y no pueden eliminarse.
IF""=a$THEN?0FOR i=1TO 10STEP 2. Existen algunas diferencias entre QBasic 1.1 (disponible en archive.org ) y QB64 :?123xconviertePRINT 123; x. Las excepciones a lo anterior son secuencias como1e2y1d+3, que se tratan como notación científica y se expanden a100!y1000#(precisión simple y doble, respectivamente).d,eofen absoluto a menos que sean parte de un literal notación científica bien formada. (Por ejemplo, no puede omitir el espacio después del número de línea1 FORo9 END, como puede hacerlo en QBasic propiamente dicho). Solo infiere punto y coma en las declaraciones de impresión si una de las expresiones es una cadena:?123"abc"funciona, pero no?TAB(5)123o?123x.PRINTdeclaración que termina con una llamada aTABoSPC. (QB64 no lo hace)0puede omitirse antes o después del punto decimal (.1o1.), pero no ambos (.).ENDIFes equivalente aEND IF.fuente
endifen realidad funciona en QB64, mira esta respuestaCombinar
NextdeclaracionesPuede condensarse hasta
donde los iteradores para los
Forbucles soni,jyk- en ese orden.Por ejemplo, el siguiente (69 Bytes)
Puede condensarse hasta 65 bytes.
Y en cuanto a cómo esto afecta el formato y la sangría, creo que el mejor enfoque para manejar esto es alinear la siguiente declaración con la declaración más externa. P.ej.
fuente
Conoce tus métodos de entrada
QBasic tiene varias maneras de conseguir la entrada de teclado del usuario:
INPUT,LINE INPUT,INPUT$, yINKEY$.INPUTes su enunciado de entrada multipropósito estándar. El programa detiene lo que está haciendo, muestra un cursor y permite al usuario escribir alguna entrada, terminada por Enter.INPUTpuede leer números o cadenas, y puede leer múltiples valores separados por comas. Puede especificar una cadena como mensaje, puede ir con el mensaje predeterminado de signo de interrogación, e incluso puede (acabo de enterarme esta noche) suprimir el mensaje por completo. Algunas invocaciones de muestra:INPUT x$,yUtiliza el
?indicador predeterminado y lee una cadena y un número, separados por comas.INPUT"Name";n$Solicita
Name?y lee una cadena.INPUT"x=",xAparece con
x=(sin signo de interrogación; observe la coma en la sintaxis) y lee un número.INPUT;"",s$Suprime la solicitud (usando la sintaxis de coma anterior con una cadena de solicitud vacía), lee una cadena y no se mueve a la siguiente línea cuando el usuario presiona enter (eso es lo que hace el punto y coma después
INPUT). Por ejemplo, siPRINT s$inmediatamente después de esto, se verá su pantallaUser_inputUser_input.INPUTes que no puede leer una cadena con una coma, ya queINPUTusa la coma como separador de campo. Para leer una sola línea de caracteres arbitrarios (ASCII imprimible), useLINE INPUT. Tiene las mismas opciones de sintaxis queINPUT, excepto que toma exactamente una variable que debe ser una variable de cadena. La otra diferencia es queLINE INPUTno muestra una solicitud por defecto; si quieres uno, tendrás que especificarlo explícitamente.INPUT$(n)no muestra ningún indicador o cursor, sino que simplemente espera hasta que el usuario ingresencaracteres y luego devuelve una cadena que contiene esos caracteres. A diferencia deINPUToLINE INPUT, el usuario no necesita presionar Enterdespués, y de hecho Enterpuede ser uno de los caracteres (le dará el carácter ASCII 13, conocido como lenguajes tipo C\r).Muy a menudo, esto es útil como
INPUT$(1), típicamente en un bucle.INPUT$es bueno en programas interactivos donde las pulsaciones de teclas individuales hacen cosas . Desafortunadamente, solo funciona con teclas que tienen códigos ASCII; esto incluye cosas como Escy Backspace, pero no las teclas de flecha, Inserty Delete, y otros.Que es donde
INKEY$entra. Es similar aINPUT$(1)que devuelve los resultados de una sola pulsación de tecla 1 , pero diferente en eso:INKEY$No tiene argumento.Mientras
INPUT$(n)detiene la ejecución hasta que el usuario ingresencaracteres,INKEY$no detiene la ejecución. Si el usuario está presionando una tecla,INKEY$devuelve una cadena que representa esa tecla; si no, vuelve"". Esto significa que si desea utilizarINKEY$para obtener la siguiente pulsación de tecla, debe envolverlo en un bucle de espera ocupada : 2Ambos caracteres de retorno
INPUT$yINKEY$ASCII para claves que corresponden a caracteres ASCII (incluidos los caracteres de control como escape, tabulación y retroceso). Sin embargo,INKEY$también puede manejar algunas claves que no tienen códigos ASCII. Para estos (dice el archivo de ayuda), "INKEY $ devuelve una cadena de 2 bytes compuesta por el carácter nulo (ASCII 0) y el código de escaneo del teclado".¿Claro como el barro? Aquí hay algunos ejemplos. Si utiliza el
INKEY$bucle anterior para capturar una pulsación de tecla de la tecla de flecha izquierda,k$contendrá la cadena"␀K"(con elKcódigo de exploración que representa 75). Para la flecha derecha, es"␀M"(77). Página abajo es"␀Q"(81). F5 es"␀?"(63).Todavía claro como el barro? Si. No es la cosa más intuitiva del mundo. El archivo de ayuda tiene una tabla de códigos de escaneo, pero siempre escribo un pequeño programa para imprimir los resultados
INKEY$y presiono un montón de teclas para averiguar cuáles son los valores correctos. Una vez que sepa qué caracteres corresponden a qué teclas, puede usarRIGHT$(k$,1)yLEN(k$)distinguir entre todos los diferentes casos que pueda encontrar.¿Línea de fondo?
INKEY$es extraño, pero es el único camino a seguir si su programa requiere una entrada sin bloqueo o necesita usar las teclas de flecha .1 No incluye Shift, Ctrl, Alt, PrntScr, Caps Lock, y similar. Esos no cuentan. : ^ P
2 El
WHILE ... WENDmodismo aquí es lo que aprendí en mis libros de QBasic. Para fines de golf, sin embargo, unGOTOcircuito es más corto .fuente
LOCATE puede ser realmente poderoso
La
LOCATEdeclaración le permite colocar el cursor en cualquier lugar de la pantalla (dentro de los límites habituales de espacio de 80x40 caracteres) e imprimir algo en esa ubicación. Esta respuesta a un desafío realmente muestra esto (y también se combina con muchos otros consejos de este tema).El desafío nos pide que saquemos todos los caracteres que un usuario ha presionado en una cuadrícula de 16x6. Con
LOCATEesto es simplemente una cuestión de div y mod sobre el código ASCII (aen este código):Y luego imprimiendo el personaje:
fuente
En QBasic, es costumbre usar la
DIMdeclaración para crear variables, dándoles un nombre y un tipo. Sin embargo, esto no es obligatorio, QBasic también puede derivar un tipo por el sufijo del nombre de la variable. Como no puede declarar e inicializar una variable al mismo tiempo, a menudo es aconsejable omitir elDIMcodegolf. Dos fragmentos que son funcionalmente idénticos *:* Tenga en cuenta que esto crea dos nombres de variables diferentes.
Podemos especificar el tipo de variable agregando
$al final de un nombre de variable para cadenas,!para números de precisión individuales y%para dobles. Se suponen solteros cuando no se especifica ningún tipo.Tenga en cuenta que esto también es válido para las matrices. Por lo general, una matriz se define como:
Pero las matrices tampoco necesitan
DIMmeditar:a$ahora es una matriz para cadenas con 11 ranuras: desde el índice 0 hasta el índice 10 incluido. Esto se hace porque QBasic tiene una opción que permite la indexación basada en 0 y en 1 para matrices. Un tipo de matriz predeterminado es compatible con ambos de esta manera.¿Recuerdas la matriz de veinte ranuras que
DIMmedimos arriba? Eso en realidad tiene 21 ranuras, porque el mismo principio se aplica tanto a las matrices atenuadas como a las no atenuadas.fuente
IFDeclaraciones de acortamientoIFlas declaraciones son bastante caras, y reducirlas puede ahorrar muchos bytes.Considere lo siguiente (adaptado de una respuesta de Erik the Outgolfer):
Lo primero que podemos hacer es guardar el
ENDIFmediante el uso de unaIFdeclaración de una sola línea :Esto funciona siempre que no intentes ponerlo en la misma línea que cualquier otra cosa. En particular, si tiene
IFdeclaraciones anidadas , solo la más interna puede tener una línea.Pero en este caso, podemos eliminar
IFcompletamente el uso de las matemáticas. Considere lo que realmente queremos:RND<.5es verdadero (-1), queremos:xdisminuir en 1ypermanecer iguala(i)convertirse en 1RND<.5es falso (0), queremos:xpermanecer igualydisminuir en 1a(i)convertirse en 0Ahora si salvamos el resultado de la condicional en una variable (
r=RND<.5), podemos calcular los nuevos valores dex,yya(i):res-1,x=x-1; cuandores0,x=x+0.res-1,y=y+0; cuandores0,y=y-1.res-1,a(i)=1; cuandores0,a(i)=0.Entonces nuestro código final se ve así:
ahorrando la friolera de 20 bytes (40%) sobre la versión original.
El enfoque matemático se puede aplicar sorprendentemente a menudo, pero cuando hay una diferencia en la lógica entre los dos casos (por ejemplo, cuando necesita ingresar algo en un caso pero no en el otro), aún tendrá que usarlo
IF.fuente
A veces, debes evitar las matrices
Las matrices en QBasic, cuando se instancian sin
DIMtener solo 11 espacios. Si un desafío requiere más de 11 ranuras (o N ranuras, donde N puede ser mayor que 11), debe hacerDIMla matriz. Además, supongamos que queremos llenar esta matriz con datos:Incluso jugando al golf, esto puede ocupar mucho espacio. En tales ocasiones, puede ser más barato en bytes hacer esto:
Aquí, colocamos todo en 1 cadena concatenada. Más tarde, accedemos así:
Para este enfoque, es importante que todos los valores tengan la misma longitud. Tome el valor más largo y rellene todos los demás:
No necesita rellenar el último valor, ¡e incluso puede omitir las comillas de cierre! Si el desafío especifica que el espacio en blanco no está permitido en la respuesta, utilícelo
RTRIM$()para solucionarlo.Puedes ver esta técnica en acción aquí .
fuente
PRINT(?) tiene algunas peculiaridadesLos números se imprimen con un espacio inicial y final.
La impresión agrega un salto de línea. Este comportamiento puede modificarse agregando una coma al final de la instrucción para insertar una pestaña o un punto y coma para evitar cualquier inserción:
No es necesario usar
&o;entre operaciones distintas al imprimir, por ejemplo.?1"x"s$imprimirá el número1, con espacios a cada lado, la letraxy el contenido des$Salidas
La impresión de un salto de línea se puede hacer con solo
?fuente
-se imprime un signo menos allí. También se imprime un espacio después del número. La mejor manera que he descubierto para deshacerme de estos espacios es - noPRINT USINGsé si quieres agregar eso a esta respuesta o si debería ser una respuesta separada.WRITEpuede ser útil en lugar dePRINTPRINTgeneralmente es la forma en que querrá hacer la salida, ya que es bastante flexible y tiene el?acceso directo. Sin embargo, elWRITEcomando puede guardarle bytes en situaciones específicas:WRITEenvuelve entre comillas dobles ("). Si necesita resultados con comillas dobles,WRITE s$es mucho más corto que?CHR$(34);s$;CHR$(34). Ver, por ejemplo, la quina QBasic más corta conocida .WRITEno agrega espacios antes y después, como loPRINThace.WRITE nes mucho más corto que?MID$(STR$(n),2). Ver, por ejemplo, FizzBuzz en QB64 .WRITEsepárelos con comas:WRITE 123,"abc"salidas123,"abc". No puedo pensar en un escenario en el que esto sea útil, pero eso no significa que no haya ninguno.Limitaciones de
WRITE:PRINT a;b.LOCATE, pero eso cuesta muchos bytes).fuente
A veces, QBasic manipula las entradas a las funciones. Abusa de eso!
Hay un par de funciones que funcionan en caracteres en lugar de cadenas, pero no hay un
chartipo de datos en QBasic, solo existe elstring ($)tipo. Tomemos por ejemplo laASC()función, que devuelve el código clave ASCII para un personaje. Si quisiéramos entrarsolo el primero
lsería considerado por QBasic. De esta manera, no tenemos que molestarnos en cortar una cuerda hasta la longitud 1.Otro ejemplo proviene de esta pregunta donde la
STRING$()función se usa en una de las respuestas.Tenga en cuenta que QBasic, cuando se le ofrece una cadena de caracteres múltiples y necesita solo un carácter, toma automáticamente el primer carácter e ignora el resto.
fuente