Wskazówki do gry w golfa w Lua


21

Jakie masz ogólne wskazówki na temat gry w golfa w Lua? Szukam pomysłów, które można by zastosować do ogólnych problemów z golfem, które są przynajmniej nieco specyficzne dla Lua (np. „Usuń komentarze” nie jest odpowiedzią). Proszę zamieścić jedną wskazówkę na odpowiedź.


6
Wskazówki dotyczące pytań powinny być wiki społeczności. Ale dla każdego, kto przedstawił to jako „oparte głównie na opiniach”, Porady dotyczące gry w golfa w języku są naszym zaakceptowanym wyjątkiem od tej zasady. Otwarty charakter tych pytań polega na tym, dlaczego są one tworzone przez społeczność na wiki.
Jonathan Van Matre

Odpowiedzi:


9

Oprócz tych już opublikowanych, oto kilka sztuczek, które zebrałem w czasie, w żadnej określonej kolejności ...

  • W przypadku wywołań funkcji, które mają tylko jeden parametr rozdzielony symbolem ( "dla łańcuchów, {dla tabel), parametr nie musi być zawijany wokół nawiasów.
    Na przykład zamiast robić print("hello"), możesz po prostu zrobić:print"hello"

  • Usuń jak najwięcej białych znaków - jest to szczególnie łatwe po symbolu, który zamyka łańcuchy (lub przed jednym otwarciem), wywołania funkcji, tabele ...
    Zamiast tego print(42) a=1możesz to zrobić print(42)a=1. Inny przykład: print(a and-1 or-2).

  • Kiedy to możliwe, użyj operatora trójskładnikowego! Zamiast if a>0 then print("hello") else print("goodbye") endwoli print(a>0 and "hello" or "goodbye"). Więcej informacji tutaj .
    (To rzeczywiście może się jeszcze lepiej: print(a>0 and"hello"or"goodbye"))

  • Użyj cukru syntaktycznego z dwukropka, gdy możesz: zamiast tego string.rep(str,12)zrobić str:rep(12). Działa to również na nie-zmienne w ten sposób (i tylko w ten sposób):("a"):rep(5)

  • Zamiast robić, tonumber(str)po prostu róbstr+0

  • W przypadku funkcji bez parametrów zamiast definiowania ich w zwykły sposób ( function tick() blabla() end) można wykonać ticks=loadstring"blabla()":, która zapisuje 1 lub więcej bajtów, w zależności od zawartości. Ponadto, jeśli zdefiniujesz wiele funkcji, zlokalizuj loadstringwcześniej zmienną 1-znakową, a zaoszczędzisz dużo bajtów;). Podziękowania dla Jima Bauwensa za tę sztuczkę.

  • Lua uważa pusty ciąg (i 0zbyt odmienny od innych języków) za prawdziwy w testach warunkowych, więc na przykład zamiast robić while 1 do ... end, zachowaj 1 bajt piszącwhile''do ... end


(Dodano trik ładujący)
Adriweb

2
0 jest prawdziwą wartością jest po prostu głupie
SuperJedi224

innym str+0odpowiednikiem jest ~~str, może być użyteczny ze względu na pierwszeństwo
Felipe Nardi Batista

@FelipeNardiBatista jednak jest to obsługiwane tylko w wersji Lua 5.3+
Adriweb

5

Już o tym pomyślałem. Nie wiem, czy to działa w niektórych innych językach, ale Lua jest jedynym, który wiem, co pozwala przechowywać funkcje w zmiennych. Więc jeśli np. string.subJest używany wielokrotnie w twoim programie, użyj np s=string.sub.


4
Działa również w wielu innych językach, takich jak Python i Ruby.
nyuszika7h

4
Javascript i Haskell również mogą mieć wartości funkcji.
dumny haskeller

Jest to równoważne s=("").sublub s=a.subdla dowolnej zmiennej azawierającej wartość ciągu.
Egor Skriptunoff,

Nazywa się to funkcjami pierwszej klasy
Redwolf Programs

5

