Советы по игре в гольф в Луа


21

Какие общие советы у вас есть для игры в гольф в Луа? Я ищу идеи, которые могут быть применены к кодовым проблемам гольфа в целом, которые, по крайней мере, несколько специфичны для Lua (например, «удалить комментарии» - это не ответ). Пожалуйста, оставьте один совет за ответ.


6
Советы по вопросам должны быть вики сообщества. Но для того, кто бы ни представил это близко к «главным образом основанным на мнении», вопросы «Советы по игре в гольф на языке» являются нашим общепринятым исключением из этого правила. Открытый характер этих вопросов заключается в том, почему они вики-сообщества.
Джонатан Ван Матре

Ответы:


9

В дополнение к уже опубликованным, вот некоторые уловки, которые я собрал со временем, без определенного порядка ...

  • Для вызовов функций, которые имеют только один параметр, разделенный символом ( "для строк, {для таблиц), параметр не нужно заключать в круглые скобки.
    Например, вместо того, чтобы делать print("hello"), вы можете просто сделать:print"hello"

  • Удалите как можно больше пробелов - это особенно легко сделать после символа, который закрывает строки (или перед одним открытием), вызовов функций, таблиц ...
    Вместо этого print(42) a=1вы можете это сделать print(42)a=1. Другой пример: print(a and-1 or-2).

  • Используйте троичный оператор, когда можете! Вместо того if a>0 then print("hello") else print("goodbye") end, чтобы предпочесть print(a>0 and "hello" or "goodbye"). Больше информации здесь .
    (Это действительно может стать еще лучше: print(a>0 and"hello"or"goodbye"))

  • Используйте синтаксический сахар при вызове двоеточия, когда можете: вместо string.rep(str,12), делайте str:rep(12). Это также работает с переменными (и только так):("a"):rep(5)

  • Вместо того, чтобы tonumber(str)просто делатьstr+0

  • Для функций без параметров вместо определения их обычным способом ( function tick() blabla() end) вы можете сделать:, ticks=loadstring"blabla()"которая сохраняет 1 или более байтов в зависимости от содержимого. Кроме того, если вы определите несколько функций, локализуйте их loadstringдо переменной с 1 символом, и вы сэкономите много байтов;). Кредиты Джиму Бовенсу за этот трюк.

  • Lua считает пустую строку (и в 0отличие от других языков) истинной в условных тестах, поэтому, например, вместо выполнения while 1 do ... endсохраните 1 байт, написавwhile''do ... end


(Добавлен трюк с нагрузкой)
Adriweb

2
0 быть истинным значением просто глупо
SuperJedi224

другой str+0эквивалент ~~str, может быть полезным для его приоритета
Фелипе Нарди Батиста

@FelipeNardiBatista, однако, поддерживается только в Lua 5.3+
Adriweb

5

Я уже думал об одном. Я не знаю, работает ли он на некоторых других языках, но я знаю только Lua, который позволяет хранить функции в переменных. Так что если например string.subиспользуется в вашей программе несколько раз, используйте например s=string.sub.


4
Он также работает во многих других языках, таких как Python и Ruby.
nyuszika7h

4
Javascript и Haskell также могут иметь значения функций.
гордый haskeller

Это эквивалентно s=("").subили s=a.subдля любой переменной, aсодержащей строковое значение.
Егор Скриптунов

Это называется первоклассными функциями
Redwolf Programs

5

Это довольно многословный язык для игры в гольф ... но некоторые общие советы, которые приходят на ум:

  • Старайтесь избегать условных выражений, поскольку if... then... else... endэто большая трата.
  • Вместо этого попытайтесь сосредоточиться на более коротких языковых конструкциях, например for i=1,5 do.
  • #Оператор является довольно большим для игры в гольф (и в целом).

5

Укороти свой бесконечный цикл

Когда вам нужно использовать бесконечный цикл, вы можете подумать об использовании a while, но вместо этого использование метки короче на 2 байта:

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

Используйте как можно меньше места

Есть простая вещь, которую вы можете (ab) использовать, чтобы убрать еще больше пробелов из вашего кода. Спецификации Lua ясны в отношении имени, которое вы даете переменным: они должны начинаться с буквы. Это означает, что иногда вы можете пропустить пробелы между числами и функциями / переменными

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

Возможность удаления пробела зависит от буквы после числа, вот письмо, которое не позволит вам сделать это:

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)

Используя это и обращая внимание на то, как вы называете свои переменные, вы можете сделать большую часть ваших исходных кодов свободными.

