Conseils pour jouer au golf à Lua

21

Quels conseils avez-vous pour jouer au golf à Lua? Je recherche des idées qui peuvent être appliquées aux problèmes de golf de code en général qui sont au moins quelque peu spécifiques à Lua (par exemple, "supprimer les commentaires" n'est pas une réponse). Veuillez poster un pourboire par réponse.

scheurneus
la source
6
Les questions sur les astuces doivent être wiki communautaire. Mais pour quiconque a soumis cela comme proche de "principalement basé sur l'opinion", les conseils pour le golf dans la langue sont notre exception acceptée à cette règle. La nature ouverte de ces questions explique pourquoi elles sont rédigées sur un wiki communautaire.
Jonathan Van Matre

Réponses:

9

En plus de ceux déjà publiés, voici quelques astuces que j'ai rassemblées au fil du temps, sans ordre précis ...

  • Pour les appels de fonction qui n'ont qu'un seul paramètre délimité par un symbole ( "pour les chaînes, {pour les tables), le paramètre n'a pas besoin d'être entouré de parenthèses.
    Par exemple, au lieu de le faire print("hello"), vous pouvez simplement faire:print"hello"

  • Supprimez autant d'espaces que possible - cela est particulièrement facile à faire après un symbole qui ferme des chaînes (ou avant une ouverture), des appels de fonction, des tableaux ...
    Au lieu de cela, print(42) a=1vous pouvez le faire print(42)a=1. Autre exemple: print(a and-1 or-2).

  • Utilisez l'opérateur ternaire quand vous le pouvez! Au lieu de if a>0 then print("hello") else print("goodbye") end, préférez print(a>0 and "hello" or "goodbye"). Plus d'infos ici .
    (Cela peut effectivement faire encore mieux: print(a>0 and"hello"or"goodbye"))

  • Utilisez le sucre syntaxique d'appel du côlon lorsque vous le pouvez: au lieu de string.rep(str,12), faites str:rep(12). Cela fonctionne également sur les non-variables de cette façon (et uniquement de cette façon):("a"):rep(5)

  • Au lieu de faire tonumber(str)simplementstr+0

  • Pour les fonctions sans paramètres, au lieu de les définir de la manière habituelle ( function tick() blabla() end), vous pouvez faire ticks=loadstring"blabla()":, qui enregistre 1 ou plusieurs octets, selon le contenu. De plus, si vous définissez plusieurs fonctions, localisez loadstringune variable à 1 caractère avant et vous économiserez beaucoup d'octets;). Crédits à Jim Bauwens pour cette astuce.

  • Lua considère la chaîne vide (et 0trop contrairement aux autres langues) comme vraie dans les tests conditionnels, donc, par exemple, au lieu de le faire while 1 do ... end, économisez 1 octet en écrivantwhile''do ... end

Adriweb
la source
(Ajout de l'astuce loadstring)
Adriweb
2
0 étant une valeur véridique est tout simplement stupide
SuperJedi224
un autre str+0équivalent est ~~str, peut être utile pour sa priorité
Felipe Nardi Batista
@FelipeNardiBatista cependant, cela n'est pris en charge que sur Lua 5.3+
Adriweb
5

J'en ai déjà pensé un. Je ne sais pas si cela fonctionne dans d'autres langages, mais Lua est le seul que je connaisse qui vous permet de stocker des fonctions dans des variables. Donc si eg string.subest utilisé plusieurs fois dans votre programme, utilisez eg s=string.sub.

scheurneus
la source
4
Il fonctionne également dans de nombreux autres langages tels que Python et Ruby.
nyuszika7h
4
Javascript et Haskell peuvent également avoir des valeurs de fonction.
fier haskeller
Cela équivaut à s=("").subou s=a.subpour toute variable acontenant une valeur de chaîne.
Egor Skriptunoff du
C'est ce qu'on appelle des fonctions de première classe
Programmes Redwolf
5

C'est un langage assez verbeux pour le golf ... mais quelques conseils généraux qui me viennent à l'esprit sont:

  • Essayez d'éviter les conditions, car if... then... else... endest un gaspillage majeur.
  • Essayez plutôt de vous concentrer sur des constructions de langage plus courtes, par exemple for i=1,5 do.
  • L' #opérateur est assez bon pour le golf (et en général).
Tal
la source
5

Raccourcissez votre boucle infinie

Lorsque vous devez utiliser une boucle infinie, vous pouvez penser à utiliser un while, mais l'utilisation d'une étiquette à la place est plus courte de 2 octets:

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

Utilisez le moins d'espace possible

Il y a une chose simple que vous pourriez (ab) utiliser pour supprimer encore plus d'espaces de votre code. Les spécifications de Lua sont claires sur le nom que vous donnez aux variables: elles doivent commencer par une lettre. Cela implique que, parfois, vous pouvez sauter des espaces entre les nombres et les fonctions / variables

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

La possibilité de supprimer l'espace dépend de la lettre qui suit le chiffre, voici la lettre qui ne vous permettra pas de faire ceci:

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)

En l'utilisant et en prêtant attention à la façon dont vous appelez vos variables, vous pouvez libérer la plupart de vos codes source sans espace.

Reprenant un exemple déjà ici, et en utilisant ce conseil, voici un octet de plus que vous pouvez raser :).

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

Utilisez la bonne méthode de saisie

Si nous regardons le passe-partout et le coût pour chaque type principal d'entrée, voici ce que nous avons:

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

Chacune de cette méthode nous permet de prendre 1 entrée, la fonction étant celle qui a le coût le plus élevé (mais nous permet de prendre un tableau en entrée)

Nous pouvons maintenant voir que l'utilisation de l'argument de ligne de commande est la voie à suivre si vous voulez jouer au golf, mais sachez que cela peut être encore plus court

arg[1]
...

Les ...sont un peu spéciaux dans lua, c'est une variable contenant le contenu décompressé de arg, ou les paramètres décompressés dans le cas d'une fonction variadique.

Lorsque vous devrez obtenir plusieurs entrées et utiliser chacune d'elles, il peut être utile de les enregistrer dans une variable. Voici quelques façons de sauvegarder 2 entrées dans des 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

et voici l'appel le plus court que vous auriez pu faire sans les 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

À partir du moment où vous avez 3 arguments, ou lorsque vous utilisez 2 arguments, avec un utilisé deux fois, vous gagnez déjà des octets à cause de a,b=...! :)