Jest to dość pełny język do gry w golfa ... ale kilka ogólnych wskazówek, które przychodzą na myśl, to:

  • Staraj się unikać warunków warunkowych, ponieważ if... then... else... endto poważna strata.
  • Zamiast tego spróbuj skupić się na krótszych konstrukcjach językowych, np for i=1,5 do.
  • #Operator jest dość dobre dla golfa (iw ogóle).

5

Skróć swoją nieskończoną pętlę

Kiedy musisz użyć nieskończonej pętli, możesz pomyśleć o użyciu while, ale zamiast tego użycie etykiety jest krótsze o 2 bajty:

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

Wykorzystaj jak najmniej miejsca

Jest prosta rzecz, której możesz (ab) użyć, aby usunąć jeszcze więcej spacji z kodu. Specyfikacje Luy jasno określają nazwę, którą nadajesz zmiennym: muszą zaczynać się od litery. Oznacza to, że czasami można pominąć spacje między liczbami a funkcjami / zmiennymi

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

Możliwość usunięcia spacji zależy od litery następującej po numerze, oto litera, która na to nie pozwoli:

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)

Korzystając z tego i zwracając uwagę na to, jak wywołujesz zmienne, możesz zwolnić większość kodu źródłowego.

Pobierając przykład już tutaj i korzystając z tej porady, oto jeszcze jeden bajt, który możesz ogolić :).

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

Użyj właściwej metody wprowadzania

Jeśli spojrzymy na płytę kotłową i koszt każdego głównego typu danych wejściowych, oto, co mamy:

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

Każda z tych metod pozwala nam pobrać 1 dane wejściowe, przy czym funkcja jest tą o największym koszcie (ale pozwala nam wziąć tabelę jako dane wejściowe)

Teraz widzimy, że jeśli chcesz grać w golfa, skorzystaj z argumentu wiersza poleceń, ale pamiętaj: może być jeszcze krótszy

arg[1]
...

...To specjalny bit lua, to zmienna zawierająca rozpakowane treść arglub niespakowanego parametry w przypadku zmiennej liczbie argumentów funkcji.

Gdy będziesz musiał uzyskać więcej niż jedno wejście i użyć każdego z nich, dobrze jest zapisać je w zmiennej. Oto kilka sposobów na zapisanie 2 danych wejściowych w zmiennych

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

a oto najkrótsze połączenie, jakie można było wykonać bez zmiennych:

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

Od momentu, w którym masz 3 argumenty lub gdy używasz 2 argumentów, z jednym argumentem dwukrotnie, zyskujesz już bajty a,b=...! :)

Prawie nigdy nie używaj, jeśli!

Nie ma prawie żadnych przypadków, w których użycie instrukcji if / elseif / if będzie kosztować mniej niż trójka. płyta dla takiego stwierdzenia jest naprawdę ciężka:

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

Na prostym przykładzie zapisujesz już 12 bajtów, a kiedy musisz zrobić kilka innych, staje się to coraz ważniejsze, więc pamiętaj o tym!

Ponadto trójskładniki w lua są wyjątkowe , istnieje pewien warunek w ich działaniu, dla zainteresowanych wyjaśnię to poniżej:

Trójskładniki w lua mają formę <condition> and <case true: have to be a true value> or <case false: can be anything>

Przede wszystkim zobaczmy tabelę prawdy or. A ormożna uznać za funkcję: zawsze zwraca wartość, oto wartość, którą zwraca:

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

To pozwala nam zbudować nasz trójskładnik.

To, andco pozwala nam ocenić warunek, zawsze powróci, yjeśli zostanie x and yocenione jako prawdziwe.

Problem polega na tym, że to się nie powiedzie, jeśli chcemy nilalbo falsepowrócić, gdy stan jest spełniony false. Na przykład, następujący wynik zawsze zwróci 5, pomimo spełnienia warunku.

v = true and false or 5

Oto krok po kroku ocena trójskładnika, aby wyjaśnić, jak to działa (przyda się, gdy trzeba je zagnieździć :))

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

