Ваша задача проста. Напишите две программы, которые не разделяют символы, которые выводят друг друга.
пример
Две программы P и Q являются взаимоисключающими квинусами, если:
- P выходы Q
- Q выходы P
- Нет символа c, который принадлежит как P, так и Q
- Каждая программа P и Q являются собственными
- Это считает пустые квины и квины, считывающие их собственный (или другой) исходный код недействительными .
Больше правил
- Самая короткая общая длина этих программ побеждает. То есть размер ( P ) + размер ( Q ) - это ваш результат, и выигрывает самый низкий показатель.
- Обе программы на одном языке
- Каждая программа может быть полной программой или функцией, и они не обязательно должны быть одинаковыми.
- Например, P может быть полной программой, а Q может быть функцией.
верификация
Это попробуйте онлайн! фрагмент здесь может проверить, являются ли две программы взаимоисключающими. Входные данные помещаются в первые два аргумента.
code-challenge
quine
Конор О'Брайен
источник
источник
Ответы:
> <> , Оценка: 41 + 41 = 82
Редактировать: оба содержали 3. Исправлено
а также
Попробуйте онлайн! (поменяйте местами строки, чтобы получить другой вывод) На этот раз с проверкой!
><>
это особенно сложный язык для использования здесь, так как есть только один способ вывода символов, командаo
. К счастью, мы можем использовать команду p ut для помещенияo
в исходный код во время выполнения, как в моем ответе « Программирование в нетронутом мире» .Этот занял много проб и ошибок. Я начал с двух взаимоисключающих программ:
а также
Каждый преобразует себя и свои данные на N, первое вычитая, а второе прибавляя. Затем он выводит это в обратном порядке. Дело в том , что данные после каждой программы является другой программой в обратном направлении, сдвинуто на N. (
X
это числом клеток , где потребность программы ставитьo
и Y является ячейкой , где указатель возвращается к началу цикла.?
То , гдеo
ставится) ,Оба имеют одинаковую структуру, представленную по-разному. Они запускают строковый литерал по всему коду, добавляя его в стек. Они воссоздают используемую ими строковую литеральную команду и помещают ее в конец стека. Они зацикливаются на стеке, добавляя / вычитая N для каждого символа и печатая их.
Первая программа использует
'
как строковый литерал, так и простой,d3*}
чтобы создать значение 39 и поместить его в конец стека. Второй использует"
строковый литерал с той же функцией. Онr
пересекает стек,g
помещает символ в ячейку 0,0 и снова переворачивает стек. Затем онg
помещает значение в ячейку 4,0 (g
), добавляет к нему 8 и получает егоo
в X.Обе программы используют разные методы зацикливания. Первая программа использует команду пропуска (
!
), чтобы выполнить только половину инструкций при движении влево, меняет направление и запускает вторую половину. Второй использует команду jump (.
), чтобы перейти назад к началу цикла в ячейке Y. Оба они выполняются до тех пор, пока в стеке не останется больше элементов и ошибок программы.Я столкнулся с рядом проблем с большинством более низких значений N, потому что смещение одного символа превратило бы его в другой символ, необходимый для этой программы (и, следовательно, не может использоваться в качестве данных для другой программы) или в два символа из две программы переместятся в один и тот же персонаж. Например:
+
+1 =,
=-
-1.
+2 =0
*
=-
-3g
+4 =k
=o
-4и т.п.
В конце концов я добрался до 10 (
a
), где я смог избежать этих проблем. Возможно, существует более короткая версия, в которой сдвиги меняются местами, и первая программа добавляет N, а вторая вычитает его. Это может быть хуже, хотя, поскольку первая программа обычно находится в нижней части шкалы ASCII, поэтому вычитание лучше, чтобы избежать конфликтов.источник
Forth (64-битный little-endian gforth) , 428 + 637 = 1065 байтов
Попробуйте онлайн!
Скрипт проверки
Спасибо @Nathaniel за идею использования Forth - он напомнил мне в комментариях, что Forth не учитывает регистр . Затем произошли перепады настроения - я находил причины, по которым это не сработало, а затем снова и снова решал эти проблемы. Все время крутя мой тренировочный мотоцикл в помещении, как перевернутый и неправильно сформированный вертушка (нужно просто взять один конец ручки и немного наклонить его).
Перед написанием этих программ я набросал, какие символы могут использоваться какой программой. В частности, вторая программа может использовать только заглавные буквы, десятичные цифры, символы табуляции и запятые. Это будет означать, что первая программа - все строчные, но я использовал заглавные буквы для их значений ASCII.
Поскольку вкладки громоздки, вместо этого я буду использовать пробелы в объяснении.
Первая программа имеет форму
s" code"code
-s"
запускает строковый литерал, который затем обрабатывается второй копией кода - стандартной структурой quine. Однако вместо вывода собственного исходного кода он создаст другую программу, которая выглядит следующим образом:HERE
64-bit-number-literal ,
length-of-the-string
115 EMIT 34 EMIT 9 EMIT 2DUP TYPE 34 EMIT TYPE
Это использует пространство данных Форта.
HERE
возвращает указатель на конец выделенной в данный момент области пространства данных и,
добавляет к ней ячейку, заполненную номером. Таким образом, первые три пункта маркера можно увидеть как строковый литерал, созданный с использованиемs"
. Чтобы закончить вторую программу:EMIT
выводит символ с учетом его значения ASCII, поэтому:115 EMIT
печатает строчные буквыs
34 EMIT
печатает символ кавычки"
9 EMIT
печатает вкладку2DUP
дублирует два верхних элемента в стеке( a b -- a b a b )
, здесь указатель и длина строкиTYPE
печатает строку для вывода первой копии кода34 EMIT
печатает заключительную цитату"
и, наконец,TYPE
выводит вторую копию кодаПосмотрим, как работает первая программа. Во многих случаях следует избегать чисел, что делается с использованием
'x
синтаксического расширения gforth для символьных литералов и иногда вычитает значение ASCII-пространства, которое можно получить с помощьюbl
:Чтобы закончить это, я хотел бы сказать, что я пытался использовать
EVALUATE
, но вторая программа становится больше, чем обе из представленных выше. Во всяком случае, вот оно:Если вам удастся сыграть в эту игру достаточно, чтобы обойти мой
s" ..."...
подход, продолжайте и опубликуйте свой ответ.источник
Perl
(311 + 630 = 941 байт)190 + 198 = 388 байтОбе программы печатают на стандартный вывод.
Первая Perl-программа содержит в основном печатные символы ASCII и символы новой строки, и она заканчивается ровно одной строкой новой строки, но две буквы ÿ представляют не-ASCII-байт \ xFF:
Второй содержит в основном не-ASCII байты, в том числе несколько высокоуровневых символов, которые заменены звездами в этом посте, и никаких новых строк вообще:
Hexdump первой программы с
xxd
:И hexdump второй программы:
Во второй программе строка в кавычках (длиной 189 байт, разделенная тильдами) представляет собой всю первую программу, за исключением последнего перевода строки, кодируется только побитовым дополнением каждого байта. Вторая программа просто декодирует строку, дополняя каждый байт, что
~
оператор делает в perl. Программа печатает декодированную строку, за которой следует новая строка (say
метод добавляет новую строку ).В этой конструкции декодер второй программы использует только шесть различных символов ASCII, поэтому первая программа может быть практически произвольной, если она содержит только символы ASCII и исключает эти шесть символов. Нетрудно написать любую Perl-программу без использования этих пяти символов. Фактическая логика Куайна, таким образом, находится в первой программе.
В первой программе логика quine использует словарь из 11 слов
@f
и собирает выходные данные из этих слов. Первые слова повторяют большую часть исходного кода первой программы. Остальные слова - это отдельные символы. Например, слово 5 - это тильда, которая является разделителем двух строкового литерала во второй программе. Список чисел в скобках - это рецепт, для которого нужно печатать слова в каком порядке. Это довольно обычный общий метод построения для квинов, единственный поворот в этом случае состоит в том, что первые слова словаря печатаются с побитовым добавлением байтов.источник
Haskell , 306 + 624 = 930 байт
Программа 1: анонимная функция, принимающая фиктивный аргумент и возвращающая строку.
Попробуйте онлайн!
Программа 2:
q[[40,...]]
в конце - анонимная функция, принимающая фиктивный аргумент и возвращающая строку.Попробуйте онлайн!
Набор символов 1 (включает пробел):
Набор символов 2 (включает новую строку):
Поскольку только набор 1 содержит символы не ASCII, их байты UTF-8 также не пересекаются.
Как это работает
Программа 1 обычно написана с лямбда-выражениями, пробелами и круглыми скобками, свободным использованием встроенных буквенно-цифровых функций, а также с данными quine в качестве строковых литералов в конце.
a
илиb
, которые образуют допустимые escape-последовательности, проходящие в обратном направленииshow
.a
,b
иc
являются только строчными буквами , чья ASCII кода меньше , чем 100, сэкономив цифры в числовом кодировке , используемой программой 2.Программа 2, как правило, написана с помощью функциональных уравнений верхнего уровня (кроме последнего анонимного), символьных литералов и десятичных чисел, синтаксиса и операторов списка / диапазона, а также с данными quine в виде списка списков
Int
s в конце.Прохождение, программа 1
b
иc
являются значениями строковых литералов для программ 2 и 1 соответственно, заданными в качестве окончательных аргументов лямбда-выражения.()
является фиктивным аргументом исключительно для удовлетворения правила PPCG о том, что программа должна определять функцию.foldr(\a->map pred)b(show()>>c)
декодирует строкуb
в основной код программы 2, применяяmap pred
к ней число раз, равное длинеshow()>>c == c++c
или182
.tail(show c)
преобразует строкуc
в основной код программы 1 с добавлением окончательной двойной кавычки.:pure b
объединяет это в списке со строкойb
.map(map fromEnum)$
преобразует строки в списки кодов`mappend`show(...)
сериализует полученный список списков и, наконец, добавляет его в основной код программы 2.Прохождение, программа 2
z~z=[[['@','0'..]!!4..]!!z]
- это функция, преобразующая кодовые точки обратно в символы (необходимо писать, так как не все символыtoEnum
доступны).z
. Маркер лени~
в этой позиции не действует, но избегает пробела.['@','0'..]
это диапазон списка шагов назад, начинающийся с кода ASCII 64, затем переходящий на 16 шагов вниз.!!4
к этому дает\NUL
характер.[ ..]
диапазона дает список всех символов, которые!!z
индексируются.z
на списки, используя=<<
вместо недоступныхmap
и<$>
.q[x,q]_=z=<<x++q++[34,34]++x
- это программа построения функций 1 из списка данных Quine.x
это данные для ядра программы 1 (включая заключительную двойную кавычку), а внутренняя частьq
представляет собой запутанные данные для ядра программы 2._
это еще один фиктивный аргумент исключительно для того, чтобы сделать конечную анонимную функцию функцией, а не просто строкой.x++q++[34,34]++x
объединяет части, включая две двойные кавычки с кодом ASCII 34.z=<<
создает программу 1 путем сопоставленияz
конкатенации для преобразования из кодовых точек в символы.q[[40,...]]
является анонимная функция, объединяющаяq
данные квин.источник
Желе ,
128 90 87 86 85 7916 + 32 = 48 байтПопробуйте онлайн!
Попробуйте онлайн!
Первая программа делает следующее:
Это оставляет строки
79,7806,8318,7885,7769,338,115
иỌṘ
как два аргумента цепочки, и они неявно объединяются и печатаются в конце.Вторая программа вычисляет
chr
(Ọ
) списка номеров, которые возвращаютсяOṾ⁾ọṙŒs
.Ṙ
печатает“OṾ⁾ọṙŒs”
(с кавычками) и возвращает ввод, оставляя“OṾ⁾ọṙŒs”OṾ⁾ọṙŒs
в качестве полного вывода.источник
Gol> <> ,
23 + 23 = 4622 + 22 = 4420 + 20 = 40 байтовПопробуйте онлайн!
Попробуйте онлайн!
Проверьте это онлайн!
Как они работают
Адаптировано из ответа Джо Кинга> <> . Имея много альтернативных команд для вывода и повторения, в них не было необходимости
g
илиp
, и два основных тела стали намного короче.Другое основное отличие состоит в том, что я генерирую цитату оппонента прямо на вершине стека. Таким образом, было немного легче сохранить инвариант
quote + my code + opponent code(reversed and shifted)
.источник