Как написать самовоспроизводящийся код (печатает источник на exec)?

Я видел много C/с++ решения этой проблемы, где мы должны написать программу, которая при выполнении печатает свой собственный источник.

некоторые решения --

http://www.cprogramming.com/challenges/solutions/self_print.html

Quine Page решение на многих языках

в сети есть еще много решений, отличающихся друг от друга. Интересно, как мы подходим к такому проблема в том, что происходит в голове того, кто ее решает. Дайте мне некоторое представление об этой проблеме... В то время как решения на интерпретируемых языках, таких как perl, php, ruby и т. д., могут быть легкими... я хотел бы знать, как можно разработать его на скомпилированных языках...

13 ответов


помимо cheating1 нет никакой разницы между скомпилированными и интерпретируемыми языками.

общий подход к quines довольно легко. Во-первых, как бы ни выглядела программа, в какой-то момент она должна что-то напечатать:

print ...

однако, что он должен печатать? Себя. Поэтому необходимо распечатать команду "print":

print "print ..."

что он должен печатать дальше? Ну, а тем временем программа росла, поэтому ей нужно распечатать строку, начинающуюся с "печать" тоже:

print "print \"print ...\""

теперь программа снова выросла, так что снова больше печатать:

print "print \"print \\"...\\"\""

и так далее. С каждым добавленным кодом появляется все больше кода для печати. Этот подход ведет в никуда., но в нем обнаруживается интересная закономерность: Строка "print \ "" повторяется снова и снова. Было бы неплохо поставить повторяющуюся часть в переменную:

a = "print \""
print a

однако программа только что изменилась, так что нам нужно приспособиться. a:

a = "a = ...\nprint a"
print a

когда мы теперь пытаемся заполнить "...", мы сталкиваемся с теми же проблемами, что и раньше. В конечном счете, мы хотим написать что-то вроде этого:

a = "a = " + (quoted contents of a) + "\nprint a"
print a

но это невозможно, потому что даже если бы у нас была такая функция quoted() для закавычить, есть еще проблема, которую мы определяем a в:

a = "a = " + quoted(a) + "\nprint a"
print a

таким образом, единственное, что мы можем сделать, это поместить держатель места в a:

a = "a = @\nprint a"
print a

и это все трик! Все остальное теперь ясно. Просто замените держатель места с цитируемым содержанием a:

a = "a = @\nprint a"
print a.replace("@", quoted(a))

так как мы изменили код, нам нужно настроить строку:

a = "a = @\nprint a.replace(\"@\", quoted(a))"
print a.replace("@", quoted(a))

и это все! Все quines на всех языках работает (кроме обманщиков).

Ну, вы должны убедиться, что вы заменяете только первое появление владельца места. И если вы используете держатель второго места, вы можете избежать необходимости цитировать строка.

но это незначительные проблемы и легко решить. Если факт реализации quoted() и replace() являются единственными деталями, в которых различные куины действительно отличаются.


1, заставляя программу читать исходный файл


существует несколько различных стратегий написания Квинса. Очевидным является то, чтобы просто написать код, который открывает код и распечатывает его. Но более интересные включают языковые функции, которые позволяют самостоятельно внедрять, например, функцию %s-style printf на многих языках. Вы должны выяснить, как встроить что-то, чтобы оно в конечном итоге разрешило запрос на внедрение. Я подозреваю, что, как и палиндромы, много проб и ошибок.


несколько учебных пособий по quines:здесь и здесь.


также вы можете изучить, как работает игра Core Wars. Думаю, это хороший пример.


обычный подход (когда вы не можете обмануть*) - написать что-то, что кодирует его источник в Строковой константе, а затем печатает эту константу дважды: один раз как строковый литерал и один раз как код. Это обходит "каждый раз, когда я пишу строку кода, я должен написать другую, чтобы распечатать ее!" проблема.

'обман' включает в себя: - Использование интерпретируемого языка и просто загрузка источника и его печать - 0-байтовые длинные файлы, которые действительны на некоторых языках, таких как С.


сайт с тоннами примеров od:
http://www.nyx.net / ~gthompso/quine.htm


для удовольствия я придумал одну схему, которой я очень гордился около 5 минут, пока не обнаружил, что был обнаружен раньше. В любом случае, есть небольшая модификация "правил" игры, чтобы лучше рассчитывать на двойственность данных и кода в Lisp: вместо того, чтобы печатать источник программы, это S-выражение, которое возвращает себя:

((lambda (x) (list x `',x)) '(lambda (x) (list x `',x)))

на на Википедии имеет ту же концепцию, но с немного другой (более подробный) механизм цитирования. Но мне моя нравится больше.


одна идея подумать о кодировании и как дать что-то двойное значение, чтобы его можно было использовать для вывода чего-то в нескольких формах. Существует также cavaet, что этот тип проблемы поставляется с ограничениями, чтобы сделать его сложнее, поскольку без каких-либо правил, кроме вывода самой программы, пустая программа является решением.


вы можете найти довольно много решений для этого здесь:http://forums.thedailywtf.com/forums/p/5232/147528.aspx


Как насчет фактического чтения и печати исходного кода? Это совсем не сложно!! Вот один в PHP:

<?php
{
header("Content-Type: text/plain");
    $f=fopen("5.php","r");
    while(!feof($f))
    {
        echo fgetc($f);
    } 
    fclose($f);
}
?>

в Python, вы можете написать:

s='c=chr(39);print"s="+c+s+c+";"+s';c=chr(39);print"s="+c+s+c+";"+s

вдохновение из собственной печати псевдо-код:

Print the following line twice, the second time with quotes.
"Print the following line twice, the second time with quotes."

Я сделал пример AS3 для тех, кто заинтересован в этом

var program = "var program = @; function main(){trace(program.replace('@', 

String.fromCharCode(34) + program + String.fromCharCode(34)))} main()"; 
function main(){
   trace(program.replace('@', String.fromCharCode(34) + program + String.fromCharCode(34)))
}
main()

в ruby:

добавляет файл.read (__FILE__)