Poproszę jedną wskazówkę na odpowiedź.
ATaco,

Pamiętaj, że sztuczka „Użyj mniej miejsca, jak to możliwe” działa tylko na Lua 5.2 i nowszych.
Adriweb

4

Zebrałem też kilka wskazówek. Jestem pewien, że niektóre moje pokryją się z tymi, które już podano, ale i tak uwzględnię je w celu stworzenia pełniejszej odpowiedzi.


Przypisz powtarzające się funkcje do zmiennych

Lua pozwala przypisywać funkcje do zmiennych. Nawet zmienne jednego znaku. Oznacza to, że jeśli powtórzysz funkcję string.sub(x, y)więcej niż dwa razy, odniesiesz korzyść z przypisania jej do zmiennej.

Bez przypisywania do zmiennej (69 znaków):

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

Przypisywanie do zmiennej (51 znaków):

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

Są przypadki, w których możesz pójść o krok dalej. Lua pozwala OOP na manipulowanie ciągami, tak jak: str:sub(x, y)lub str.sub(x, y)To otwiera nowe opcje dla naszego kodu. Możesz przypisać zmienną do funkcji poprzez jej odwołanie, jak pokazano (46 znaków).

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

Użyj najbardziej wydajnego sposobu parsowania ciągów

Możesz użyć forpętli i string.subiterować postać po znaku w Lua. Czasami może to działać najlepiej, w zależności od potrzeb, ale innym razem string.gmatch będzie działał z mniejszą liczbą znaków. Oto przykład obu:

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

A kiedy gra się w golfa, różnica jest bardziej zauważalna:

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

Restrukturyzacja przypisań w celu optymalizacji białych znaków

W Lua nie musisz umieszczać spacji między zamkniętymi nawiasami lub końcowym cudzysłowem a następnym znakiem. Do tej pory znalazłem dwa przypadki, w których restrukturyzacja z myślą o tym spowoduje odcięcie postaci.

  • Przypisywanie zmiennych:

     x,y=io.read(),0 print(x)
     vs.
     y,x=0,io.read()print(x)
    
  • Jeśli oświadczenia:

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

Zwróć jak najmniej znaków

Jeśli musisz zwrócić wartość true lub false, wydaje się, że musisz koniecznie użyć co najmniej 5 znaków dla wartości zwracanej. W rzeczywistości działa równie dobrze:

return true
return false
vs
return 1>0
return 0>1

Świetne wskazówki, skorzystałem z możliwości zaproponowania edycji Twojego postu. Tylko nili falseFALSE w Lua, wszystko inne jest prawdą, dzięki czemu wskazówki na temat wymiany x==0, x==""a x==''przez xto fałszywe. Obecnie zmieniam na nil:).
Katenkyo

Ach, masz rację. Dziękujemy za naprawienie tego!
Skyl3r

2

Są to tylko optymalizacje Lua (myślę):

Ciągi są automatycznie konwertowane na liczby podczas wykonywania na nich operacji arytmetycznych. Uważaj tylko na instrukcje warunkowe, nie będą one automatycznie konwertowane. Jest to doskonałe do wprowadzania danych liczbowych przez użytkownika przy jednoczesnym oszczędzaniu miejsca.

Przełączanie zawartości dwóch zmiennych nie wymaga zmiennej tymczasowej. a,b=b,azamieni wartości a i b.

Ponadto, aby rozszerzyć to, co powiedziano powyżej, każdy znak alfanumeryczny może dotykać znaku innego niż alfanumeryczny. a,b=io.read():match"(.+)/(.+)"u,v=a,bJest to więc doskonały, działający skrypt, nawet przy braku białych znaków.


2

Połącz przypisania zmiennych lokalnych

Zamiast:

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

Użyj równoległego przypisania:

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

6 bajtów zapisanych dla każdej zmiennej!

Deklaruj zmienne lokalne za pomocą nieużywanych parametrów funkcji

Zamiast:

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

Posługiwać się

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

