Dicas para jogar golfe em lote

14

O Windows Batch (CMD) é provavelmente o idioma menos adequado para o golfe com código.

Evite caracteres de nova linha . Se você estiver procurando pelo código mais curto em bytes, em vez de caracteres, desejará se livrar de todos os retornos de carro desnecessários (caracteres de nova linha = 2 bytes). Você pode usar a &operação para fazer isso, aparando um byte para cada comando.

echo Hello&echo World.

Definindo variáveis . Ao definir variáveis ​​usando opções, o setanalisador ignorará os espaços.

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

Observe que as mesmas regras do analisador não se aplicam a todos os comandos - como um exemplo, pois os loops requerem espaços. Exceto entre set, string, or command(ou seja, o que está dentro dos colchetes) e a palavra do.

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

Expressões matemáticas simples . Além disso, observe a expressão que eu usei para incrementar no set /acomando. Para expressões matemáticas simples, use em += -= *= /=vez de (por exemplo) set /a a=%a%+1.

Reunindo saída de comando . Para obter a saída de um comando, às vezes pode ser útil enviar e ler um arquivo, onde você poderia ter usado um loop for para reunir a saída:

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

echo testenvie stdout para um arquivo chamado f, >finicie um novo comando &e obtenha o conteúdo do arquivo em uma variável set/pa=<f. Obviamente, isso nem sempre é útil. Mas pode ser quando tudo que você precisa é de uma única linha de saída.

Saída de comando . Ao suprimir a saída do comando, use @antes dos comandos, a menos que você precise suprimir mais de 9 comandos; nesse caso, use @echo offno início do seu script. @echo offtem 9 bytes de comprimento e, portanto, geralmente salva mais bytes com scripts mais longos.

Os comandos geralmente fazem mais do que apenas o óbvio - pense no que seus comandos estão fazendo. Por exemplo; se você precisar definir uma variável e repetir outra variável, em vez de:

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

Você pode usar o comando set com a /popção de saída %a%para você.

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

Completamente jogado ...

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

Um par de exemplos - Contagem da soma de todos os dígitos - conjectura de Goldbach .

Quaisquer outras dicas são mais do que apreciadas - continuarei atualizando isso se pensar em outra coisa.

desgrudar
fonte
16
Poste as partes da resposta como resposta, não como parte da pergunta.
Não que Charles
@ Charles Eu tenho certeza de como eu fiz isso, é um formato aceitável para uma 'pergunta de dicas'. Outras pessoas podem adicionar respostas com dicas próprias.
unclemeat,

Respostas:

4

Contadores

Sempre que você tiver uma variável que atuará como um contador a partir de 0você, poderá escrever

set count=0
set/acount+=1

; no entanto, você pode eliminar as primeiras linhas porque sempre que set/aé usado com uma variável não definida, seu valor é assumido como0

set/acounter+=1

Blocos de código

Existem várias maneiras de economizar alguns bytes quando precisar usar blocos de código.

Sempre que você abre um bloco de código, não é necessário inserir uma quebra de linha antes da primeira linha de código nesse bloco. Os parênteses de fechamento também não precisam estar em uma linha própria.

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

pode ser jogado golfe para

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

Imprimindo sem rastrear nova linha

O padrão comum para isso é

echo|set/p=text

mas você pode salvar 2 bytes mudando echoparacd

cd|set/p=text
ankh-morpork
fonte
2
@ ankp-morpork Ei, estou um pouco atrasado. Mas quero informá-lo de que a ifdeclaração pode ser mais aprofundada. O melhor deve ser:if %a%==%b% (echo true)else echo false
stevefestl
3

E comercial

Embora & faça com que o código pareça mais curto, ele usa menos linhas, mas usa tantos caracteres quanto uma nova linha. Isso significa que

echo a&echo b

é contanto que

echo a
echo b

para que seu código fique legível sem desperdiçar caracteres.

Pode haver exceções, porque alguns editores de texto combinam o avanço de linha e o retorno de carridge para cada nova linha.

kitcar2000
fonte
Eu incluí isso no post original porque uma nova linha conta com dois bytes em cada editor de texto que eu uso. Obrigado por adicionar este esclarecimento.
Unclemeat
2
O avanço de linha de retorno de janela da Window tem dois caracteres e muitos editores de texto o contam como dois, mas, quando comecei a responder às perguntas de golfe, um dos comentários deixados dizia que nas terminações de linha do PPCG sempre são contados como um caractere.
Jerry Jeremiah
2
Os feeds de linha no estilo Unix funcionarão bem nos scripts CMD, pelo menos nas versões recentes do Windows.
precisa saber é o seguinte
1
De fato, o CMD remove até caracteres CR antes de analisar: stackoverflow.com/questions/4094699/…
schnaader 17/17
3

Imprimir diretamente o resultado de um cálculo numérico

Se o desafio exigir que você forneça um número que precise ser calculado, use-o cmd/c set/apara enviar diretamente o resultado do cálculo, em vez de salvar o cálculo e repeti-lo. Exemplo:

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

torna-se

@cmd/cset/a%1+%2

Editar: Aparentemente, nenhum espaço é necessário, economizando mais 2 bytes.

Neil
fonte
2

Expansão atrasada

Em vez de usar o longo, setLocal enableDelayedExpansionvocê pode usar cmd /v on(ou cmd/von) o que iniciará um novo intérprete com a expansão variável atrasada ativada.

Ainda tenho que implementar isso para não ter exemplos, mas você pode usá-lo em conjunto com o /cswitch. Exemplo:

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

Observe o uso do quilate antes do e comercial. se você precisar usar vários "e" comercial ou qualquer outro caractere especial, é melhor incluir tudo depois da /cmudança entre aspas:

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

