Consejos para jugar al golf en Batch

14

Windows Batch (CMD) es probablemente el lenguaje menos adecuado para el golf de código.

Evita los personajes de nueva línea . Si está buscando el código más corto en bytes, en lugar de caracteres, querrá deshacerse de todos los retornos de carro innecesarios (caracteres de nueva línea = 2 bytes). Puede usar la &operación para hacer esto, recortando un byte para cada comando.

echo Hello&echo World.

Configuración de variables . Cuando se configuran variables usando interruptores, el setanalizador ignorará los espacios.

set /a a+=1
set /p b="User Input: "
:: Will be handled the same as..
set/aa+=1
set/pb="User Input: "

Tenga en cuenta que las mismas reglas del analizador no se aplican a todos los comandos; por ejemplo, para los bucles se requieren espacios. Excepto entre el set, string, or command(es decir, lo que está dentro de los corchetes) y la palabra do.

for /f %%a in (file.txt)do ...

Expresiones matemáticas simples . Además, observe la expresión que usé para incrementar en el set /acomando. Para expresiones matemáticas simples, use en += -= *= /=lugar de (por ejemplo) set /a a=%a%+1.

Recopilación de salida del comando . Para obtener la salida de un comando, a veces puede ser útil enviar y leer desde un archivo, donde de lo contrario podría haber usado un bucle for para recopilar la salida:

for /f %%a in ('echo test') do set a=%%a
:: Can be shortened to
echo test>f&set/pa=<f

echo testenvíe stdout a un archivo llamado f, >finicie un nuevo comando &y obtenga el contenido del archivo en una variable set/pa=<f. Obviamente esto no siempre es útil. Pero puede ser cuando todo lo que necesita es una sola línea de salida.

Comando de salida . Al suprimir la salida del comando, úselo @antes de los comandos, a menos que necesite suprimir más de 9 comandos, en cuyo caso, úselo @echo offal comienzo de su script. @echo offtiene una longitud de 9 bytes y, por lo tanto, generalmente guardará más bytes con secuencias de comandos más largas.

Los comandos a menudo hacen más que lo que es obvio : piense en lo que están haciendo sus comandos. Por ejemplo; si necesita establecer una variable y hacer eco de otra variable, en lugar de:

set a=OUTPUT
echo %a%
echo test>f
set /p b=<f

Puede usar el comando set con el /pinterruptor para enviarlo %a%por usted.

set a=OUTPUT
echo test>f
set /p b=%a%<f

Completamente golf ...

set a=OUTPUT&echo test>f&set/pb=%a%<f

Un par de ejemplos: cuenta de suma de todos los dígitos , conjetura de Goldbach .

Cualquier otro consejo es más que apreciado. Seguiré actualizando esto si pienso en otra cosa.

carne sin carne
fuente
16
Publique las partes de respuesta de esto como una respuesta, no como parte de la pregunta.
No es que Charles
@Charles Estoy bastante seguro de cómo lo he hecho, este es un formato aceptable para una 'pregunta de consejos'. Otras personas pueden agregar respuestas con consejos propios.
dejar sin carne

Respuestas:

4

Contadores

Siempre que tenga una variable que actuará como un contador a partir de 0tal vez quiera escribir

set count=0
set/acount+=1

; sin embargo, puede eliminar las primeras líneas porque siempre que set/ase usa con una variable no establecida se supone que su valor es0

set/acounter+=1

Bloques de código

Hay varias formas en que puede reducir algunos bytes cuando tiene que usar bloques de código.

Siempre que abra un bloque de código, no necesita insertar un salto de línea antes de la primera línea de código en ese bloque. Los paréntesis de cierre tampoco tienen que estar en una línea propia.

If %a%==%b% (
     echo true
) else (
    echo false
)

se puede jugar golf

If %a%==%b% (echo true)else (echo false)

Imprimir sin arrastrar nueva línea

El patrón común para esto es

echo|set/p=text

pero puedes guardar 2 bytes cambiando echoacd

cd|set/p=text
ankh-morpork
fuente
2
@ ankp-morpork Hola, llego un poco tarde. Pero quiero informarle que la ifdeclaración se puede seguir jugando. El mejor debería ser:if %a%==%b% (echo true)else echo false
stevefestl
3

Amonestaciones

Aunque 's hace que el código parezca más corto, ya que usa menos líneas, usa tantos caracteres como una nueva línea. Esto significa que

echo a&echo b

es tan largo como

echo a
echo b

para que su código pueda seguir siendo legible sin desperdiciar caracteres.

