Prindeal (произносится как prin-dee-al ) - это новый эзотерический язык программирования, который имеет только четыре команды: pr int , in crement , de crement и al ias . Несмотря на минимализм, в Prindeal можно выполнять сложные математические операции, умело комбинируя четыре команды.
Ваша задача в этом коде состоит в том, чтобы написать самую короткую программу, которая может запускать код Prindeal.
Спецификация длинная, но я постарался сделать ее как можно более понятной, и я верю, что если вы приложите усилия, чтобы изучить Prindeal, вы найдете ее довольно элегантной!
Интерпретация Приндейла
предварительная обработка
Перед интерпретацией программы Prindeal из нее необходимо удалить эти вещи в следующем порядке:
- Все, что идет после
#
знака до конца строки, плюс#
само. (Это комментарии.) - Конечный пробел на любой строке.
- Полностью пустые строки.
Например, программа Prindeal
p cat #The next line has 7 trailing spaces.
p dog
#p mouse
будет предварительно обработан в
p cat
p dog
С этого момента мы будем предполагать, что этот шаг предварительной обработки был выполнен.
переменные
Нам нужно быстро определить переменные, прежде чем показывать, как они используются.
Переменные (и ссылки на переменные) - это то, что передается в аргументы команд Prindeal. Переменные всегда являются глобальными , поэтому изменения переменной, независимо от того, где они происходят, отражаются повсеместно.
Каждая переменная содержит неотрицательное целое число произвольной точности (0, 1, 2, 3, ...). Переменные не нужно предварительно инициализировать - они всегда начинаются со значения 0 при первом использовании или вызове.
Имя переменной может быть любой непустой строкой буквенно-цифровых символов и подчеркиваний, которая не начинается с цифры - [a-zA-Z_][0-9a-zA-Z_]*
в регулярном выражении . Они чувствительны к регистру, поэтому spiny_lumpsuck3r
и Spiny_lumpsuck3r
являются разными переменными.
выполнение
Prindeal - это императивный язык программирования. Когда программа Prindeal запущена, ее операторы выполняются сверху вниз по порядку, а затем программа завершается.
Каждый без отступа строки в Prindeal программы является утверждение , что включает в себя выполнение одной команды , которые могут или не могут принимать аргументы.
Строки с отступом появляются только после команд псевдонимов . В частности, ровно три строки с отступом в один пробел появляются после каждой команды псевдонима и считаются ее частью. Таким образом, псевдонимы на самом деле состоят из четырех строк. (Они могут быть одной строкой, четыре просто читаемее.)
Не псевдонимы Заявления
За исключением псевдонима , каждое утверждение в программе Prindeal имеет вид:
[command name] [argument 1] [argument 2] [argument 3] ...
Может быть произвольное количество аргументов (включая их вообще). Каждый аргумент всегда является переменной или (как мы увидим при обсуждении псевдонима ) ссылкой на переменную .
По завершении выполнения каждый оператор помечается как неудачный или успешный в зависимости от того, были ли обнаружены ошибки или нет. (Это действительно имеет значение, только когда мы используем псевдоним .)
Встроенные функции print , increment и expment являются операторами с вышеуказанной формой. Вот что они делают:
print имеет имя команды
p
и принимает один аргумент. Он печатает имя переданной переменной и ее значение (в десятичной дроби), разделенные знаком «=», а затем символ новой строки. Это всегда помечается как успех .Например, программа Prindeal
p _MyVariable_321 p screaming_hairy_armadillo
будет выводить
_MyVariable_321 = 0 screaming_hairy_armadillo = 0
потому что все переменные начинаются с 0. (Пробелы до и после знака равенства обязательны).
инкремент имеет имя команды
i
и принимает один аргумент. Он увеличивает значение переменной, переданной на 1. Он всегда помечается как успешный .Например, программа
i alpaca p alpaca i alpaca p alpaca
будет выводить
alpaca = 1 alpaca = 2
Обратите внимание, как
alpaca
был увеличен с 0 до 1, хотя он никогда не был доступен раньше.декремент имеет имя команды
d
и принимает один аргумент. Если переданная переменная отлична от нуля, ее значение уменьшается на 1, и оператор помечается как успешный . Если переданная переменная равна 0, то ничего не делается, и оператор помечается как сбой .Например, программа
i malamute p malamute d malamute #success p malamute d malamute #failure p malamute d akita #failure p akita
будет выводить
malamute = 1 malamute = 0 malamute = 0 akita = 0
Обратите внимание, что уменьшение переменной со значением 0 является единственным способом вызвать ошибку .
Псевдоним Постановка и команды Связанных
Команда псевдонимов имеет специальный синтаксис и является наиболее мощной, поскольку ее можно использовать для определения новых команд. Псевдоним имя команды a
и псевдоним оператор имеет вид:
a [name of new command]
[statement A]
[statement B]
[statement C]
Где каждый [statement X]
представляет какое-либо утверждение без псевдонима , то есть что-то с формой [command name] [argument 1] [argument 2] [argument 3] ...
.
Имя псевдонима команды [name of new command]
может быть любой непустой строкой буквенно-цифровых символов и подчеркиваний, которая начинается не с цифры, а [a-zA-Z_][0-9a-zA-Z_]*
в регулярном выражении.
(Это тот же набор имен, что и для переменных, но псевдонимные команды и переменные - это разные вещи, используемые в разных местах . Переменная может называться так же, как и команда без каких-либо вредных последствий.)
Когда выполняется псевдоним , новая команда добавляется вместе с исходными четырьмя p
i
d
a
командами. Новая команда может использоваться как [command name]
операторы in и вызываться с аргументами, как и любая другая команда без псевдонимов .
Когда выполняется оператор с псевдонимом команды , запускаются ровно еще два оператора из его исходного оператора псевдонима :
[statement A]
всегда работает[statement B]
выполняется, если[statement A]
был успех[statement C]
выполняется, если[statement A]
был сбой
Операторы A, B и C всегда выполняются лениво , т.е. они оцениваются на лету во время выполнения.
По завершении выполнения команда с псевдонимом помечается тем же флагом успеха или неудачи, что и оператор B или C, в зависимости от того, какая команда была выполнена . ( Сами псевдонимы не нужно помечать, поскольку они не могут встречаться внутри себя.)
Псевдоним Пример 1
Скажем, мы хотим новую команду, которая увеличивает переменную в
frog
два раза. Это псевдоним заявления достигает этого:a increment_frog_twice i frog i frog d frog
Оператор A (
i frog
) всегда выполняется и всегда помечается как успешный, поэтому оператор B (i frog
) также всегда выполняется, иfrog
, следовательно, переменная увеличивается на 2. Командаincrement_frog_twice
всегда помечается как успешная, поскольку оператор B всегда выполняется, а B всегда является успех . Оператор C (d frog
) никогда не выполняется.Итак, вывод
a increment_frog_twice i frog i frog d frog p frog increment_frog_twice p frog
было бы
frog = 0 frog = 2
Мы можем обобщить этот пример, чтобы любая переменная могла быть увеличена в два раза, дав аргументированной команде-псевдониму.
В операторе псевдонима положительные целые числа 1, 2, 3 и т. Д. Представляют 1-й, 2-й, 3-й и т. Д. Аргументы, передаваемые в команду с псевдонимом. (Эти аргументы могут быть простыми переменными или ссылками на сами переменные.) Эти числа могут появляться только в аргументах операторов A, B и C в операторе псевдонимов . Для них не имеет смысла появляться в другом месте.
Псевдоним Пример 2
Это обобщает последний пример - любая переданная переменная
increment_twice
будет увеличена на 2, потому что1
это ссылка на первый переданный аргумент:a increment_twice i 1 i 1 d 1 #never reached p toad increment_twice toad p toad
Результатом этой программы будет
toad = 0 toad = 2
Затем мы можем создать псевдоним другой команды, которая принимает два аргумента и вызывает
increment_twice
оба из них:a increment_twice i 1 i 1 d 1 #never reached a increment_both_twice increment_twice 1 increment_twice 2 d 1 #never reached increment_both_twice platypus duck p platypus p duck
Выход здесь будет
platypus = 2 duck = 2
Важно понимать, что псевдонимные команды могут быть рекурсивными, поскольку именно в этом заключается их истинная сила. Например, мы можем сделать команду, которая устанавливает любую переданную переменную в 0:
Псевдоним Пример 3
Команда
set_to_zero
принимает один аргумент и устанавливает свою переменную в 0 и помечается как успешная после завершения:a set_to_zero d 1 set_to_zero 1 i _dummy_ i oryx i oryx i oryx p oryx set_to_zero oryx p oryx
Результатом этой программы будет
oryx = 3 oryx = 0
Происходит то, что когда
set_to_zero oryx
выполняется,d 1
успешно уменьшаетсяoryx
с 3 до 2, затемset_to_zero 1
вызывается, что аналогичноset_to_zero oryx
повторному вызову . Таким образом, процесс повторяется до тех пор, покаd 1
не произойдет сбой , останавливая рекурсию и увеличивая_dummy_
переменную, чтобы получить успех .
Вызов
Напишите программу, которая может выполнять код Prindeal точно так же, как описано выше. Возьмите код Prindeal через стандартный ввод, командную строку или в виде текстового файла. Распечатайте вывод программы Prindeal на стандартный вывод или ближайшую альтернативу вашего языка.
Кроме того, вы можете написать функцию, которая принимает код в виде строки и печатает или возвращает строку вывода.
Кроме того, вы можете предположить, что:
- Входной код Prindeal будет содержать только переводы строк и печатный ASCII и (опционально), что он заканчивается пустой строкой.
- Код ввода будет действительным Prindeal - правильно сформированный и синтаксически правильный.
- Выполнение кода не приведет к возникновению бесконечных циклов и недопустимых ссылок на команды, которые не были определены, или аргументы, которые не были заданы.
- Названия команд
p
,i
,d
, иa
никогда не будет совмещенным над. (Вы не можете предполагать, что переменные не будут иметь этих имен.)
Кроме того, не имеет значения, что значения вашей переменной не являются целыми числами с произвольной точностью, так как будут проверяться только числа меньше 1000. Также хорошо, если у вашего языка есть рекурсивные ограничения (такие как Python ), с которыми могут столкнуться более сложные программы Prindeal, пока работает тестовая программа ниже.
Тестовая программа
Вот большая программа Prindeal, которая создает операции сложения, умножения и возведения в степень посредством использования фиктивных переменных (начиная с _
условного обозначения) и множества вспомогательных псевдонимов:
#Command Definitions:
a s #flag as a success
i _
d _
d _
a f #flag as a failure
d _
d _
d _
a z #1 = zero
d 1
z 1
s
a n #1 = one
z 1
i 1
s
a move #2 += 1, 1 = zero
moveH 1 2
move 1 2
s
a moveH #move helper
d 1
i 2
f
a dupe #2 += 1, 3 += 1, 1 = zero
dupeH1 1 2 3
dupe 1 2 3
s
a dupeH1 #dupe helper
d 1
dupeH2 2 3
f
a dupeH2 #dupe helper
i 1
i 2
s
a copy #2 = 1
z 2
copyH 1 2
s
a copyH #copy helper
dupe 1 2 _copy
move _copy 1
s
a addTo #1 += 2
copy 2 _add
#testing comments #
move _add 1#in weird places # just because #
s
#it's a g##d idea
###
a add #1 = 2 + 3
#its a good idea
z 1
addH 1 2 3
s
##
#
a addH #add helper
#this is a comment
addTo 1 2 #as is this
addTo 1 3
s
a mul #1 = 2 * 3
mulH1 1 2
mulH2 1 3
s
a mulH1 #mul helper
z 1
copy 2 _mul
s
a mulH2 #mul helper
mulH3 1 2
mulH2 1 2
s
a mulH3 #mul helper
d _mul
addTo 1 2
f
a mulBy #1 *= 2
mul _mulBy 1 2
copy _mulBy 1
s
a pow #1 = 2^3
powH1 1 3
powH2 1 2
s
a powH1 #pow helper
n 1
copy 2 _pow
s
a powH2 #pow helper
powH3 1 2
powH2 1 2
s
a powH3 #pow helper
d _pow
mulBy 1 2
f
#Running Tests:
p A
p B
p C
n A #A = 1
n B #B = 1
add C A B #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B #d = d * B = 6 * 3 = 18
p ____
p d
d A #A = A - 1 = 1 - 1 = 0
mulBy d A #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C
(Если вы играете с этим кодом, имейте в виду, что многие команды завершатся неудачно, если одна и та же переменная будет указана несколько раз в качестве аргумента. Это легко исправить, но в результате получается более длинный код.)
Ваш переводчик Prindeal должен быть в состоянии произвести точный вывод:
A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729
счет
Самый короткий код в байтах побеждает. Tiebreaker переходит на более раннюю подачу.
Бонус Брауни: написать классную программу на Приндее. Я реализовал сложение и умножение, вы можете сделать вычитание или деление?
источник
p
, а затемp p
, что бы вывести 1, верно?Ответы:
Pyth,
162136 байтДемонстрация.
Гольф 26 символов, встраивая переменные и изменяя
I
иE
основанный поток управления на?
и.x
основанный поток управления.Впервые у меня закончились переменные в Pyth. Каждая переменная в Pyth (
bdkGHNTY
иJK
) использовалась, и я хотел использоватьb
в качестве новой строки. К счастью, я смог использоватьN
две совершенно разные вещи в разных частях программы, и это все еще работает.Ungolfed (запустить с -m):
источник
Python 2,
600584397373 байтаЭто мое собственное решение для игры в гольф. Любой желающий может улучшить его или следовать его логике в своем собственном ответе, пока дается атрибуция.
Самое приятное в том, что рекурсия не выполняется, поэтому у нее никогда не будет проблем с пределом рекурсии Python. Например, программа Sp Countup Prindeal может работать бесконечно долго.
Это программа, которая принимает в строке программы в кавычках экранированные строки, например
'p _MyVariable_321\np screaming_hairy_armadillo'
.Я взял различные сигналы игры в гольф от Sp - х и PIETŲ в ответах. Спасибо, парни :)
источник
Python 3
345336335328 байт(-6 байт благодаря @orlp)
Все еще играю в гольф. Предполагается, что программа хранится в файле с именем
P
.Размещение вызовов
f
внутри лямбдыd
позволило бы сэкономить несколько байтов, но это сделало бы, что последний тестовый случай достиг максимальной глубины рекурсии.Некоторые программы Prindeal
Бесполезная программа вычитания
Вот бесполезная программа вычитания . Это бесполезно, потому что, даже если оно правильно вычитается, оно не возвращает соответственно успех / неудачу.
Выход должен быть:
Посчитать
Считает вверх и печатает
n
навсегда. Может работать как тест на скорость интерпретатора (остерегайтесь длинных трассировок при прерывании клавиатуры).источник
l[:(l+"#").find("#")]
и все его вариации могут быть заменены простымиl.split('#')[0]
.find
том, что я забыл, что ты мог бы просто,split
даже если#
бы там не было. Спасибо :)JavaScript (ES6), 273
258Редактировать Исправлены ошибки и добавлен настоящий набор тестов.
Не считая ведущих пробелов и переносов.
Конечно, можно играть в гольф немного больше.
Слишком усталый, чтобы писать объяснения сейчас, я думаю, что это хороший пример использования замыканий для поддержания временных значений (параметров).
Протестируйте выполнение сниппета в любом браузере, совместимом с EcmaScript 6 (в частности, не Chrome, не MSIE. Я тестировал на Firefox, Safari 9 мог пойти)
источник
C # 6, 653 байта
Вот моя запись среди моря Python ...
Расширено и прокомментировано:
Чтобы использовать его, просто создайте экземпляр класса и вызовите
R()
метод, например:источник
Обыкновенный Лисп,
+758646619Вставьте это
file.lisp
и назовите, напримерsbcl --script file.lisp
; ввод читается из стандартного потока ввода.Эта версия анализирует расширенный набор Prindeal: без особых сложностей вы можете получить доступ ко всем Common Lisp из источника Prindeal. Я считаю это особенностью переводчика.
Комментируемая версия
пример
Если мы заменим
eval
наprint
в цикле read / eval, то увидим, что оценивается:Macroexpansion
Если мы выберем следующее определение псевдонима:
... мы можем видеть ссылки на переменную с именем,
g
которая нигде не найдена в лексической области видимости. Но после макроразложения вот фактический код, который оценивается:Теперь
g
ссылается на список аргументов определяемой функции.источник
Python 2, 486 байт
Это эталонное решение, в котором я играл больше (в настоящее время - 98 байт).
Изменения (что я помню):
[l,l[:l.find('#')]]['#'in l]
).V[k]=-~V[k]if k in V else 1
)k=s[1]
)print
автоматическое добавление пробелов (print k,'=',V.get(k,0)
)'0'<t[0]<':'
)r
чтобы сохранитьreturn
сmap(str.split,c[:3]))
)источник
Python 3, 1322 байта
Golfed:
Ungolfed:
Использование:
Где
c
текстовое содержание.Примеры:
Однострочные строки принимаются:
P("p cat")
P("p dog\ni dog\np dog")
Многолинейные строки также принимаются:
Или:
И т.п.
Заметки:
Это работает правильно для всех тестовых случаев, но достигает предела рекурсии:
Отсюда
sys.setrecursionlimit(2000)
.источник
Python -
695688 байт<TAB>
буквальный символ табуляцииисточник
C ++, 1111 байт
Это C ++ - настолько идиоматичный, насколько я мог.
Это означает, что он должен быть более C ++ и меньше C-ish.
Это также означает, что он больше, чем эквивалентная программа на Си.
Я думаю, что C ++ соперничает с Java по многословной стандартной библиотеке.
Компилируется с VS2013 и g ++ 4.9.2 (с -std = c ++ 11)
Ниже оригинал. Если кто-нибудь может придумать способ сделать его более идиоматичным и более коротким одновременно, пожалуйста, дайте мне знать.
источник
Хаскелл, 1009
Я сделал все возможное, чтобы играть в гольф; мой код без ключа состоял из более чем 3000 символов. На данный момент я не могу вспомнить, что делают все функции, поэтому играть в гольф больше значит догадываться, что сломает, а что нет.
источник