N'utilisez presque jamais si!

Il n'y a presque aucun cas où l'utilisation d'une instruction if / elseif / if coûtera moins cher qu'un ternaire. le passe-partout pour une telle déclaration est vraiment lourd:

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

Avec un exemple simple, vous économisez déjà 12 octets, quand vous devez faire des elseifs, cela devient de plus en plus important, alors soyez conscient de cela!

De plus, les ternaires à lua sont spéciaux , il y a des conditions dans leur fonctionnement, pour ceux qui sont intéressés, je l'expliquerai ci-dessous:

Les ternaires en lua sont de la forme <condition> and <case true: have to be a true value> or <case false: can be anything>

Tout d'abord, voyons la table de vérité du or. A orpeut être considéré comme une fonction: il renvoie toujours une valeur, voici la valeur qu'il renvoie:

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

C'est ce qui nous permet de construire notre ternaire.

C'est andce qui nous permet d'évaluer la condition, elle reviendra toujours ysi la valeur est x and yvraie.

Le problème avec cela est qu'il échouera si nous voulons qu'un nilou falsesoit retourné lorsque la condition est false. Par exemple, ce qui suit renvoie toujours 5, bien que la condition soit vraie.

v = true and false or 5

Voici une évaluation étape par étape d'un ternaire pour expliquer comment cela fonctionne (il sera utile lorsque vous devrez les imbriquer :))

-- 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
la source
Un conseil par réponse, s'il vous plaît.
ATaco
Notez que l'astuce "Utiliser le moins d'espace possible" ne fonctionne que sur Lua 5.2 et versions ultérieures.
Adriweb
4

J'ai également compilé plusieurs conseils. Je suis sûr que certains des miens chevaucheront ceux déjà mentionnés, mais je les inclurai de toute façon dans la veine de créer une réponse plus complète.


Attribuer des fonctions répétées aux variables

Lua vous permet d'assigner des fonctions aux variables. Même une variable de caractère. Cela signifie que si vous répétez la fonction string.sub(x, y)plus de deux fois, vous bénéficierez de son affectation à une variable.

Sans attribuer à une variable (69 caractères):

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

Affectation à une variable (51 caractères):

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

Il y a des cas où vous pouvez aller encore plus loin. Lua permet à un POO de manipuler des chaînes, comme ceci: str:sub(x, y)ou str.sub(x, y)Cela ouvre de nouvelles options pour notre code. Vous pouvez affecter une variable à la fonction par sa référence comme indiqué (46 caractères.)

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

Utilisez le moyen le plus efficace pour analyser les chaînes

Vous pouvez vous retrouver à utiliser une forboucle et string.subà itérer caractère par caractère dans Lua. Parfois, cela peut fonctionner le mieux, selon vos besoins, mais d'autres fois, string.gmatch fonctionnera en moins de caractères. Voici un exemple des deux:

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

Et au golf, la différence est plus 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

Restructurer les affectations pour optimiser les espaces blancs

Dans Lua, vous n'avez pas besoin de mettre un caractère espace entre des parenthèses fermées ou un guillemet de fin et le caractère suivant. Jusqu'à présent, j'ai trouvé deux cas où une restructuration dans cet esprit coupera les caractères.

  • Affectation de variables:

     x,y=io.read(),0 print(x)
     vs.
     y,x=0,io.read()print(x)
    
  • Si relevés:

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

Renvoie le moins de caractères possible

Si vous devez renvoyer une valeur vraie ou fausse, il semble que vous devez nécessairement utiliser au moins 5 caractères pour la valeur de retour. En réalité, les travaux suivants fonctionnent tout aussi bien:

return true
return false
vs
return 1>0
return 0>1
Skyl3r
la source
Excellents conseils, j'ai pris la liberté de suggérer une modification à votre message. Seulement nilet la falsevaleur false dans Lua, tout le reste est vrai, pour que vos conseils sur le remplacement x==0, x==""et x==''par xest faux. Je le change actuellement en nil:).
Katenkyo
Ah, tu as raison. Merci d'avoir réparé ça!
Skyl3r
2