Puede haber excepciones porque algunos editores de texto combinan el avance de línea y el retorno de cartucho para cada nueva línea.

kitcar2000
fuente
Incluí esto en la publicación original porque una nueva línea cuenta para dos bytes en cada editor de texto que uso. Gracias por agregar esta aclaración.
Unclemeat
2
El salto de línea de retorno de carraige de Window es de dos caracteres y muchos editores de texto lo contarán como dos, pero cuando comencé a responder preguntas de golf, uno de los comentarios que quedaba decía que en PPCG las terminaciones de línea siempre se cuentan como un carácter.
Jerry Jeremiah
2
Los avances de línea de estilo Unix funcionarán bien en scripts CMD, al menos en versiones recientes de Windows.
user2428118
1
De hecho, CMD incluso elimina los caracteres CR antes de analizar: stackoverflow.com/questions/4094699/…
schnaader
3

Imprima directamente el resultado de un cálculo numérico

Si el desafío requiere que ingrese un número que necesita ser calculado, puede usarlo cmd/c set/apara generar el resultado del cálculo directamente en lugar de guardar el cálculo y luego repetirlo. Ejemplo:

@set/a a=%1+%2
@echo %a%

se convierte

@cmd/cset/a%1+%2

Editar: aparentemente no se necesitan espacios, ahorrando 2 bytes más.

Neil
fuente
2

Expansión retrasada

En lugar de usar el extenso setLocal enableDelayedExpansion, puede usar cmd /v on(o cmd/von) que iniciará un nuevo intérprete con la expansión variable retardada habilitada.

Todavía tengo que implementar esto, así que no tengo ningún ejemplo, pero podría usar esto junto con el /cinterruptor. Ejemplo:

@cmd/von/cset test=test^&echo !test!

Observe el uso del quilate antes del signo "&". Si necesita usar varios símbolos de unión o cualquier otro carácter especial, es mejor que incluya todo después del /ccambio entre comillas:

@cmd/von/c"set test=test&set test1=test1&echo !test! !test1!"

Este método también tiene la ventaja de tener que usar un solo @carácter para enmascarar toda la entrada y, por lo tanto, puede usarse sin /vonuna alternativa más corta @echo off(o varios @símbolos).

9 caracteres: @echo off
6 caracteres:@cmd/c

Para secuencias de comandos más largas, que no puede hacer en una línea, puede hacer lo siguiente para guardar algunos bytes:

@!! 2>nul||cmd/q/v/c%0&&exit/b

O, no golfista:

@!! 2>nul || cmd /q /v on /c %0 && exit/b

Reemplazar @echo off&setLocal enableDelayedExpansioncon lo anterior.

Cuando ejecuta su script por primera vez !!, no se expandirá en absoluto, por lo que recibirá un error porque "!!"no es un comando. La salida del error se canaliza a nul ( 2>nul). Cuando este primer 'comando' falla ( ||), llama a una nueva instancia de cmd, que llama al archivo por lotes en sí mismo ( /v (on)para habilitar la expansión retardada y /qdesactivar el eco). Luego !!se expandirá a nada, ya que no hay una variable llamada <NULL>. El resto de su script se ejecuta. Después de lo cual volverá a la instancia original de cmd, y ( &&) saldrá con la /bcondición de mantener la ventana abierta (la salida es para que no continúe ejecutándose a través de su script en el contexto de la primera instancia de cmd, con echo encendido y retraso de la expansión apagado).

carne sin carne
fuente
Para esto, ejecutar archivos por lotes con cmd /q /v on /c <filename>solo debería contar como 2 bytes porque son dos "banderas" similares a las banderas de Perl como las -pIque solo contarían como 2 bytes adicionales.
Artyer
1

Cuerdas repetitivas

Establezca bloques de código repetitivo en variables, donde el número de bytes utilizados para establecer la variable + el número de bytes para generar la variable son menores que el número de bytes para simplemente llamar al código directamente.

Para ver un ejemplo, vea: Dibuje las combinaciones que suman 100

Usted ahorra 1 byte por uso del comando set, si crea una variable (nombrada con un carácter, como "s") que contiene set<space>. Esto solo genera valor si usa el comando set más de 12 veces. (Tenga en cuenta que hay un carácter al final de la cadena set s=set).

set s=set 
%s%a=1
%s%b=2
%s%c=3
%s%d=4
%s%e=5
%s%f=6
%s%g=7
%s%h=8
%s%i=9
%s%j=10
%s%k=11
%s%l=12
%s%m=13

Lo anterior es 1 byte más corto que ...