Взяв пример уже здесь и используя этот совет, вот еще один байт, который вы можете сбрить :).

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

Используйте правильный метод ввода

Если мы посмотрим на шаблон и стоимость для каждого основного типа ввода, вот что мы имеем:

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

Каждый из этих методов позволяет нам брать 1 вход, причем функция является самой дорогой (но позволяет нам брать таблицу в качестве входных данных).

Теперь мы можем видеть, что использование аргумента командной строки - это путь, если вы хотите играть в гольф, но помните: он может быть еще короче

arg[1]
...

Они ...немного особенные в lua, это переменная, содержащая распакованное содержимое argили распакованные параметры в случае функции с переменным числом аргументов.

Когда вам нужно получить более одного ввода и использовать каждый из них, может быть полезно сохранить их в переменной. Вот несколько способов сохранить 2 входа в переменных

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

и вот самый короткий вызов, который вы могли бы сделать без переменных:

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

С момента, когда у вас есть 3 аргумента, или когда вы используете 2 аргумента, причем один используется дважды, вы уже получаете байты из-за a,b=...! :)

Почти никогда не использовать, если!

Практически нет случаев, когда использование оператора if / elseif / if будет стоить меньше, чем троичный. шаблон для такого заявления действительно тяжел:

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

На простом примере вы уже сохраняете 12 байтов, когда вам приходится делать какие-то другие операции, это становится все более и более важным, так что имейте это в виду!

Кроме того, троицы в lua являются особыми , есть некоторые условия, как они работают, для тех, кто заинтересован, я объясню это ниже:

Тройки в Луа имеют форму <condition> and <case true: have to be a true value> or <case false: can be anything>

Прежде всего, давайте посмотрим на таблицу истинности or. A orможно рассматривать как функцию: она всегда возвращает значение, вот значение, которое она возвращает:

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

Вот что позволяет нам строить нашу троицу.

Это andто, что позволяет нам оценить условие, оно всегда будет возвращаться, yесли x and yоценивается как истинное.

Проблема в том, что он потерпит неудачу, если мы хотим, чтобы nilили falseбыло возвращено, когда условие false. Например, следующее всегда будет возвращать 5, несмотря на то, что условие истинно.

v = true and false or 5

Вот пошаговая оценка троичного, чтобы объяснить, как он работает (это будет полезно, когда вам придется их вкладывать :))

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

Один совет за ответ, пожалуйста.
ATaco

Обратите внимание, что трюк «Используйте как можно меньше места» работает только в Lua 5.2 и более поздних версиях.
Adriweb

4

Я также собрал несколько советов. Я уверен, что некоторые из моих совпадут с уже заявленными, но я все равно включу их в основу создания более полного ответа.


Присвойте повторяющиеся функции переменным

Lua позволяет назначать функции переменным. Ещё одна символьная переменная. Это означает, что если вы повторите функцию string.sub(x, y)более двух раз, вы получите выгоду от назначения ее переменной.

Без присвоения переменной (69 символов):

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

Присвоение переменной (51 символ):

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

Есть случаи, когда вы можете сделать еще один шаг вперед. Lua позволяет ООП манипулировать строками, например так: str:sub(x, y)или str.sub(x, y)Это открывает новые опции для нашего кода. Вы можете назначить переменную функции по ее ссылке, как показано (46 символов.)

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

Используйте самый эффективный способ разбора строк

Вы можете использовать forцикл и string.subвыполнять итерацию за символом в Lua. Иногда это может работать лучше всего, в зависимости от ваших потребностей, но в других случаях string.gmatch будет работать с меньшим количеством символов. Вот пример обоих:

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

И когда игра в гольф, разница более заметна:

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

Назначение реструктуризации для оптимизации пробелов

В Lua вам не нужно ставить пробел между закрытыми скобками или конечной кавычкой и следующим символом. До сих пор я обнаружил два случая, когда реструктуризация с учетом этого будет сокращать персонажей.

  • Назначение переменных:

     x,y=io.read(),0 print(x)
     vs.
     y,x=0,io.read()print(x)
    
  • Если заявления:

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

Верните как можно меньше символов

Если вы должны вернуть значение «истина» или «ложь», то, похоже, вы должны обязательно использовать как минимум 5 символов для возвращаемого значения. На самом деле следующее работает так же хорошо:

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