Ce ne sont que des optimisations Lua (je pense):

Les chaînes sont automatiquement converties en nombres lorsque vous effectuez des opérations arithmétiques sur elles. Attention aux instructions conditionnelles, elles ne se convertissent pas automatiquement. C'est idéal pour prendre les entrées utilisateur sous forme de nombres tout en économisant de l'espace.

La commutation du contenu de deux variables ne nécessite pas de variable temporaire. a,b=b,apermutera les valeurs de a et b.

De plus, pour prolonger ce qui a été dit ci-dessus, tout caractère alphanumérique peut toucher un caractère non alphanumérique. Il en a,b=io.read():match"(.+)/(.+)"u,v=a,bva de même pour un script parfait et fonctionnel, même en l'absence d'espace.

Dwayne Slater
la source
2

Combiner les affectations de variables locales

Au lieu de:

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

Utiliser l'affectation parallèle:

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

6 octets enregistrés pour chaque variable!

Déclarer des variables locales via des paramètres de fonction inutilisés

Au lieu de:

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

Utilisation

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

6 octets enregistrés (moins 1 à 2 octets pour chaque variable pouvant être dupliquée).

Phrogz
la source
1
Voté car il n'y a absolument aucun cas où l'utilisation localest justifiée lors du golf, car il suffit d'utiliser un nom différent. Nous pourrions utiliser TOUS les noms jusqu'à 7 caractères ET tables avec des index de chaîne jusqu'à 7 combinaisons de caractères avant de toucher quelque chose qui pourrait bénéficier de l'utilisation des locaux
Katenkyo
1

Fonctions variadiques

La principale fonction variadique qui vous dérangera est print(). Par exemple, lorsque vous l'utilisez, String.gsub()il affichera la chaîne que vous avez modifiée ET le nombre de gsubdéclenchements.

Pour supprimer cette deuxième sortie, encapsulez votre gsubin parens pour la forcer à renvoyer une seule valeur

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

Savoir comment sortir

Il y a deux méthodes principales de sortie dans lua

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

Lorsque vous devez concaténer plusieurs fois, vous pouvez raccourcir cela en utilisant io.write()assigné à une variable d'une lettre au lieu de l'opérateur de concaténation standard..

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

Vous gagnez 2 octets à chaque appel tout en payant d'avance

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

Vous êtes même à la troisième concaténation et commencez à gagner des octets à la quatrième.

Katenkyo
la source
3
C'est printet non printf!
val dit Réintégrer Monica
@val Wow, je ne sais même pas comment je pourrais faire cette erreur. Merci de l'avoir signalé, je vais modifier
Katenkyo
1

Un tas de conseils sans ordre particulier:

  • stringest un nom assez long. Efficacement, ('').charc'est la même chose que string.char. Des résultats encore meilleurs peuvent être obtenus si vous l'utilisez avec un point-virgule sur les variables:, a=...; print(a:sub(1, 5))mais certaines stringfonctions ne prennent pas de chaînes en entrée.
  • Lua a des conversions automatiques entre les chaînes et les nombres dans la plupart des cas, donc tonumberet +0souvent ne gaspille que des octets.
  • Utilisez toujours load'your function code here'au lieu de function()your function code here end. Accédez aux arguments de la fonction en utilisant ...inside.
  • Certaines fonctions de chaîne de Lua peuvent être utilisées de manière inattendue! Par exemple, a:gsub('.',load'my function')semble être le moyen le plus court pour parcourir les caractères d'une chaîne
  • Bien que le moteur de chaîne soit puissant, méfiez-vous de sa puissance lorsque vous utilisez les entrées utilisateur comme modèles! Pour cette raison, vous devrez peut-être utiliser a:find('.',1,1)(pour tester ce problème, essayez d'inclure %à divers endroits dans votre entrée et consultez les résultats). D'innombrables idées ont éclaté à cause de Lua essayant d'analyser l'entrée comme modèle.
  • nilest de trois octets, _est un (c'est juste un nom aléatoire qui n'existe probablement pas). De plus, tout chiffre fonctionnera comme une valeur véridique.
  • Connaissez votre logique derrière x and i or o. Ce n'est pas seulement un opérateur ternaire - c'est une expression logique complète. En fait, cela signifie ce qui suit: "si xc'est vrai, essayez i. Si x ou i est faux, retournez o". Donc, si ce in'est pas vrai, le résultat l'est o. En outre, les deux andou orpeuvent être supprimés parties ( x and i, x or o).
  • Utilisation division entière par un au lieu de math.floor: 5.3//1==5.0. Veuillez noter que le nombre résultant suit toujours le type d'entrée un (entier / flottant).
val dit de réintégrer Monica
la source
1
"De plus, tout chiffre fonctionnera comme une valeur véridique." Je voulais juste préciser que cela inclut 0, ce qui pourrait ne pas être très intuitif pour certains codeurs issus d'un arrière-plan C / C ++.
ouflak