Цель этой задачи - (в конечном итоге) вывести все возможные программы остановки на выбранном вами языке. Поначалу это может показаться невозможным, но вы можете сделать это с помощью очень тщательного выбора порядка выполнения.
Ниже приведена диаграмма ASCII, чтобы проиллюстрировать это. Пусть столбцы представляют нумерацию каждой возможной программы (каждая программа представляет собой конечное число символов из конечного алфавита). Пусть каждая строка представляет отдельный шаг в выполнении этой программы. X
Представляют исполнение в исполнении этой программы в то время шага.
step# p1 p2 p3 p4 p5 p6
1 X X X X X X
2 X X X X X
3 X X X X
4 X X X X
5 X X X
6 X X
7 X X
8 X X
9 X X
∞ X X
Как вы можете сказать, программы 2 и 4 не останавливаются. Если бы вы выполняли их по одному, ваш контроллер застрял бы в бесконечном цикле, который является программой 2, и никогда не выводил бы программы 3 и выше.
Вместо этого вы используете подход ласточкин хвост . Буквы представляют возможный порядок выполнения для первых 26 шагов. Это *
места, где эта программа остановлена и выведена. Это .
шаги, которые еще не были выполнены.
step# p1 p2 p3 p4 p5 p6
1 A C F J N R V
2 B E I M Q * Z
3 D H * P U
4 G L T Y
5 K O X
6 * S .
7 W .
8 . .
9 . .
∞ . .
Требования к целевому языку
Целевой язык (который интерпретируется параллельно) должен быть завершен по Тьюрингу. Кроме этого, это может быть любой язык, полный по Тьюрингу, включая подмножества по Тьюрингу из гораздо более крупных языков. Вы также можете свободно интерпретировать такие вещи, как системные правила циклических тегов. Вам также разрешается создавать язык для тестирования, если вы можете показать, почему он завершен по Тьюрингу.
Например, если вы выберете тестирование brainfuck, то лучше всего протестировать только []-+<>
подмножество, так как ввод не поддерживается, а вывод просто отбрасывается (см. Ниже).
Когда дело доходит до программы «контроллер» (которую вы играете в гольф), особых требований нет. Нормальные языковые ограничения применяются.
Как создать бесконечный список программ
Большинство языков программирования могут быть представлены в виде последовательности символов из конечного алфавита. В этом случае сравнительно легко перечислить список всех возможных программ в порядке увеличения длины. Используемый алфавит должен соответствовать требованиям целевого языка. В большинстве случаев это печатная версия ASCII. Если ваш язык поддерживает Unicode в качестве дополнительной функции, вам не следует тестировать каждую возможную комбинацию символов Unicode, только ASCII. Если ваш язык использует только []-+<>
то, не проверяйте различные комбинации символов ASCII «комментарий». Такие языки, как APL, будут иметь свои собственные специальные алфавиты.
Если ваш язык лучше всего описывается неалфавитным способом, например, Fractran или Turing Machines, то существуют другие одинаково допустимые методы создания списка всех возможных допустимых программ.
Интерпретация постоянно растущего списка программ
Ключевой частью этой задачи является написание параллельного интерпретатора для растущего списка программ. Есть несколько основных шагов для этого:
- Добавить конечное количество программ в список
- Интерпретировать каждую программу в списке индивидуально в течение ограниченного периода времени. Это может быть достигнуто путем выполнения одного шага инструкции для каждого. Сохранить все состояния.
- Удалить все завершающие / генерирующие ошибки программы из списка
- Вывести полностью остановленные * программы
- Добавьте еще несколько программ в список
- Моделируйте каждую программу по очереди, продолжая выполнение старых программ, где она остановилась
- Удалить все завершающие / генерирующие ошибки программы из списка
- Вывести полностью остановленные * программы
- повторение
* Вы должны выводить только программы, которые останавливаются чисто. Это означает, что во время выполнения не было никаких синтаксических ошибок или необработанных исключений. Программы, которые запрашивают ввод, также должны быть завершены без их вывода. Если программа производит вывод, вы не должны его прекратить, просто выбросьте вывод.
Больше правил
- Вы не должны создавать новые потоки, содержащие тестируемые программы, так как это переносит работу по распараллеливанию на основную ОС / другое программное обеспечение.
- Редактировать: чтобы закрыть возможные будущие лазейки, вам не разрешено
eval
(или любая связанная функция) часть кода тестируемой программы. Вы можетеeval
кодовый блок из кода переводчика. (Ответ BF-in-Python все еще действителен в соответствии с этими правилами.) - Это код-гольф
- Язык, на котором вы пишете свою заявку , не обязательно должен совпадать с языком, который вы тестируете / выводите.
- Вы должны предположить, что ваша доступная память не ограничена.
- При доказательстве полноты по Тьюрингу вы можете предположить, что входные данные жестко закодированы в программе, а выходные данные могут быть считаны из внутреннего состояния программы.
- Если ваша программа выводит себя сама, это, вероятно, неправильно или полиглот.
источник
"If your program outputs itself, it is probably wrong or a polyglot."
Ответы:
Subleq OISC в Python,
317269 байтhttps://esolangs.org/wiki/Subleq
Программа subleq - это расширяемый список целых чисел (p) и указатель инструкции (i). Этот вариант subleq использует относительную адресацию, которая, как предполагает вики-страница обсуждения, необходима для обеспечения полноты при ограниченных значениях. Каждый тик выполняется операция
p[i+p[i+1]]-=p[i+p[i]]
, а затем,i+=p[i+2]
если результат операции был <= 0, в противном случаеi+=3
. Если я когда-либо отрицательный, программа останавливается.Эта реализация проверяет каждую программу, чье начальное состояние состоит из неотрицательных целых чисел (0-9) с начальным указателем команд 0.
Выходная информация обратная, по соображениям игры в гольф. Вышеприведенная спецификация может быть переформулирована в обратном порядке, но тогда не будет соответствовать коду, используемому в реализации, поэтому я не описал ее таким образом.
РЕДАКТИРОВАТЬ: Первая программа, которая демонстрирует простой неограниченный рост - это 14283, который уменьшает значение в ячейке памяти 6 и записывает явный 0 (в отличие от неявного 0 в каждой ячейке) в следующую отрицательную ячейку, каждые три тика.
источник
Побитовый циклический тег в CJam,
98878477 байтПоскольку это бесконечный цикл, вы не можете напрямую проверить это в онлайн-переводчике. Тем не менее, вот альтернативная версия, которая считывает количество итераций из STDIN, с которыми вы можете поиграть. Чтобы протестировать полную программу, вам потребуется интерпретатор Java .
BCT - это минималистский вариант систем циклических меток . Программа определяется двумя двоичными строками: (циклическим) списком инструкций и начальным состоянием. Чтобы упростить мою жизнь при печати программ, я определил свою собственную запись: каждая из строк дана как массив целых чисел в стиле CJam, и вся программа заключена в
[[...]]
, например,Я также запрещаю пустые начальные состояния или пустые списки команд.
Инструкции в BCT интерпретируются следующим образом:
0
, удалите ведущий бит из текущего состояния.1
, прочитайте другой бит из списка инструкций, вызовите этоX
. Если начальный бит из текущего состояния равен1
, добавьтеX
к текущему состоянию, в противном случае ничего не делайте.Если текущее состояние становится пустым, программа останавливается.
Первые несколько программ остановки
Если вы хотите увидеть больше, ознакомьтесь с версией в онлайн-переводчике, на которую я ссылался выше.
объяснение
Вот как работает код. Чтобы отследить ласточкин хвост, у нас всегда будет массив в стеке, который содержит все программы. Каждая программа является парой внутреннего представления программного кода (например
[[0 1 0] [1 0]]
), а также текущего состояния программы. Мы будем использовать только последнее для выполнения вычислений, но нам нужно будет помнить первое, чтобы напечатать программу, как только она остановится. Этот список программ просто инициализируется в пустой массив сL
.Остальная часть кода представляет собой бесконечный цикл,
{...1}g
который сначала добавляет одну или несколько программ в этот список и вычисляет один шаг для каждой программы. Программы, которые останавливаются, распечатываются и удаляются из списка.Я перечисляю программы, считая двоичное число. Начальная цифра убирается, чтобы мы могли получить все программы с ведущими нулями. Для каждого такого усеченного двоичного представления я нажимаю одну программу для каждого возможного разделения между инструкциями и начальным состоянием. Например, если счетчик в данный момент равен
42
, его двоичное представление равно101010
. Мы избавляемся от лидирующих1
и выталкиваем все непустые разбиения:Так как нам не нужны пустые инструкции или состояния, мы запускаем счетчик с 4, что дает
[[[0] [0]]]
. Это перечисление выполняется с помощью следующего кода:Остальная часть кода отображает блок в список программ, который выполняет один шаг вычисления BCT для второй половины этих пар и удаляет программу, если она останавливается:
источник
Brainfuck в Python, 567 байтов
Относительно простое решение, поскольку Brainfuck едва ли не самый сложный язык для написания интерпретатора.
Эта реализация Brainfuck имеет указатель данных, начинающийся с 0, допускается принимать только положительное значение (считается ошибкой, если он пытается перейти влево от 0). Ячейки данных могут принимать значения от 0 до 255 и переноситься. 5 действительных инструкций
><+[]
(-
ненужны из-за упаковки).Я думаю, что теперь все правильно, но трудно быть уверенным, что он печатает все возможные решения, поэтому я могу пропустить некоторые.
Первые несколько выходов:
И список первых 2000: http://pastebin.com/KQG8PVJn
И, наконец, список первых 2000 выходов с
[]
ними: http://pastebin.com/iHWwJprs(все остальные тривиальны, пока они действительны)
Обратите внимание, что выходные данные не в отсортированном порядке, хотя для многих из них может показаться, что программы, которые занимают больше времени, будут напечатаны позже.
источник
[-]
и[+]
должны определенно появляться, потому что содержимое цикла просто пропускается (без переноса).[-]
и[+]
была ошибка , которая должна теперь фиксированной и я обновил с настройками.
? Это не обязательно для подмножества BF, полного по Тьюрингу, и выход должен быть проигнорирован в любом случае. Кроме того, поскольку вы оборачиваете значения ячеек вокруг, я думаю, что вам нужен только один из-
и+
.косые черты в Python,
640498 байтhttps://esolangs.org/wiki////
Программа слэша - это строка, в этом интерпретаторе ограниченная символами '/' и '\'. В этой реализации / - это «1», а «\» - это «0», чтобы можно было играть в гольф с использованием корзины (x) python. Когда интерпретатор встречает \, выводится следующий символ, и оба символа удаляются. Когда он встречает /, он ищет шаблоны поиска и замены как / search / replace /, включая экранированные символы в шаблонах (\\ представляет \ и \ / представляет /). Эта операция замены затем выполняется над строкой несколько раз, пока строка поиска больше не присутствует, затем интерпретация продолжается с самого начала. Программа останавливается, когда она пуста. Программа будет убита, если есть открытый набор / шаблонов или \ без символа после него.
источник
Treehugger на Java,
1,2991,2571,2511,2071,2031,2011,1931,189 байтисточник
Brachylog → Проблема почтовой корреспонденции , 10 байт
Попробуйте онлайн!
Функция, которая является генератором, который генерирует все возможные проблемы почтовой корреспонденции, для которых в конечном итоге решения о грубой перестановке останавливаются. (Известно, что грубое решение проблемы почтовой корреспонденции является завершающей по Тьюрингу операцией.) Ссылка TIO содержит заголовок, который преобразует генератор в полную программу и распечатывает каждый вывод сразу после его создания (таким образом, когда TIO убивает программа из-за того, что потребляет более 60 секунд времени выполнения, вывод, полученный до сих пор, виден).
При этом используется формулировка задачи, в которой строки задаются в виде строк цифр, начальные нули не допускаются, кроме как для
0
себя, решения проблемы, включающей в себя начальные нули, не принимаются, а строка цифр может быть представлена либо как число. или минус число. Ясно, что ни одно из этого не имеет никакого влияния на полноту по Тьюрингу языка (потому что нет необходимости в проблеме корреспонденции после использования цифры ноль вообще).Эта программа работает путем генерации всех возможных решений проблем, а затем работает в обратном направлении, чтобы найти оригинальные программы, которые решаются ими. Таким образом, отдельная программа может выводиться много раз. Неясно, отменяет ли это ответ или нет; обратите внимание, что все программы остановки будут в конечном итоге выводиться по крайней мере один раз (на самом деле, бесконечно много раз, поскольку любая программа, имеющая решения, имеет бесконечно много решений), а программы без остановки никогда не будут выводиться.
объяснение
источник
"Фиолетовый без ввода / вывода" на Цейлоне, 662
Фиолетовый - это самоизменяющийся язык с одной инструкцией, который попросили интерпретировать здесь . Как ввод и вывод не актуальны для решения этой задачи, я извлекал
o
смысл символа из интерпретатора, таким образом, чтобы (потенциально) действительные символы простоa
,b
,A
,B
,i
и1
(последняя только для чтения, а не для записи).Но поскольку Purple самоизменяется (и использует свой исходный код в качестве данных), потенциально полезны также программы, содержащие другие символы, поэтому я решил разрешить в коде все печатаемые (не пробельные) символы ASCII (другие могут быть полезно, но не так легко печатается).
(Вы можете изменить интерпретатор так, чтобы он вместо этого принимал в качестве строки разрешенных символов в качестве аргумента командной строки - переключите закомментированную строку, определяющую
a
ниже. Тогда длина становится 686 байтов.)Мой «параллельный» интерпретатор, таким образом, создает все конечные строки из этих символов (в возрастающей длине и в лексикографическом порядке) и пробует каждый из них.
Purple будет останавливаться без ошибок всякий раз, когда команда, которая будет считана с ленты для выполнения, недействительна - таким образом, нет недопустимых программ и много-много остановок. (Большинство останавливается даже на первом шаге, только некоторые из программ с длиной 3 переходят на второй шаг (и затем останавливаются), первые не останавливающие программы имеют длину 6.
Я думаю, что самая первая не прерывающая программа в том порядке, который испробовал мой интерпретатор, - это то
aaaiaa
, что на первом шагеa
регистр устанавливается в 0 (каким он уже был), а на втором и каждом последующем шаге указатель команды возвращается к 0, вызывая егоiaa
снова выполнить .Я повторно использовал часть кода, написанного для моего интерпретатора «стандартного» Purple , но из-за удаления ввода и вывода мой параллельный интерпретатор становится даже немного короче этого, включая дополнительную логику для выполнения нескольких программ одновременно.
Вот закомментированная и отформатированная версия:
источник
Комбинаторное исчисление SK в Haskell , 249 байтов
Попробуйте онлайн!
Как это работает
Правила оценки по значению для исчисления комбинатора SK следующие:
(а) S xyz ↦ xz ( yz ), для x , y , z в нормальной форме;
(б) K xy ↦ x , для x , y в нормальной форме;
(c) xy ↦ x ′ y , если x ↦ x ′;
(d) xy ↦ xy ′ для x в нормальной форме, если y ↦ y ′ .
Поскольку нас интересует только остановка поведения, мы немного расширяем язык, вводя символ H, который не находится в нормальной форме, но которому «оценивают» все нормальные формы:
(а) S xyz ↦ xz ( yz ), для x , y , z в нормальной форме;
(b ') K x H ↦ x для x в нормальной форме;
(c) xy ↦ x ′ y , если x ↦ x ′;
(d) xy ↦ xy ′ для x в нормальной форме, если y ↦ y ′ ;
(е) S ↦ H;
(е) K ↦ H;
(ж) SH ↦ H;
(h) KH ↦ H;
(я) SHH ↦ H.
Мы считаем, что любое приложение H x является ошибкой во время выполнения и обрабатывается так, как если бы это был бесконечный цикл, и мы упорядочиваем оценки таким образом, чтобы (e) - (i) не производил H, кроме как в контексте, где игнорируется (верхний уровень, любой K x ☐, любой игнорируемый K☐, любой игнорируемый S x ☐ для x в нормальной форме, любой игнорируемый S☐H). Таким образом, мы не влияем на поведение при остановке обычных терминов, не содержащих H.
Преимущества этих измененных правил состоят в том, что каждый нормализуемый термин имеет уникальный путь оценки к H, и что каждый термин имеет конечное число возможных прообразов в ↦. Таким образом, вместо использования подхода ласточкин хвост, мы можем сделать намного более эффективный поиск в ширину всех путей обратной оценки из H.
n
проверяет, находится ли термин в нормальной форме,f
находит все возможные прообразы термина иl
является ленивым бесконечным списком нормализуемых терминов, полученных в результате поиска в ширину из H.источник