Отличные советы, я позволил себе предложить редактирование вашего поста. Только nilи falseоценивается как ложное в lua, все остальное верно, поэтому ваши советы о замене x==0, x==""и x==''на xложное. Я в настоящее время изменяю это на nil:).
Катенкё

Ах, ты прав. Спасибо за исправление этого!
Skyl3r

2

Это только Lua (я думаю) оптимизация:

Строки автоматически преобразуются в числа при выполнении арифметических операций над ними. Просто следите за условными утверждениями, они не конвертируются автоматически. Это отлично подходит для принятия пользовательского ввода в виде чисел при экономии места.

Переключение содержимого двух переменных не требует временной переменной. a,b=b,aпоменяет местами значения a и b.

Кроме того, чтобы расширить сказанное выше, любой буквенно-цифровой символ может касаться не буквенно-цифрового символа. Так a,b=io.read():match"(.+)/(.+)"u,v=a,bчто это идеальный, рабочий сценарий, даже при отсутствии пробелов.


2

Объединить присвоения локальных переменных

Вместо того:

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

Используйте параллельное назначение:

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

6 байтов сохранено для каждой переменной!

Объявление локальных переменных через неиспользуемые параметры функции

Вместо того:

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

использование

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

6 байтов сохранено (минус 1-2 байта для каждой переменной, которая может быть дублирована).


1
Принято во внимание, потому что нет абсолютно никакого случая, когда использование localоправдано при игре в гольф, потому что вы просто должны использовать другое имя. Мы могли бы использовать ВСЕ имена до 7 символов и таблицы со строковыми индексами до 7 комбинаций символов, прежде чем мы добьемся того, что могло бы принести пользу от использования местных жителей
Katenkyo

1

Variadic Функции

Основная переменная функция, которая вас беспокоит, это print(). Например, когда вы используете его вместе, String.gsub()он напечатает строку, которую вы изменили, и количество gsubсрабатываний.

Чтобы подавить этот второй вывод, заключите его gsubв parens, чтобы заставить его возвращать только одно значение

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

1

Знать, как выводить

Есть два основных способа вывода в lua

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

Когда вам приходится конкатенировать несколько раз, вы можете сократить это, используя io.write()присвоенную однобуквенной переменной вместо стандартного оператора конкатенации..

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

Вы получаете 2 байта за каждый звонок, платя при этом авансом

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

Вы даже на третьем объединении, и начинаете получать байт на четвертом.



@val Вау, я даже не знаю, как я мог сделать эту ошибку. Спасибо за указание, я отредактирую
Katenkyo

1

Куча советов в произвольном порядке:

  • stringэто довольно длинное имя. Эффективно, так ('').charже, как string.char. Еще лучших результатов можно достичь, если использовать его вместе с точкой с запятой для переменных:, a=...; print(a:sub(1, 5))но некоторыеstring функции не принимают строки в качестве входных данных.
  • Lua имеет автоматические преобразования между строками и числами для большинства случаев, поэтому tonumber и +0часто только тратить байты.
  • Всегда используйте load'your function code here'вместоfunction()your function code here end . Доступ к аргументам функции с помощью ...inside.
  • Некоторые строковые функции в Lua могут использоваться непреднамеренно! Например,a:gsub('.',load'my function') кажется, самый короткий способ перебрать символы в строке
  • Несмотря на то, что строковый механизм является мощным, остерегайтесь его мощности при использовании пользовательского ввода в качестве шаблона! Из-за этого вам, возможно, придется воспользоваться a:find('.',1,1)(чтобы проверить эту проблему, попробуйте включить ее %в разные места и проверить результаты). Бесчисленные идеи сломались из-за того, что Луа пытается проанализировать входные данные как шаблон.
  • nil это три байта, _ это один (это просто случайное имя, которое, скорее всего, не существует). Также любая цифра будет работать как истинное значение.
  • Знай свою логику позади x and i or o. Это не просто троичный оператор - это полное логическое выражение. Фактически, это означает следующее: «если xэто правда, попробуйте i. Если x или i - ложь, верните o». Так что, если iэто неправда, результат есть o. Кроме того, оба andили orчасти могут быть опущены ( x and i,x or o ).
  • Используйте целочисленное деление на единицу вместо math.floor: 5.3//1==5.0. Обратите внимание, что полученное число всегда соответствует типу ввода (целое число / число с плавающей запятой).

1
«Кроме того, любая цифра будет работать как истинное значение». Просто хотел уточнить, что это включает в себя 0, что может быть не очень интуитивно понятно для некоторых программистов из C / C ++ фона.
ouflak
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.