Consejos para jugar golf en Lua

21

¿Qué consejos generales tienes para jugar al golf en Lua? Estoy buscando ideas que se puedan aplicar a los problemas de golf de código en general que sean al menos algo específicos para Lua (por ejemplo, "eliminar comentarios" no es una respuesta). Por favor, publique un consejo por respuesta.

Scheurneus
fuente
66
Las preguntas sobre consejos deberían ser wiki de la comunidad. Pero para quien haya presentado esto para cerrarlo como "principalmente basado en opiniones", las sugerencias de Consejos para jugar golf en el idioma son nuestra excepción aceptada a esa regla. La naturaleza abierta de estas preguntas es por qué son wiki de la comunidad.
Jonathan Van Matre

Respuestas:

9

Además de los ya publicados, aquí hay algunos trucos que he reunido con el tiempo, sin ningún orden específico ...

  • Para las llamadas a funciones que solo tienen un parámetro delimitado por un símbolo ( "para cadenas, {para tablas), el parámetro no necesita estar entre paréntesis.
    Por ejemplo, en lugar de hacerlo print("hello"), simplemente puede hacer:print"hello"

  • Elimine la mayor cantidad de espacio en blanco posible: esto es especialmente fácil de hacer después de un símbolo que cierra cadenas (o antes de una apertura), llamadas a funciones, tablas ...
    En lugar de print(42) a=1hacerlo, puede hacerlo print(42)a=1. Otro ejemplo: print(a and-1 or-2).

  • ¡Usa el operador ternario cuando puedas! En lugar de if a>0 then print("hello") else print("goodbye") end, prefiera print(a>0 and "hello" or "goodbye"). Más información aquí .
    (En realidad, esto puede ser aún mejor: print(a>0 and"hello"or"goodbye"))

  • Use el azúcar sintáctico de dos puntos cuando pueda: en lugar de string.rep(str,12)hacerlo str:rep(12). Eso también funciona en no variables de esta manera (y solo de esta manera):("a"):rep(5)

  • En lugar de hacer tonumber(str)solo hazstr+0

  • Para funciones sin parámetros, en lugar de definirlas de la manera habitual ( function tick() blabla() end), puede hacer:, ticks=loadstring"blabla()"que ahorra 1 o más bytes, dependiendo del contenido. Además, si define varias funciones, localice loadstringantes una variable de 1 carácter y ahorrará muchos bytes;). Créditos a Jim Bauwens por este truco.

  • Lua considera la cadena vacía (y 0muy diferente a otros idiomas) como verdadera en las pruebas condicionales, por lo que, por ejemplo, en lugar de hacerlo while 1 do ... end, guarde 1 byte escribiendowhile''do ... end

Adriweb
fuente
(Se agregó el truco de la cadena de carga)
Adriweb
2
0 ser un valor verdadero es una tontería
SuperJedi224
otro str+0equivalente es ~~str, puede ser útil por su precedencia
Felipe Nardi Batista
@FelipeNardiBatista, sin embargo, eso solo es compatible con Lua 5.3+
Adriweb
5

Ya he pensado en uno. No sé si funciona en otros idiomas, pero Lua es el único que sé que le permite almacenar funciones en variables. Entonces, si eg string.subse usa varias veces en su programa, use eg s=string.sub.

Scheurneus
fuente
44
También funciona en muchos otros idiomas, como Python y Ruby.
nyuszika7h
44
Javascript y Haskell también pueden tener valores de función.
orgulloso haskeller
Esto es equivalente s=("").subao s=a.subpara cualquier variable que acontenga un valor de cadena.
Egor Skriptunoff
Esto se llama funciones de primera clase
Programas Redwolf
5

Es un lenguaje bastante detallado para el golf ... pero algunos consejos generales que vienen a la mente son:

  • Trate de evitar los condicionales, ya que if... then... else... endes un desperdicio importante.
  • En cambio, trate de enfocarse en construcciones de lenguaje que sean más cortas, por ejemplo for i=1,5 do.
  • El #operador es bastante bueno para jugar al golf (y en general).
Tal
fuente
5

Acorta tu ciclo infinito

Cuando tiene que usar un bucle infinito, puede pensar en usar a while, pero usar una etiqueta en su lugar es más corto en 2 bytes:

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

Usa el menor espacio posible

Hay una cosa simple que podría (ab) usar para eliminar aún más espacios de su código. Las especificaciones de Lua son claras sobre el nombre que le das a las variables: tienen que comenzar con una letra. Implica que, a veces, puede omitir espacios entre números y funciones / variables

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

La posibilidad de eliminar el espacio depende de la letra que sigue al número, aquí está la letra que no le permitirá hacer esto:

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)

Al usar esto y prestar atención a cómo llama a sus variables, puede hacer que la mayoría de sus códigos fuente estén libres de espacio.