set a=1
set b=2
set c=3
set d=4
set e=5
set f=6
set g=7
set h=8
set i=9
set j=10
set k=11
set l=12
set m=13

Este es probablemente un ejemplo bastante pobre, pero deja claro el punto.

carne sin carne
fuente
1

Inicio de una cadena

La notación %var:~start,end%extrae una subcadena de la variable var. Sin embargo, si startes 0así, puede omitirlo por completo. Ya sabemos que puede omitir ,endsi desea el resto de la cadena, lo que hace %var:~%un sinónimo casi inútil para %var%, excepto que regresa ~cuando %var%está vacío. (Tal vez podría usarlo en una prueba if %var:~%==~:?)

Neil
fuente
Me gusta tu última oración recordándonos que esto ahorrará algunas citas :) +1 para eso.
stevefestl
1

IF EQUDeclaraciones de acortamiento

if %a% equ %b% do_something
if %a%==%b% do_something

Usar en ==lugar de equ guardar 3 bytes.


Acortando citas en IF declaraciones

Esta es una comparación tradicional llamada "más segura" if.

if "%a%"=="%b%" do_something

Para acortar esta declaración, haga lo siguiente cuando la entrada solo puede ser alfanumérica / vacía :

if %a%.==%b%. do_something

Ahorrando un total de 2 bytes.


Desafíos que requieren resultados

Si la pregunta dice algo como:

Emite al menos 1 carácter visible.

entonces podrías hacer esto:

cd

El cdmuestra el directorio actual a STDOUT.


GOTOing una etiqueta

Aquí hay algunos métodos para gotocrear una etiqueta, ordenados en orden descendente de bytes.

goto :l
goto l
goto:l

El método anterior ahorra 1 byte.

stevefestl
fuente
1
Alternativamente, podría hacer lo goto:lque ahorra el mismo 1 byte y tiene la ventaja adicional de mantener intacto su colon
Matheus Avellar
@MatheusAvellar: He agregado el contenido en consecuencia a su comentario
stevefestl
1

Omitir espacio entre comando y parámetros con barras inclinadas

Perdón por el título poco informativo. A lo que estoy tratando de llegar es que para algunos (no todos) comandos de Windows, puede omitir el espacio entre el nombre del comando / programa y el parámetro, siempre que ese parámetro comience con una barra inclinada. Por ejemplo:

for /f %%G in ...

se convierte

for/f %%G in ...

-1 Byte!

Salida de tubería en lugar de usar ERRORLEVEL

Usar ERRORLEVEL para determinar si un comando se ejecutó correctamente no es el método más corto o más elegante. En cambio, puede canalizar la salida. Esto funciona de la siguiente manera (recuerde que cualquier comando después del &&operador solo se ejecuta si el comando anterior a&& ejecutó sin errores. Cualquier comando posterior al ||operador, por otro lado, se ejecutará solo si el comando anterior NO se ejecutó correctamente. Mi ejemplo es :

net session>nul
if %errorlevel%==0 (echo 1) else (echo 0)

Esto podría ser reemplazado por:

net session>nul&&echo 1||echo 0

-26 Bytes, ¡guau! Tenga en cuenta que esto no funciona con comandos comochoice , donde ERRORLEVEL tiene un valor especial de acuerdo con alguna entrada.

Saludos,
Gabe

Gabriel Mills
fuente
1

Usar paréntesis de manera efectiva

Hola de nuevo,

Lamento publicar una segunda respuesta, pero sentí que esta se lo merecía. He notado que las personas a menudo usan uno de los siguientes métodos para mostrar la salida del comando sin mostrar esa molesta C:\Windows\System32>echo foolínea antes de cada comando.
El primer método (usando echo off):

@echo off
echo foo
echo bar
echo foobar
echo barfoo

El segundo método:

@echo foo
@echo bar
@echo foobar
@echo barfoo

Sin embargo, ninguno de estos métodos es tan corto como el siguiente:

@(echo foo
echo bar
echo foobar
echo barfoo)

Bastante útil, ¿verdad? En otra nota, esto se puede usar para canalizar fácilmente múltiples líneas de salida a un archivo o dispositivo. Por ejemplo, este largo código:

echo foo>file.txt
echo bar>file.txt
echo foobar>file.txt
echo barfoo>file.txt

se vuelve significativamente más corto:

(echo foo
echo bar
echo foobar
echo barfoo)>file.txt

Gracias por leer esta respuesta bastante larga, y espero que esto te ayude. Saludos,
Gabe

Gabriel Mills
fuente
Publicar respuestas múltiples a preguntas de consejos no es malo.
Erik the Outgolfer