Dicas para jogar golfe em Lua

21

Que dicas gerais você tem para jogar golfe em Lua? Estou procurando idéias que possam ser aplicadas para codificar problemas de golfe em geral que sejam pelo menos um pouco específicos para Lua (por exemplo, "remover comentários" não é uma resposta). Poste uma dica por resposta.

scheurneus
fonte
6
Perguntas sobre dicas devem ser wiki da comunidade. Mas para quem enviou isso de perto como "principalmente baseado em opiniões", as perguntas sobre Dicas de golfe no idioma são nossa exceção aceita a essa regra. A natureza aberta dessas perguntas é por que elas são publicadas na comunidade.
Jonathan Van Matre

Respostas:

9

Além dos já publicados, eis alguns truques que reuni ao longo do tempo, sem ordem específica ...

  • Para as chamadas de função que possuem apenas um parâmetro delimitado por um símbolo ( "para strings, {para tabelas), o parâmetro não precisa ser colocado entre parênteses.
    Por exemplo, em vez de fazer print("hello"), você pode simplesmente fazer:print"hello"

  • Remova o máximo de espaço em branco possível - isso é especialmente fácil de fazer depois de um símbolo que fecha seqüências de caracteres (ou antes de uma abertura), chamadas de função, tabelas ...
    Em vez de print(42) a=1você pode fazer print(42)a=1. Outro exemplo: print(a and-1 or-2).

  • Use o operador ternário quando puder! Em vez de if a>0 then print("hello") else print("goodbye") end, prefira print(a>0 and "hello" or "goodbye"). Mais informações aqui .
    (Isso pode ficar ainda melhor print(a>0 and"hello"or"goodbye"):)

  • Use o açúcar sintático chamado cólon quando puder: em vez de string.rep(str,12), faça str:rep(12). Isso também funciona em não variáveis ​​desta maneira (e somente dessa maneira):("a"):rep(5)

  • Em vez de fazer tonumber(str)apenas façastr+0

  • Para funções sem parâmetros, em vez de defini-las da maneira usual ( function tick() blabla() end), você pode fazer ticks=loadstring"blabla()":, que salva 1 ou mais bytes, dependendo do conteúdo. Além disso, se você definir várias funções, localize loadstringantes uma variável de 1 caractere e economize muitos bytes;). Créditos a Jim Bauwens por esse truque.

  • Lua considera a string vazia (e 0muito diferente de outras linguagens) como verdadeira em testes condicionais; portanto, por exemplo, em vez de fazê-lo while 1 do ... end, salve 1 byte escrevendowhile''do ... end

Adriweb
fonte
(Adicionado o truque loadstring)
Adriweb
2
0 sendo um valor truthy é bobagem
SuperJedi224
outra str+0equivalente ~~str, pode ser útil para a sua precedência
Felipe Nardi Batista
@FelipeNardiBatista, no entanto, isso é suportado apenas no Lua 5.3+
Adriweb 15/17
5

Eu já pensei em um. Não sei se funciona em outras línguas, mas Lua é a única que sei o que permite armazenar funções em variáveis. Portanto, se eg string.subfor usado várias vezes em seu programa, use eg s=string.sub.

scheurneus
fonte
4
Também funciona em muitas outras linguagens, como Python e Ruby.
precisa saber é o seguinte
4
Javascript e Haskell também podem ter valores de função.
proud haskeller
Isso é equivalente a s=("").subou s=a.subpara qualquer variável que acontém o valor da sequência.
Egor Skriptunoff
Isso é chamado de funções de primeira classe
Programas Redwolf
5

É uma linguagem bastante detalhada para o golfe ... mas algumas dicas gerais que vêm à mente são:

  • Tente evitar condicionais, já que if... then... else... endé um grande desperdício.
  • Em vez disso, tente se concentrar em construções de linguagem mais curtas, por exemplo for i=1,5 do.
  • O #operador é ótimo para jogar golfe (e em geral).
Tal
fonte
5

Encurte seu loop infinito

Quando você precisa usar um loop infinito, pode pensar em usar a while, mas o uso de um rótulo é menor em 2 bytes:

while''do end
::a::goto a

Use o menor espaço possível

Há uma coisa simples que você pode (ab) usar para remover ainda mais espaços do seu código. As especificações de Lua são claras sobre o nome que você atribui às variáveis: elas precisam começar com uma letra. Isso implica que, às vezes, você pode pular espaços entre números e funções / variáveis

x=0>1 and 0or 1print(x)

A possibilidade de remover o espaço depende da letra após o número, aqui está a letra que não permitirá que você faça isso:

a,b,c,d,e,f            -- They would be interpreted as hexadecimal
x                      -- only fail when after a 0, other number are fine
                       -- (0x indicates the following is an hexadecimal number)

Ao usar isso e prestar atenção em como você chama suas variáveis, você pode tornar a maioria dos seus códigos-fonte sem espaço.

Pegando um exemplo já aqui, e usando este conselho, aqui está mais um byte que você pode raspar :).

print(a and-1 or-2)
print(a and-1or-2)

Use o método de entrada correto

Se olharmos para o padrão e o custo de cada tipo principal de entrada, eis o que temos:

function f(x)x end
io.read()
arg[1]

Cada um desses métodos nos permite obter 1 entrada, com a função com o custo mais alto (mas nos permite tomar uma tabela como entrada)

Agora podemos ver que o uso do argumento da linha de comando é o caminho a seguir, se você deseja jogar golfe, mas esteja ciente: ele pode ser ainda mais curto

arg[1]
...

Eles ...são um pouco especiais em lua, é uma variável que contém o conteúdo descompactado de argou os parâmetros descompactados no caso de uma função variável .

Quando você precisar obter mais de uma entrada e usar cada uma delas, pode ser bom salvá-las em uma variável. Aqui estão algumas maneiras de salvar 2 entradas em variáveis

a=arg[1]b=arg[2]    -- highly un-efficient, costs 8 bytes by variable
a,b=unpack(arg)     -- costs 15, but at least doesn't depends on the number of argument
a,b=...             -- only costs 7

e aqui está a chamada mais curta que você poderia ter feito sem as variáveis:

...     -- using a allow a gain of 1-2 bytes at each use
arg[2]  -- using b allow a gain of 4-5 bytes at each use

Do ponto em que você tem 3 argumentos, ou quando você usa 2 argumentos, com um usado duas vezes, você já está ganhando bytes devido a a,b=...! :)

Quase nunca use se!

Quase não há casos em que o uso de uma instrução if / elseif / if custará menos que um ternário. o padrão para essa afirmação é realmente pesado:

-- exemple with dumb values
if 1>0then v=1 else v=0 end
v=1>0 and 1or 0

Com um exemplo simples, você já salva 12 bytes; quando precisar fazer outras coisas, isso se tornará cada vez mais importante; portanto, esteja ciente disso!

Além disso, os ternários em lua são especiais , há alguma condição em como eles funcionam, para os interessados, explicarei abaixo:

Os ternários em lua têm a forma <condition> and <case true: have to be a true value> or <case false: can be anything>

Primeiro de tudo, vamos ver a tabela verdade do or. A orpode ser considerado como uma função: sempre retorna um valor, eis o valor que retorna:

x | y ||x or y
------||-------
0 | 0 ||   y
0 | 1 ||   y
1 | 0 ||   x
1 | 1 ||   x

Isso é o que nos permite construir nosso ternário.

O andé o que nos permite avaliar a condição, ele sempre retornará yse x and yavalia a verdade.

O problema com ele é que ele irá falhar se queremos uma nilou falseestar de retorno quando a condição é false. Por exemplo, o seguinte sempre retornará 5, apesar da condição ser verdadeira.

v = true and false or 5

Aqui está uma avaliação passo a passo de um ternário para explicar como ele funciona (será útil quando você precisar aninhar :))

-- let's use our dumb ternary
= true and false or 5
-- and statement will be evaluated first, leading to
= false or 5
-- and we saw how the or works
= 5
Katenkyo
fonte
Uma dica por resposta, por favor.
ATaco
Observe que o truque "Use o menor espaço possível" funciona apenas no Lua 5.2 e posterior.
Adriweb
4

