Помимо читерства¹ нет никакой разницы между компилируемыми и интерпретируемыми языками.
Общий подход к кваи довольно прост. Во-первых, как бы программа ни выглядела, в какой-то момент она должна что-то напечатать:
print ...
Однако, что это должно напечатать? Сам. Так что нужно распечатать команду «печать»:
print "print ..."
Что должно быть напечатано дальше? Ну, в то время как программа выросла, поэтому она должна напечатать строку, начинающуюся также с «print»:
print "print \"print ...\""
Теперь программа снова выросла, так что есть еще что напечатать:
print "print \"print \\\"...\\\"\""
И так далее.
С каждым добавленным кодом появляется больше кода для печати.
Такой подход ни к чему не приведет,
но это показывает интересную закономерность:
Строка "print \" "повторяется снова и снова.
Было бы неплохо поставить повторяющуюся часть
в переменную:
a = "print \""
print 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()
единственные детали, в которых различные квины действительно отличаются.
¹, заставив программу прочитать исходный файл