随机奎因


15

编写一个能够随机生成自身的程序。

它必须基于其源代码中使用的令牌来执行此操作。如果您的程序的源代码由50个唯一令牌组成,并且长度为60个令牌,则程序应输出60个令牌,其中每个令牌都是从50个唯一令牌中随机选择的。

例如,此程序将有50/60的机会复制自己。

什么是代币?这取决于语言。例如,在大多数语言中,标识符(foo_bar),关键字(while)和数字(42)将被视为标记。在大多数语言中,空格都不起作用。

附加规则:

  • 输出只能包含在程序源代码中找到的标记,并由适当的定界符分隔
  • 输出必须与程序的源代码具有相同的长度,并以令牌计数
  • 只能使用一种编程语言
  • 源代码必须至少具有3个唯一令牌
  • 从源代码中排除注释
  • 程序应该只有一个U ^ L机会重现自己

计分:获胜的机会最大。


@MathieuRodic:您假设程序不重复地绘制标记。
user2357112支持Monica 2014年

@MathieuRodic:让我改一下。您假设程序随机地对其令牌的多重集进行加扰,而不是重复从其源中使用的U个令牌集中抽取L个令牌。
user2357112支持Monica 2014年

@ user2357112:我知道了。我的错误是将这个问题视为没有替换的平局。
Mathieu Rodic'3

1
规则#1和#5似乎与我矛盾。
Cruncher 2014年

4
您可以假设内置随机函数是TRNG吗?典型的实现方法的种子太小,无法产生所有输出,因此可能无法真正自我再生。
CodesInChaos

Answers:


11

Python 2、3 ^ -3 = 0.037

exec滥用对于减少令牌数量非常方便。现在更新为不读取源文件!

exec '' """
s = '''{a}
s = {b}
s = s.format(a='"'*3, b="'"*3+s+"'"*3)
import random
tokens = ['exec', "''", s]
print random.choice(tokens), random.choice(tokens), random.choice(tokens),
{a}'''
s = s.format(a='"'*3, b="'"*3+s+"'"*3)
import random
tokens = ['exec', "''", s]
print random.choice(tokens), random.choice(tokens), random.choice(tokens),
"""

引号和三引号''之间的多余exec字符只是将令牌计数填充到所需的最小值3。由于隐式字符串文字串联,它会合并到第二个字符串中。

原始的打开源文件版本:

exec '''
# String literals are one token!
import random
import tokenize

with open(__file__) as f:
    tokens = [x[1] for x in tokenize.generate_tokens(f.readline)][:-1]

''' '''
# Splitting the string into two strings pads the token count to the minimum of 3.

print random.choice(tokens), random.choice(tokens), random.choice(tokens),
'''

严格来说,Python语法在源文件的末尾放置了一个ENDMARKER标记,而我们不能生成带有随机散布的ENDMARKER的源文件。我们假装它不存在。


@Cruncher这就是可能性。3 ^ -3 == 1/3 ^ 3
奥斯汀·亨利2014年

