Цель этой задачи - (в конечном итоге) вывести все возможные программы остановки на выбранном вами языке. Поначалу это может показаться невозможным, но вы можете сделать это с помощью очень тщательного выбора порядка выполнения.
Ниже приведена диаграмма 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."