Esse método também tem a vantagem de ter que usar apenas um @caractere para mascarar todas as entradas e, portanto, pode ser usado, sem /von, como uma alternativa mais curta a @echo off(ou vários @símbolos).

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

Para scripts mais longos, que você não pode executar em uma linha, faça o seguinte para salvar alguns bytes:

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

Ou ungolfed:

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

Substitua @echo off&setLocal enableDelayedExpansionpelo acima.

Quando você executa o script pela primeira vez, !!ele não será expandido, então você recebe um erro porque "!!"não é um comando. A saída de erro é então canalizada para nul ( 2>nul). Quando esse primeiro 'comando' falha ( ||), ele chama uma nova instância do cmd, que chama o próprio arquivo em lotes (usando /v (on)para ativar a expansão atrasada e /qdesativar o eco). Em seguida !!, expandirá para nada, pois não há variável chamada <NULL>. O restante do seu script é executado. Depois disso, ele retornará à instância original do cmd e ( &&) sairá com a /bcondição de manter a janela aberta (a saída é para que ele não continue a executar seu script no contexto da primeira instância do cmd, com echo expansão atrasada).

desgrudar
fonte
Para isso, a execução de arquivos em lote com cmd /q /v on /c <filename>deve contar apenas como 2 bytes, porque são dois "sinalizadores" semelhantes aos sinalizadores Perl, como os -pIque contariam apenas como 2 bytes extras.
Artyer
1

Sequências repetitivas

Defina blocos de código repetitivo em variáveis, em que o número de bytes usados ​​para definir a variável + o número de bytes para gerar a variável são menores que o número de bytes para chamar apenas o código diretamente.

Por exemplo, consulte: Desenhe as combinações que somam até 100

Você salva 1 byte por uso do comando set, se criar uma variável (nomeada com um caractere, como "s") que contenha set<space>. Isso gera valor apenas se você usar o comando set mais de 12 vezes. (Observe que há um caractere no final da string 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

O acima é 1 byte menor 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

Provavelmente, este é um exemplo muito ruim - mas é claro.

desgrudar
fonte
1

Início de uma string

A notação %var:~start,end%extrai uma substring da variável var. No entanto, se startfor 0, você pode omiti-lo completamente. Já sabemos que você pode omitir ,endse quiser o restante da string, o que faz com que seja %var:~%um sinônimo quase inútil %var%, exceto que ele retorna ~quando %var%está vazio. (Talvez você possa usá-lo em um teste if %var:~%==~:?)

Neil
fonte
Eu gosto da sua última frase nos lembrando que isso economizará algumas citações :) +1 para isso.
Stevefestl
1

Encurtando IF EQUdeclarações

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

Usar em ==vez de equ salva 3 bytes.


Encurtar citações em IFdeclarações

Essa é uma comparsão tradicional chamada "mais segura" if.

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

Para encurtar esta declaração, faça o seguinte quando a entrada puder ser apenas alfanumérica / vazia :

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

Salvando um total de 2 bytes.


Desafios que exigem resultados

Se a pergunta disser algo como:

Produz pelo menos 1 caractere visível.

então você poderia fazer isso:

cd

O cdmostra o diretório atual para STDOUT.


GOTOum rótulo

Aqui estão alguns métodos para gotoinserir um rótulo, ordenados em ordem decrescente de bytes.

goto :l
goto l
goto:l

O método acima salva 1 byte.

stevefestl
fonte
1
Alternativamente, você pode fazer goto:lo que economiza o mesmo 1 byte e tem a vantagem adicional de manter seu cólon intacto
Matheus Avellar
@ MatheusAvellar: Adicionei o conteúdo de acordo com o seu comentário
stevefestl 13/09/17
1

Omitindo espaço entre comando e parâmetros com barras

Desculpe pelo título pouco informativo. O que estou tentando entender é que, para alguns (não todos) comandos do Windows, você pode omitir o espaço entre o nome do comando / programa e o parâmetro, desde que esse parâmetro comece com uma barra. Por exemplo:

for /f %%G in ...

torna-se

for/f %%G in ...

-1 Byte!

Saída da tubulação em vez de usar ERRORLEVEL

Usar ERRORLEVEL para determinar se um comando foi executado corretamente não é o método mais curto ou mais elegante. Em vez disso, você pode canalizar a saída. Isso funciona da seguinte maneira (lembre-se de que qualquer comando após o &&operador é executado apenas se o comando for &&executado sem erros. Qualquer comando após o ||operador, por outro lado, será executado apenas se o comando antes NÃO for executado corretamente. Meu exemplo é :

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

Isso pode ser substituído por:

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

-26 Bytes, uau! Observe que isso não funciona com comandos como choice, onde ERRORLEVEL possui um valor especial de acordo com alguma entrada.

Atenciosamente,
Gabe

Gabriel Mills
fonte
1

Usando parênteses efetivamente

Oi de novo,

Desculpe postar uma segunda resposta, mas achei que essa merecia. Percebi que as pessoas costumam usar um dos métodos a seguir para exibir a saída do comando sem exibir a C:\Windows\System32>echo foolinha traquina antes de cada comando.
O primeiro método (usando echo off):

@echo off
echo foo
echo bar
echo foobar
echo barfoo

O segundo método:

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

No entanto, nenhum desses métodos é tão curto quanto o seguinte:

@(echo foo
echo bar
echo foobar
echo barfoo)

Muito útil, certo? Em outra nota, isso pode ser usado para canalizar várias linhas de saída para um arquivo ou dispositivo facilmente. Por exemplo, este código longo:

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

torna-se significativamente mais curto:

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

Obrigado por ler esta resposta bastante longa, e espero que isso ajude você. Atenciosamente,
Gabe

Gabriel Mills
fonte
Postar várias respostas para perguntas de dicas não é ruim.
Erik the Outgolfer