Eu compilei várias dicas também. Tenho certeza de que alguns dos meus se sobrepõem aos já declarados, mas os incluirei de qualquer maneira na veia de criar uma resposta mais completa.


Atribuir funções repetidas a variáveis

Lua permite atribuir funções a variáveis. Variáveis ​​de um caractere. Isso significa que se você repetir a função string.sub(x, y)mais de duas vezes, será beneficiado com a atribuição a uma variável.

Sem atribuir a uma variável (69 caracteres):

print(string.sub(x, y))
print(string.sub(x, y))
print(string.sub(x, y))

Atribuindo a uma variável (51 caracteres):

s=string.sub
print(s(x,y))
print(s(x,y))
print(s(x,y))

Há casos em que você pode levar isso adiante ainda mais. Lua permite que um OOP manipule string, da seguinte forma: str:sub(x, y)ou str.sub(x, y)Isso abre novas opções para o nosso código. Você pode atribuir uma variável à função por sua referência, como mostrado (46 caracteres).

s=z.sub
print(s(x, y))
print(s(x, y))
print(s(x, y))

Use a maneira mais eficiente de analisar seqüências de caracteres

Você pode se encontrar usando um forloop e string.subiterar caractere por caractere em Lua. Às vezes, isso pode funcionar melhor, dependendo de suas necessidades, mas outras vezes, string.gmatch funcionará com menos caracteres. Aqui está um exemplo de ambos:

s=io.read()
for a = 1, s:len() do
    print(s:sub(a, a))
end 

for i in io.read():gmatch('.') do
    print(i)
end

E quando jogado, a diferença é mais notável:

s=io.read()for a=1,s:len()do print(s:sub(a, a))end

for i in io.read():gmatch'.'do print(i)end

Reestruturar atribuições para otimizar espaço em branco

Em Lua, você não precisa colocar um caractere de espaço entre parênteses fechados ou aspas finais e o próximo caractere. Até agora, encontrei dois casos em que a reestruturação com isso em mente cortará caracteres.

  • Atribuindo variáveis:

     x,y=io.read(),0 print(x)
     vs.
     y,x=0,io.read()print(x)
    
  • Declarações If:

     if x:sub(1,1)==1 then
     vs
     if 1==x:sub(1,1)then
    

Retorne o menor número possível de caracteres

Se você deve retornar um valor verdadeiro ou falso, parece que você deve necessariamente usar pelo menos 5 caracteres para o valor de retorno. Na realidade, o seguinte também funciona:

return true
return false
vs
return 1>0
return 0>1
Skyl3r
fonte
Ótimas dicas, tomei a liberdade de sugerir uma edição em sua postagem. Apenas nile falseavalia a falsa na lua, tudo o resto é verdadeiro, assim que suas dicas sobre a substituição x==0, x==""e x==''por xé falsa. Atualmente, estou mudando para nil:).
Katenkyo
Ah, você está certo. Obrigado por corrigir isso!
Skyl3r
2

Estas são apenas otimizações de Lua (eu acho):

As strings são convertidas automaticamente em números ao executar operações aritméticas nelas. Cuidado com as declarações condicionais, elas não são convertidas automaticamente. Isso é ótimo para receber a entrada do usuário como números e economizar espaço.

Mudar o conteúdo de duas variáveis ​​não requer uma variável temporária. a,b=b,atrocará os valores de a e b.

Além disso, para estender o que foi dito acima, qualquer caractere alfanumérico pode tocar em um caractere não alfanumérico. Então, a,b=io.read():match"(.+)/(.+)"u,v=a,bé um script perfeito e funcional, mesmo com a falta de espaço em branco.

Dwayne Slater
fonte
2

Combinar atribuições de variáveis ​​locais

Ao invés de:

local a=42
local b=17
local c=99

Use atribuição paralela:

local a,b,c=42,17,19

6 bytes salvos para cada variável!

Declarar variáveis ​​locais por meio de parâmetros de função não utilizados

Ao invés de:

function foo(a,b) local c,d ... end
function bar(a,b) local c,d=42,17 ... end