2
+1完美破解了规则。在J:中实现了相同的想法".]';(?3 3 3){]`".;~({:,],{:,],6#{:)'';(?3 3 3){]`".;~({:,],{:,],6#{:)'''''''
algorithmhark

5

Javascript,102个令牌,33个唯一,7.73×10 -154

请注意,这是一个真实的信息。它不会读取文件或使用evalFunction.toString

meta = "meta = ; out = '' ; tokens = meta . split ( '\\u0020' ) ; tokens . push ( '\"' + meta + '\"' ) ; length = tokens . length ; tmp = length ; unique = { } ; while ( tmp -- ) unique [ tokens [ tmp ] ] = unique ; unique = Object . keys ( unique ) ; tmp = unique . length ; while ( length -- ) out += tokens [ ~~ ( Math . random ( ) * tmp ) ] + '\\u0020' ; console . log ( out )"; 
out = '';
tokens = meta.split('\u0020');
tokens.push('"' + meta + '"');
//console.log(tokens);
length = tokens.length;
tmp = length;
unique = { };
while(tmp--) unique[tokens[tmp]] = unique;
unique = Object.keys(unique);
//console.log(unique);
tmp = unique.length;
while(length--)
    out += unique[~~(Math.random() * tmp)] + '\u0020';
console.log(out)

4

Python:P(在1个试验中生成程序)= 3.0317 * 10 ^ -123

34个唯一令牌,总共80个令牌。请注意,每行的末尾都有一个空格。

import tokenize , random 
tokens = [ x [ 1 ] for x in tokenize . generate_tokens ( open ( __file__ , 'r' ) . readline ) ] [ : -1 ] 
s = '' 
for x in tokens : s += random . choice ( list ( set ( tokens ) ) ) ; s += [ ' ' , '' ] [ s [ -1 ] == '\n' ] 
print s 

样本输出:

' ' random len set 'r' , for ( list , import ] ] tokens : random [ for '\n' import readline readline 'r' tokens [ len 'r' import '' choice '' '' for in ( readline ( = open readline , list 1 list s += for s 1 , '' : 1 += list len - __file__ ; open __file__ print . - ] 'r' for import [ print . , 

; . [ [ print print __file__ generate_tokens ] ; open ] , readline 

感谢user2357112提出的另一种Python解决方案,提醒我丢弃最后一个令牌并使用__file__我以前不了解的令牌。


3

J-11中的1 17 = 1.978 x 10 -18

;(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''

J有很多方便的小工具可以完成这些工作。

  • 首先,任何用空格分隔的数字字符串都是一个令牌。这意味着这些数字的一维数组。这就是J的词法分析器的工作方式。顺便说一句,11如果有人好奇,那就是十七秒。

  • (,,,{:,{:)'QUINE'''是J中的一个常见的quine技巧,使得使用尽可能少的标记:{:意味着Tail,因此它将字符串附加到其自身,然后在末尾添加最后一个字符的两个副本。由于最后一个字符是单引号(J使用Pascal样式的字符串),因此结果为QUINE'QUINE'''

  • ;:是一个分词器,将输入字符串分解为J代码,返回一个框列表。该结果的长度是17。

  • ~.接受此数组的所有唯一元素。该结果的长度是11。

  • ?被称为Roll。对于其参数中的每个整数,它将选择一个大于或等于零(小于该数字)的随机正数。因此,这里J将生成17个从0到10(含)的数字。

  • { 使用随机索引从我们的盒子中唯一令牌列表中选择项目。

  • ; 打开所有这些框并一起运行结果。

以下是一些示例。缩进的行是输入提示,与左侧齐平的行是解释器的输出。

   ;(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''
~.~.(?;;:11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''(){11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){(;:;
   ;(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''
{';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)''',?{:;:{:';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11{:{;(;:{:,~.

2

后记

这很有趣

/cvx /cvx cvx /exec /exec cvx /dup /rand /mod /get /== /array /astore /realtime
/srand /repeat 6 17 54 17 /array cvx exec /astore cvx exec 54 /dup cvx /rand
cvx 17 /mod cvx /get cvx /== cvx 6 /array cvx exec /astore cvx exec cvx /realtime
cvx exec /srand cvx exec /repeat cvx exec

在3.6e-67的机会中,大约有1个令牌共有17个唯一令牌和54个令牌。


2

空格,3 ^ -205 3 ^ -189 3 ^ -181 3 ^ -132〜= 10 ^ -63

这是一个Whitespace程序,当使用随机字符播种时,它有三分之二的机会重现自身(3个不同的标记,重复132次)。运行时,它必须至少带有132个随机字符作为种子((空白没有内置的随机或日期函数作为种子),例如some_whitespace_interpreter my_quine.ws <some_random_source >quine_output.ws。如果该程序可以再打高尔夫球,则得分会提高,但这是我的第一个“真实” Whitespace程序,所以我只剩下很少的打高尔夫球了。

普通的空白代码,或运行它:(尝试一下,单击“编辑”,复制<pre>标记内的内容;使用Unix样式的EOL应该为132个字符)

    

























用什么命令注释的代码是什么(从技术上讲,不是奎因,因为它不会重现注释):

堆栈push_number + 0结束
堆栈push_number + 1 0 0 1结束
堆存储堆栈push_number + 1个结束
堆栈push_number + 1 0 0 0 0 0结束
堆存储堆栈push_number + 1 0结束
堆栈push_number + 1 0 1 0结束
堆存储堆栈push_number + 1 0 0 0 0 0 1 1结束
流
make_label loop_begin  
堆栈push_number + 1 1结束
IO  
读取字符堆栈push_number + 1 1结束
堆检索堆栈push_number + 1 1结束
算术模堆检索IO  
打印字符堆栈push_number + 1结尾
算术减堆栈重复
 流
jump_if_zero end_prog
流
跳到 
loop_begin  
流
make_label end_prog
流
结束程序

如果种子恰好与此等效(将字符取为mod 3以转换为令牌),它将成功:

CCCCACCCBCCBABBBBCCCCBACCCBCCCCCABBCCCCBCACCCBCBCABBCCCCBCCCCCAAAACCBACCCBBABABCCCCBBABBBCCCBBABCBBBBBBBBCCCCBABCCBCACACBABAACABAACAC

这是一个非常简单的程序,大致等效于以下Ruby程序:

i = 131
while true
    print '\t \n'[STDIN.getc.ord % 3]
    i = i - 1
    break if i < 0
end

1

Perl,27个令牌,P = 1.4779 x 10 -34

@ARGV=$0;print$W[rand@W]for@W=split/(\W)/,readline

最后编辑:使用@ARGV=$0而不是open*ARGV,$0保存令牌。

  • 15个唯一代币
  • 4个令牌出现2次(=/@$
  • 1个令牌出现了4次(W

所以我认为这使概率(pow(2,2 * 4)* pow(4,4))/ pow(27,27)大约为1.48E-34。

如果源代码在一个名为的文件中ARGV,则可以使用以下26个令牌解决方案,其中P =〜2.193 x 10 -31

@ARGV=ARGV;print$ARGV[rand@ARGV]for@ARGV=split/(\W)/,readline

实际上,P = (4 * 2! + 4!) / 27!大约是1.7632684538487448 x 10 ^ -26
Mathieu Rodic

0

Perl 61个33 = 0.037037 ...

(我知道这不是代码高尔夫球,但是...)

q[say |roll <<~~"q[$_]".EVAL>>: 3]~~.EVAL

在线尝试!

与Python答案非常相似,第一个标记是要评估的字符串文字。令牌是

q[say |roll <<~~"q[$_]".EVAL>>: 3]   String literal
~~                                   Smartmatch operator
.EVAL                                Function call

说明:

q[say |roll <<~~"q[$_]".EVAL>>: 3]         # Push as string literal
                                  ~~       # Smartmatch by setting $_ to the string literal
                                    .EVAL  # Eval the string
            <<~~"q[$_]".EVAL>>             # From the list of tokens
       roll                   : 3          # Pick 3 times with replacement
  say |                                    # Join and print
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.