如何编写自我复制代码(在exec上打印源代码)?

时间:2020-03-06 14:27:55  来源:igfitidea点击:

我已经看到了很多基于C / C ++的解决方案,我们必须编写一个程序,该程序在执行时会打印自己的源代码。

一些解决方案-

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

多种语言的Quine Page解决方案

网上有更多解决方案,每个解决方案互不相同。我想知道我们如何解决这个问题,解决这个问题的人的内心深处。向我提供有关此问题的一些见解...虽然解释语言(例如perl,php,ruby等)的解决方案可能很简单...我想知道如何用编译的语言对其进行设计...

解决方案

在红宝石中:

把File.read(_ _ FILE _ _)

编写藜有两种不同的策略。显而易见的一种方法是编写代码,然后将其打开并打印出来。但是更有趣的是涉及允许自我嵌入的语言功能,例如许多语言中的%s样式printf功能。我们必须弄清楚如何嵌入某些东西,以便最终解决要嵌入的请求。我怀疑像回文症一样,涉及很多试验和错误。

通常的方法(当我们不能作弊时*)是编写一些东西,将其源代码编码为字符串常量,然后将该常量打印两次:一次为字符串文字,一次为代码。这样就解决了"每次我写一行代码,我都必须写另一行代码来打印出来!"问题。

"作弊"包括:
使用解释性语言并简单地加载源并进行打印
0字节长的文件,在某些语言(例如C)中有效。

我们也可以研究Core Wars游戏的运作方式。我认为这将是一个很好的例子。

考虑编码的想法以及如何赋予某种双重含义,以便可以将其用于输出两种形式的某种想法。也有消息说,这种类型的问题带有限制,使其变得更加困难,因为除了程序输出本身之外,没有任何规则,空程序是一种解决方案。

我们可以在这里找到很多解决方案:http://forums.thedailywtf.com/forums/p/5232/147528.aspx

几本有关quines的教程:此处和此处。

除了作弊1,编译语言和解释语言之间没有区别。

奎因的通用方法非常简单。首先,无论程序是什么样,它都必须打印一些内容:

print ...

但是,它应该打印什么?本身。因此它需要打印" 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))

就是这样!
所有语言的所有奎因都是这样工作的
(作弊者除外)。

好吧,你应该确保只更换
首次出现的占位符。
如果我们使用第二名,
我们可以避免用引号引起来。

但这是次要问题
且易于解决。
如果有的话,quoted()replace()的实现
是唯一不同的细节,真正的不同。

1通过使程序读取其源文件

带有吨od示例的站点:
http://www.nyx.net/~gthompso/quine.htm

为了娱乐,我在Scheme中想出了一个,在大约5分钟的时间内我一直感到很自豪,直到我被发现之前就被发现了。无论如何,对游戏的"规则"进行了一些小的修改,以更好地考虑Lisp中数据和代码的二重性:它是一个返回自身的S表达式,而不是打印程序的源代码:

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

Wikipedia上的那个具有相同的概念,但是引用机制略有不同(更为冗长)。我更喜欢我的。