Tomando un ejemplo que ya está aquí, y siguiendo este consejo, aquí hay un byte más que podría eliminar :).

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

Use el método de entrada correcto

Si observamos el estándar y el costo de cada tipo principal de entrada, esto es lo que tenemos:

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

Cada uno de este método nos permite tomar 1 entrada, siendo la función la que tiene el costo más alto (pero nos permite tomar una tabla como entrada)

Ahora podemos ver que usar el argumento de la línea de comandos es el camino a seguir si desea jugar al golf, pero tenga en cuenta: puede ser aún más corto

arg[1]
...

El ...son un poco especial en Lua, que es una variable que contiene el contenido descomprimido del argo los parámetros descomprimidos en caso de una función variadic.

Cuando tenga que obtener más de una entrada y usar cada una de ellas, puede ser bueno guardarlas en una variable. Aquí hay algunas formas de guardar 2 entradas en variables

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

y aquí están las llamadas más cortas que podrías haber hecho sin las variables:

...     -- 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

Desde el punto donde tiene 3 argumentos, o cuando usa 2 argumentos, con uno usado dos veces, ¡ya está ganando bytes debido a a,b=...! :)

Casi nunca uso si!

Casi no hay casos en los que el uso de una declaración if / elseif / if cueste menos que un ternario. La base para tal afirmación es realmente pesada:

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

Con un ejemplo simple, ya guarda 12 bytes, cuando tiene que hacer otras cosas, se vuelve cada vez más importante, ¡así que tenga en cuenta eso!

Además, los ternaries en lua son especiales , hay alguna condición en su funcionamiento, para los interesados, lo explicaré a continuación:

Los ternarios en lua son de la forma <condition> and <case true: have to be a true value> or <case false: can be anything>

En primer lugar, veamos la tabla de verdad de or. A orse puede considerar como una función: siempre devuelve un valor, aquí está el valor que devuelve:

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

Eso es lo que nos permite construir nuestro ternario.

El andes lo que nos permitirá evaluar la condición, siempre devolverá ysi x and yse evalúa como TRUE.

El problema con esto es que fallará si queremos que se devuelva un nilo falsecuando la condición sea false. Por ejemplo, lo siguiente siempre devolverá 5, a pesar de que la condición sea verdadera.

v = true and false or 5

Aquí hay una evaluación paso a paso de un ternario para explicar cómo funciona (será útil para cuando tenga que anidarlos :))

-- 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
fuente
Un consejo por respuesta, por favor.
ATaco
Tenga en cuenta que el truco "Usar el menor espacio posible" solo funciona en Lua 5.2 y versiones posteriores.
Adriweb
4

He compilado varios consejos también. Estoy seguro de que algunos de los míos se superpondrán con los ya mencionados, pero los incluiré de todos modos para crear una respuesta más completa.


Asigna funciones repetidas a variables

Lua le permite asignar funciones a variables. Incluso las variables de un personaje. Esto significa que si repite la función string.sub(x, y)más de dos veces, obtendrá un beneficio al asignarla a una variable.

Sin asignar a una variable (69 caracteres):

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

Asignación a una variable (51 caracteres):

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

Hay casos en los que puedes llevar esto un paso más allá. Lua permite que una OOP manipule cadenas, de esta manera: str:sub(x, y)o str.sub(x, y)Esto abre nuevas opciones para nuestro código. Puede asignar una variable a la función por su referencia como se muestra (46 caracteres).

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

Use la forma más eficiente de analizar cadenas

Puede encontrarse utilizando un forbucle e string.subiterar carácter por carácter en Lua. A veces esto puede funcionar mejor, dependiendo de sus necesidades, pero otras veces, string.gmatch funcionará en menos caracteres. Aquí hay un ejemplo 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

Y cuando se juega al golf, la diferencia es más notable:

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

Reestructurar asignaciones para optimizar espacios en blanco

En Lua, no tiene que poner un carácter de espacio entre paréntesis cerrados o una comilla final y el siguiente carácter. Hasta ahora, he encontrado dos casos en los que la reestructuración con esto en mente reducirá los caracteres.

  • Asignación de variables:

     x,y=io.read(),0 print(x)
     vs.
     y,x=0,io.read()print(x)
    
  • Si declaraciones:

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

Devuelve la menor cantidad de caracteres posible

Si debe devolver un valor verdadero o falso, entonces parece que necesariamente debe usar al menos 5 caracteres para el valor devuelto. En realidad, lo siguiente funciona igual de bien:

return true
return false
vs
return 1>0
return 0>1
Skyl3r
fuente
Grandes consejos, me tomé la libertad de sugerir una edición a su publicación. Sólo nily falsese evalúa como falsa en lua, todo lo demás es cierto, por lo que sus consejos acerca de reemplazar x==0, x==""y x==''por xes falsa. Actualmente lo estoy cambiando a nil:).
Katenkyo
Ah, tienes razón. ¡Gracias por arreglar eso!
Skyl3r
2

Estas son solo optimizaciones de Lua (creo):

Las cadenas se convierten automáticamente en números cuando se realizan operaciones aritméticas en ellas. Solo ten cuidado con las declaraciones condicionales, no se convierten automáticamente. Esto es excelente para tomar la entrada del usuario como números mientras ahorra espacio.

Cambiar el contenido de dos variables no requiere una variable temporal. a,b=b,aintercambiará los valores de a y b.

Además, para ampliar lo que se dijo anteriormente, cualquier carácter alfanumérico puede tocar un carácter no alfanumérico. Por a,b=io.read():match"(.+)/(.+)"u,v=a,blo tanto, es un script perfecto y funcional, incluso con la falta de espacios en blanco.

Dwayne Slater
fuente
2

Combinar asignaciones de variables locales

En lugar de:

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

Usar asignación paralela:

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

¡6 bytes guardados para cada variable!

Declarar variables locales a través de parámetros de función no utilizados

En lugar de:

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

Utilizar

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

6 bytes guardados (menos 1-2 bytes por cada variable que pueda estar duplicada).

Phrogz
fuente
1
Votaron en contra porque no hay absolutamente ningún caso en el que el uso localesté justificado al jugar al golf, porque solo tienes que usar un nombre diferente. Podríamos usar TODOS los nombres de hasta 7 caracteres Y tablas con índices de cadena de hasta 7 combinaciones de caracteres antes de llegar a algo que podría beneficiarse con el uso de locales
Katenkyo
1

Funciones Variadas

La función variadic principal que te molestará es print(). Por ejemplo, cuando lo esté utilizando String.gsub(), imprimirá la cadena que modificó Y la cantidad de veces que se gsubactivó.

Para suprimir esa segunda salida, encapsule su gsuben parens para forzarlo a devolver solo un valor

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

Sepa como salida

Hay dos métodos principales de salida en lua

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

Cuando tiene que concatenar varias veces, puede acortar eso mediante el uso io.write()asignado a una variable de una letra en lugar del operador de concatenación estándar..

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

Ganas 2 bytes en cada llamada mientras pagas por adelantado

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

Incluso estás en la tercera concatenación y comienzas a ganar byte en la cuarta.

Katenkyo
fuente
3
Es printy no printf!
Val dice reinstalar a Monica el
@val Wow, ni siquiera sé cómo podría cometer ese error. Gracias por señalarlo,
editaré
1

Un montón de consejos sin ningún orden en particular:

  • stringEs un nombre bastante largo. Eficientemente, ('').chares lo mismo que string.char. Se pueden lograr resultados aún mejores si lo usa junto con un punto y coma en las variables a=...; print(a:sub(1, 5)), pero algunas stringfunciones no toman cadenas como entrada.
  • Lua tiene conversión automática entre cadenas y números para la mayoría de los casos, por lo que tonumber, y +0a menudo sólo perder bytes.
  • Siempre use en load'your function code here'lugar de function()your function code here end. Acceder a argumentos de la función utilizando ...inside.
  • ¡Algunas funciones de cadena en Lua se pueden usar de manera no deseada! Por ejemplo, a:gsub('.',load'my function')parece ser la forma más corta de iterar sobre caracteres en una cadena
  • Si bien el motor de cadenas es potente, ¡tenga cuidado con su potencia cuando use la entrada del usuario como patrones! Debido a eso, es posible que tenga que usar a:find('.',1,1)(para probar este problema, intente incluir %en varios lugares en su entrada y verifique los resultados). Innumerables ideas se rompieron debido a que Lua intentó analizar la entrada como patrón.
  • niles de tres bytes, _es uno (es solo un nombre aleatorio que probablemente no existe). Además, cualquier dígito funcionará como valor verdadero.
  • Conoce tu lógica detrás x and i or o. No es solo un operador ternario, es una expresión lógica completa. De hecho, significa lo siguiente: "si xes verdadero, intente i. Si x o i es falso, devuelva o". Entonces, si ino es verdad, el resultado sí lo es o. Además, se pueden omitir ambas ando orpartes ( x and i, x or o).
  • Uso división entera por uno en lugar de math.floor: 5.3//1==5.0. Tenga en cuenta que el número resultante siempre sigue el tipo de entrada uno (entero / flotante).
val dice reinstalar a Monica
fuente
1
"Además, cualquier dígito funcionará como valor verdadero". Solo quería explicar que esto incluye 0, que podría no ser muy intuitivo para algunos codificadores de un fondo C / C ++.
ouflak