Usar

function foo(a,b,c,d) ... end
function bar(a,b,c,d) c,d=42,17 ... end

6 bytes salvos (menos 1-2 bytes para cada variável que pode ser duplicada).

Phrogz
fonte
11
Diminuiu a votação porque não há absolutamente nenhum caso em que o uso localseja justificado ao jogar golfe, porque você só precisa usar um nome diferente. Nós poderíamos usar todos os nomes até 7 charachters e tabelas com índices de cordas até 7 charachters combinações antes estamos atingindo algo que poderia beneficiar do uso de habitantes locais
Katenkyo
1

Funções Variadic

A principal função variável que o incomodará é print(). Por exemplo, quando você o usa, String.gsub()imprime a string que você modificou E o número de vezes que foi gsubacionado.

Para suprimir essa segunda saída, encapsule seu gsubparens para forçá-lo a retornar apenas um valor

print(String.gsub("aa",".","!"))    -- outputs "!!    2\n"
print((String.gsub("aa",".","!")))  -- outputs "!!\n"
Katenkyo
fonte
1

Saiba como produzir

Existem dois métodos principais de saída em lua

io.write()    -- outputs without trailing newline
print()       -- outputs with trailing new line and shorter by 3 bytes

Quando você precisar concatenar várias vezes, poderá reduzi-lo usando o io.write()atribuído a uma variável de uma letra em vez do operador de concatenação padrão..

i(a)    -- i was defined as io.write
s=s..a

Você ganha 2 bytes em cada chamada enquanto paga antecipadamente

i=io.write  -- longer by 6 bytes
s=""

Você está na terceira concatenação e começa a ganhar byte na quarta.

Katenkyo
fonte
3
É printe não printf!
val diz Reinstate Monica
@ Val Wow, eu nem sei como eu poderia cometer esse erro. Obrigado por apontar, eu vou editar
Katenkyo 29/10
1

Um monte de dicas em nenhuma ordem específica:

  • stringé um nome bastante longo. Eficientemente, ('').charé o mesmo que string.char. Resultados ainda melhores podem ser alcançados se você o usar em conjunto com um ponto-e-vírgula nas variáveis:, a=...; print(a:sub(1, 5))mas algumas stringfunções não recebem seqüências de caracteres como entrada.
  • Lua tem conversões automáticas entre seqüências de caracteres e números na maioria dos casos, tonumbere +0muitas vezes desperdiçam apenas bytes.
  • Sempre use em load'your function code here'vez de function()your function code here end. Acesse argumentos de função usando ...inside.
  • Algumas funções de string em Lua podem ser usadas de maneiras não intencionais! Por exemplo, a:gsub('.',load'my function')parece ser a maneira mais curta de iterar sobre caracteres em uma string
  • Enquanto o mecanismo de cordas é poderoso, tome cuidado com seu poder ao usar a entrada do usuário como padrões! Por esse motivo, você pode precisar usar a:find('.',1,1)(para testar esse problema, tente incluir %em vários locais da sua entrada e verificar os resultados). Inúmeras idéias quebraram por causa de Lua tentando analisar as entradas como padrão.
  • niltem três bytes, _é um (é apenas um nome aleatório que provavelmente não existe). Além disso, qualquer dígito funcionará como um valor verdadeiro.
  • Conheça a sua lógica por trás x and i or o. Não é apenas um operador ternário - é uma expressão lógica completa. De fato, significa o seguinte: "se xfor verdade, tente i. Se x ou i for falso, retorne o". Portanto, se inão for verdade, o resultado será o. Além disso, ambas andou orpartes podem ser omitidas ( x and i, x or o).
  • Use divisão inteira por uma vez de math.floor: 5.3//1==5.0. Observe que o número resultante sempre segue o tipo de entrada um (inteiro / flutuante).
val diz Reinstate Monica
fonte
11
"Além disso, qualquer dígito funcionará como um valor verdadeiro." Só queria esclarecer que isso inclui 0, o que pode não ser muito intuitivo para alguns codificadores com experiência em C / C ++.
ouflak 30/10