Zapisano 6 bajtów (minus 1-2 bajty dla każdej zmiennej, która może być zduplikowana).


1
Usprawiedliwiony, ponieważ absolutnie nie ma przypadku, w którym używanie localjest uzasadnione podczas gry w golfa, ponieważ wystarczy użyć innej nazwy. Moglibyśmy użyć WSZYSTKICH nazw do 7 znaków i tabel z indeksami ciągów do 7 kombinacji znaków, zanim
trafimy na

1

Funkcje Variadic

Główną funkcją wariadyczną, która będzie cię martwić, jest print(). Na przykład, gdy go użyjesz, String.gsub()wydrukuje zmodyfikowany ciąg ORAZ liczbę gsuburuchomień.

Aby pominąć to drugie wyjście, obuduj pareny, gsubaby zmusić je do zwrócenia tylko jednej wartości

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

1

Wiedzieć, jak wydrukować

Istnieją dwie główne metody wypisywania danych w lua

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

W przypadku wielokrotnej konkatenacji można ją skrócić, używając io.write()przypisanej zmiennej o wartości jednej litery zamiast standardowego operatora konkatenacji..

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

Zyskujesz 2 bajty przy każdym połączeniu, płacąc z góry

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

Jesteś nawet na trzeciej konkatenacji i zacznij zyskiwać bajt na czwartej.


3
Tak jest printi nie printf!
val mówi Przywróć Monikę

@val Wow, nawet nie wiem, jak mogłem zrobić ten błąd. Dzięki za zwrócenie uwagi,
zredaguję

1

Kilka wskazówek w określonej kolejności:

  • stringto dość długie imię. Skutecznie ('').charjest taki sam jak string.char. Jeszcze lepsze wyniki można osiągnąć, jeśli użyjesz go razem ze średnikiem zmiennych:, a=...; print(a:sub(1, 5))ale niektóre stringfunkcje nie przyjmują ciągów jako danych wejściowych.
  • Lua ma automatyczne konwersje między ciągami i liczbami w większości przypadków, więc tonumberi +0często marnuje tylko bajty.
  • Zawsze używaj load'your function code here'zamiast function()your function code here end. Dostęp do argumentów funkcji za pomocą ...wewnątrz.
  • Niektóre funkcje łańcuchowe w Lua mogą być używane w niezamierzony sposób! Na przykład a:gsub('.',load'my function')wydaje się być najkrótszym sposobem na iterację znaków w łańcuchu
  • Podczas gdy silnik łańcuchowy jest potężny, strzeż się jego mocy, gdy używasz danych wejściowych użytkownika jako wzorców! Z tego powodu może być konieczne użycie a:find('.',1,1)(aby przetestować ten problem, spróbuj dołączyć %w różnych miejscach danych wejściowych i sprawdzić wyniki). Niezliczone pomysły zostały złamane, ponieważ Lua próbowała przeanalizować dane wejściowe jako wzorzec.
  • nilma trzy bajty, _jest jeden (to po prostu losowa nazwa, która najprawdopodobniej nie istnieje). Ponadto każda cyfra będzie działać jako prawdziwa wartość.
  • Poznaj swoją logikę x and i or o. To nie jest tylko potrójny operator - to kompletne wyrażenie logiczne. W rzeczywistości oznacza to: „jeśli xto prawda, spróbuj i. Jeśli x lub i jest fałszem, zwróć o”. Więc jeśli inie jest to prawdą, wynik jest o. Obie andlub orczęści można również pominąć ( x and i, x or o).
  • Zastosowanie dzielenia całkowitego jeden zamiast math.floor: 5.3//1==5.0. Należy pamiętać, że wynikowa liczba zawsze odpowiada typowi wejścia 1 (liczba całkowita / liczba zmiennoprzecinkowa).

1
„Ponadto każda cyfra będzie działać jako prawdziwa wartość”. Chciałem tylko wyjaśnić, że obejmuje to 0, co może nie być bardzo intuicyjne dla niektórych programistów z tła C / C ++.
ouflak
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.