99 (произносится как «девяносто девять») - это совершенно новый язык эзотерического программирования (не путать с 99 , обратите внимание на курсив). Ваша задача в этой задаче - написать переводчика для 99, который будет максимально коротким. Представление с наименьшим количеством байтов выигрывает. Tiebreaker переходит к представлению, опубликованному первым.
Поскольку этот вопрос немного глубже, чем обычно, и мне не терпится увидеть хорошие ответы, я буду награждать награду в 250 представителей своим любимым ответом (не обязательно победителем).
99 Спец
99 - императивный язык. Каждая строка в программе 99 представляет собой один оператор , и во время выполнения указатель инструкции начинается с верхней строки и проходит по порядку через каждую из последующих строк, выполняя их по пути. Программа заканчивается, когда последняя строка была выполнена. Операторы Goto могут перенаправлять путь указателя инструкции.
Новая строка, пробел и 9
единственные три символа, которые имеют значение в программе 99 . Все остальные персонажи полностью игнорируются. Кроме того, завершающие пробелы в каждой строке игнорируются, и несколько пробелов в строке читаются как один пробел. («Новая строка » относится к любой обычной кодировке разрыва строки . Не имеет значения, какой из них использует ваш интерпретатор.)
Итак, эта программа:
9 BLAH 99 9a9bb9c9
9 this line and the next have 6 trailing spaces 9
Идентичен этой программе:
9 99 9999
9 9
переменные
Все переменные в 99 имеют имена, которые связаны одним или несколькими 9
( 9+
в регулярном выражении). Так , например, 9
, 99
и 9999999999
все различные переменные. Естественно, их бесконечно много (за исключением ограничений памяти).
Значением каждой переменной является целое число произвольной точности со знаком. По умолчанию каждой переменной присваивается собственное числовое представление. Поэтому, если он не был переназначен, значением переменной 9
является число 9, а значением переменной 99
является число 99 и так далее. Вы можете думать об этом как об обработке переменных как простых чисел, пока они не будут явно назначены.
Я буду использовать V
для ссылки на произвольное имя переменной ниже.
Каждый экземпляр V
может быть заменен 9
, 99
, 999
, 9999
и т.д.
Заявления
В 99 есть пять различных типов операторов . Каждая строка в программе 99 содержит ровно одно утверждение.
Синтаксис, описанный здесь, предполагает, что все посторонние символы были удалены, все конечные пробелы были удалены, и все последовательности из нескольких пробелов были заменены одиночными пробелами.
1. Нет операции
Пустая строка не является опцией . Это ничего не делает (кроме увеличения указателя инструкции).
2. Выход
V
Одна переменная V
в строке выводит эту переменную в стандартный вывод.
Если V
имеет нечетное число 9
'( 9
, 999
и т. Д.), То V
будет напечатано целое число, деленное на 9 (в десятичном виде).
Если V
имеет четное число 9
s ( 99
, 9999
и т. Д.) , То будет напечатан символ ASCII с кодом, V
разделенным на 9, mod 128. (Это (V / 9) % 128
значение от 0 до 127.)
Пример : программа
9
9999
будет печатать 1W
. Первая строка печатается, 1
потому что 9/9 - 1. Вторая строка печатается, W
потому что 9999/9 - 1111, а 1111 mod 128 - 87, а 87 - код символа для W
.
Обратите внимание, что разрывы строк не выводятся между токенами вывода. \n
должен быть явно напечатан для разрыва строки.
3. Ввод
V
Одна переменная V
в строке с начальным пробелом принимает входные данные из stdin и сохраняет их в этой переменной.
Если V
имеет нечетное число 9
's, то пользователь может ввести любое целое число со знаком, и V
будет установлено в 9 раз больше этого значения.
Если V
имеет четное число 9
«s», то пользователь может ввести любой символ ASCII, и для него V
будет установлено значение, в 9 раз превышающее его код символа.
Пример : данный -57
и A
как вход, эта программа
9
9
99
99
будет выводить -57A
. Внутри переменная 9
будет иметь значение -513 и 99
585.
Ваш переводчик может предположить, что входные данные всегда синтаксически действительны.
4. Назначение
Это утверждение может быть сколь угодно длинным. Это две или более переменных в строке, разделенных пробелами:
V1 V2 V3 V4 V5 ...
Это присваивает сумму всех с четными индексами минус сумма с нечетными индексами (исключая ). Назначения по значению, а не по ссылке.V1
V
V
V1
Это может быть переведено на большинство языков как .V1 = V2 - V3 + V4 - V5 + ...
Итак, если есть только две переменные, это нормальное присваивание:
V1 V2
→ V1 = V2
Если их три, то это вычитание:
V1 V2 V3
→ V1 = V2 - V3
И знак +
/ -
продолжает переключаться с каждой дополнительной переменной:
V1 V2 V3 V4
→ V1 = V2 - V3 + V4
Пример : эта программа выдаст 1110123
:
999 Prints triple-nine divided by nine (111).
999 9 9 Assigns triple-nine to zero (nine minus nine).
999 Prints triple-nine divided by nine (0)
9 999 9 Assigns single-nine to negative nine (zero minus nine).
999 999 9 Adds nine to triple-nine (really subtracts negative nine).
999 Prints triple-nine divided by nine (1).
999 999 9 Adds nine to triple-nine (really subtracts negative nine).
999 Prints triple-nine divided by nine (2).
999 999 9 Adds nine to triple-nine (really subtracts negative nine).
999 Prints triple-nine divided by nine (3).
5. Перейти (прыгать, если все ноль)
Это утверждение также может быть сколь угодно длинным. Это две или более переменных в строке, разделенных пробелами, с начальным пробелом :
V1 V2 V3 V4 V5 ...
Если некоторые из значений, кроме того , ненулевые, то это ведет себя так же, как отсутствие операции. Указатель инструкции перемещается на следующую строку как обычно.V1
Если все значения, кроме того, равны нулю, указатель инструкции перемещается на номер строки . Строки индексируются нулем, поэтому, если ноль, указатель перемещается на верхнюю строку. Программа завершается (обычно без ошибок), если она отрицательна или превышает максимально возможный индекс (количество строк минус одна).V1
V1
V1
V1
Обратите внимание, что здесь не было разделено на 9. И поскольку невозможно, чтобы переменная была значением, не кратным 9, можно перейти только к номерам строк, кратным 9.V1
Примеры:
Эта программа напечатает 1
навсегда:
9 Prints single-nine divided by nine (always 1).
99 9 9 Assigns double-nine to zero.
99 99 Jumps to line zero (top line) if double-nine is zero.
Эта программа
99999999 Print G.
999 99 Set triple-nine to ninety-nine.
9999999999 9999999999 9999999999 99 99 9 9 999 999 Set 10-nine to zero.
99999999999 9999999999 Set 11-nine to zero.
999 Print triple-nine's value divided by nine. (This is the ninth line.)
99999999 Print G.
999 999 9 Subtract nine from triple-nine.
99999 999 Jump to line 5-nines if triple-nine is zero (ends program).
9 99999999999 9999999999 Jump to line nine if 10-nine and 11-nine are zero (always jumps).
выведет числа от 11 до 1 в порядке убывания, окруженные G
символами:
G11G10G9G8G7G6G5G4G3G2G1G
дополнительные детали
Идеальный интерпретатор будет запускаться из командной строки с именем файла программы 99 в качестве аргумента. Ввод / вывод также будет выполняться на лету в командной строке.
Вы можете, однако, просто написать функцию интерпретатора, которая принимает в программу строку, а также список входных токенов (например ["-57", "A"]
). Функция должна напечатать или вернуть выходную строку.
Немного разные способы запуска интерпретатора и обработки ввода / вывода хороши, если эти опции невозможны на вашем языке.
Бонус: Напишите что-нибудь классное в 99, и я с удовольствием выложу это в качестве примера.
- Вот Pastebin из аккуратной программы "99 бутылок пива" из ответа Mac .
Надеюсь, вам понравился мой 99-й вызов! : D
источник
Ответы:
CJam, 157 байтов
Попробуйте онлайн:
объяснение
Попытка отформатировать это с правильными отступами и комментариями, вероятно, займет вечность, поэтому я просто дам алгоритмическое резюме.
Код представляет собой блок, аналог CJam для анонимных функций. Блок ожидает строку программы и список входных данных в стеке при выполнении.
Инициализация состоит из трех этапов. Во-первых, список ввода сохраняется. Затем каждый символ в программе, который не имеет смысла, удаляется, а результат разбивается на список строк и сохраняется. Наконец, список переменных инициализируется. Этот список отображает каждую переменную, проиндексированную по длине имени, на ее значение, деленное на 9 (переменная никогда не может содержать значение, не кратное 9, и все операции, кроме goto, извлекают выгоду из этого изменения). Список инициализируется до длины самой длинной строки, которая является верхней границей самого длинного доступного имени. Есть также небольшая неявная инициализация из-за начальных значений переменных: номер строки равен 0, а входной индекс равен -1.
Интерпретатор реализован так, как и следовало ожидать: цикл, который читает следующую строку, увеличивает номер строки и выполняет строку, в то время как номер строки указывает на существующую строку. Разбор строки сначала проверяет, что строка не пустая, затем ветвится в зависимости от того, является ли арность 1 или> 1, затем ветвится в зависимости от того, был ли начальный пробел. Эти четыре ветви эмулируют четыре (исключая неоперационные) операции в основном простым способом, хотя агрессивно играют в гольф, как и все остальное. Возможно, одна оптимизация примечания состоит в том, что, поскольку допустимая входная последовательность всегда должна создавать элемент типа, ожидаемого программой, я исключил создание отдельных случаев для ввода на основе длины имени переменной. Просто предполагается, что элемент, считываемый из списка ввода, имеет ожидаемый тип.
источник
128%
на128,=
.Python 3,
421414410404388395401 байтGolfed:
Ungolfed:
Практически просто буквальная реализация спецификации, насколько я могу понять.
Запустите из командной строки, указав в качестве единственного аргумента файл с исходным кодом 99 (например, последний пример из OP):
В качестве дополнительного бонуса, вот (довольно плохая) реализация «99 бутылок» в 99 : http://pastebin.com/nczmzkFs
источник
else
после числа можно удалить, но когда я попробовал это раньше, я получил синтаксическую ошибку. Ваши другие советы очень ценятся!goto
процедуре и при получении значения переменной по умолчанию). Что касается пользователя языка, это не имеет значения.else
сам по себе, только пространство перед ним. Например3*n+1if n%2else n//2
.else
. Например, я попытался заменитьprint(w if L(e)%2 else chr(w%128))
наprint(w if L(e)%2else chr(w%128))
и получил синтаксическое исключение.e
илиE
, и (из комментариев) не для0or
ни того, ни другого.Common Lisp,
1180857+837836 байтЯ знаю, что это не победит, но я получил удовольствие от игры в гольф. Мне удалось удалить 343 байта, что составляет более двух 99 интерпретаторов, написанных на CJam.
Кроме того, довольно забавно, что чем больше я пытаюсь сжать его, тем больше меня убеждают, что для Common Lisp компилировать код короче, чем пытаться интерпретировать его на лету.
есть один,
tagbody
чтобы выполнить 2 цикла:локальные переменные объявлены в
&aux
Ungolfed, прокомментировал
Мы используем стандартный ввод / вывод во время оценки, то есть мы используем стандарт
read
иprinc
функции. Следовательно, полученный код можно сделать исполняемым в командной строке, как показано ниже.При запуске 99 программ входы не полностью очищены : предполагается, что пользователь знает, какие значения ожидаются.
Единственные возможные издержки времени выполнения могут возникнуть при переходе, так как мы должны оценить значение переменной и сопоставить это значение с меткой. Кроме того, переводчик должен быть достаточно эффективным.
Основываясь на умном наблюдении от Mac, что нам не нужно делить и умножать на 9 каждый раз, текущей версии удается никогда не делить и не умножать на 9 во время выполнения.
пример
Если мы заменим
defmacro
наdefun
, мы увидим сгенерированный код. Например:Вот результирующий код:
После выполнения выдает «G11G10G9G8G7G6G5G4G3G2G1G»
Командная строка
Мы можем создать исполняемый файл, выгрузив ядро и указав
toplevel
функцию. Определите файл с именем,boot.lisp
куда вы положилиdefmacro
, и затем напишите следующее:Запуск
sbcl --load boot.lisp
дает следующий вывод:Затем запустите скомпилированную программу 99 :
99 бутылок
Если вам интересно, вот скомпилированный код для программы на 99 бутылок, написанный в ответе Mac : http://pastebin.com/ZXe839CZ (это старая версия, где у нас есть
jmp
иend
метки, и окружающая лямбда и более симпатичная арифметика).Вот исполнение с новой версией, чтобы доказать, что оно все еще работает: http://pastebin.com/raw.php?i=h73q58FN
источник
TI-84 Basic (скрипт калькулятора),
376373377381 байтЕсли он работает на калькуляторе TI-84, вы сможете использовать его в стандартизированном тесте ... так что это полезно;)
Минимальная версия операционной системы - 2,53MP (MathPrint) из-за сигма суммирования
PS ASCII руководящие принципы не могли быть точно выполнены, но в TI-Basic
:
это новая строка. Таким образом, все действительные символы новой строки в коде означают, что:
или#
в начале каждой строки не требуется. Начало токенов:
и#
просто различие между комментариями и кодом.Оригинальный шестнадцатеричный дамп (376 байт)
Редактирование # 1 - Оптимизировано 3 байта с использованием наблюдения Mac. Редактирование # 2 и # 3 - Исправлены ошибки, обнаруженные Runer112.
источник
#
, для комментариев? (Примечание: комментарии в реальном коде реализованы в виде строки с только незамкнутой строкой, которая забивает ответ)Ans
ввод перезаписывается, поэтомуAns->Str0
в строке 6 произойдет ошибка, есть несколько случаев, когда аргумент длиныsub()
команды может быть нулевым, что приводит к ошибке,Ans
в строке 11 будет строка такAns-J
будет и ошибка ... И я только посмотрел примерно на первую половину программы.sub()
команда может иметь нулевую длину и выдавать ошибку. И как толькоsub()
вызовы исправлены, я боюсь, что это может выявить больше проблем.9
является число 9, а значением переменной99
является число 99, и так далее." И строки длины 0 могут быть получены с помощью подобных средств""
, но это своего рода ошибка, которая, по сути, ни одна команда манипуляции со строками не может использовать или производить пустую строку, в том числеsub()
.С 426
458 481 497Edit Возможно, я захожу слишком далеко, но это работает с Visual C: удален stdio.h, с использованием int вместо FILE * для fopen и getc
Изменить 2 Изменить порядок выполнения шага, больше беспорядка, 32 символа сохранены
Автономная консольная программа, имя программы берется из командной строки и ввод / вывод через консоль.
Старый стиль K & R, тип по умолчанию int для глобальных переменных и параметров. Предполагая, что EOF определен как -1 (как и в каждой реализации C, о которой я знаю)
Компилируется с предупреждениями с помощью Visual Studio 2010 (консольный проект C32 для Win32, компилируется как C). Компилируется в Ideone, но не может работать, так как ему нужен файл.
Первый шаг, исходный код читается и анализируется, каждая строка сохраняется в виде последовательности целых чисел на основе чисел 9. Если есть пробел, первая цифра отрицательна. Итак:
9 BLAH 99 9a9bb9c9
(9 99 9999
) становится.-1,2,4
Есть ярлык - не такой законный: все коды ascii, меньшие чем ', считаются символами новой строки.На этом этапе все используемые переменные предварительно инициализируются.
Шаг выполнения соответствует спецификациям, без излишеств, за исключением сохраненных номеров, разделенных на 9.
Более читаемый код (надеюсь), добавлены пробелы и переводы строк
источник
Haskell, 550 байт
Пример запуска с программой «обратный отсчет», сохраненной в файле
i.99
Безголовая версия:
источник
JavaScript (ES6) 340
352Функция с 2 параметрами
Третий необязательный параметр (по умолчанию 10k) - это максимальное количество итераций - мне не нравится программа, которая работает вечно
JSFiddle для тестирования
источник
к / к,
490469,
Скрипт представляет собой смесь q и k, поэтому сначала я определю несколько ключевых слов q, которые я хочу использовать несколько раз в k функциях. (в основном #define макросы)
f
читает переданный в программу файл и удаляет ненужные символыm
берет список / вектор и умножает нечетные индексы на -1b
это просто пустая функция, используемая для неоперативных линийp
это функция печати.K
это функция, которая проверяет переменную. Если переменная существует, она возвращает ее, в противном случае она просто возвращает литерал.v
это функция присваивания.g
это функция перехода.r
берет строку и решает, какую операцию нужно применить.И, наконец, я просто перебираю
f
список строк, используяn
в качестве итератора. Функция goto будет обновляться поn
мере необходимости.источник
Perl,
273 266 255 244238Добавлены разрывы строк для ясности.
Имя программы берется из командной строки:
Каждая строка программы конвертируется в код Perl, например:
Подробнее
источник