您可以使用Meta Quine吗?


25

与其他quine拼图(更具体地讲,这个)类似,编写一个程序为自己生成源。

这里是新的转折:产生的代码应该等同于源。相反,它应该输出将创建第一个程序的其他程序。

与上述相关的挑战通过在两种语言之间跳转来实现。我认为仅用一种语言即可完成,但是源的两个(或更多)版本应该有显着差异(请参见以下规则)。在这种约束下,单字符答案将是不允许的,因此需要在最终提交中多加思考。


规则

  1. 您的代码必须仅以一种语言生成。(多次提交,每种语言都可以接受。)
  2. 您不同的代码版本在语法上必须是不同的。换句话说,如果要为代码绘制一棵抽象语法树,则至少应有一个不同的节点。
    • 提供AST并不是必需的,但是如果您希望为每个程序提供一个AST则将有助于判断。
  3. 您可以根据需要生成任意数量的迭代,只要它们在语法上保持不同即可。(更多信息将对您有所帮助,请参阅下文。)

计分

您的最终分数将是所有程序的平均时长,再除以程序数。

范例1:

A(B来源)= 50个字符
B(A来源)= 75个字​​符
最终分数= 31.25

范例2:

A(B来源)= 50个字符
B(C来源)= 75个字​​符
C(A来源)= 100个字符
最终分数= 25


18
我一次奎因。
mellamokb

1
@mellamokb har har ;-)
加菲(Gaffi)2012年

实际上,这只是这个 quine挑战的更一般的版本,在那里给出的答案也将在这里赢得。
停止了开启

@leftaroundabout,对语法差异的要求使“旋转quine”无效,因此这不是更普遍的。
standby

2
从来没有我不喜欢的麦奎因。
Stack Tracer

Answers:


35

Python,0(限制为(68 + 3 n)/(16 n)的限制)

如果两个抽象语法树的常量不同,那么它们也不同,

r='r=%r;n=(0x%XL+1)%%0x10...0L;print r%%(r,n)';n=(0xF...FL+1)%0x10...0L;print r%(r,n)

有16最多 n个程序,长度最多为68 + 3n,渐近得分为0。

如果您想要具有可变结构的程序,我们可以在n位上实现二进制加法器。在这里,有2 长度为On 2)的程序。由于进位丢失而进入一个周期。

s="""
print 's='+'"'+'"'+'"'+s+'"'+'"'+'"'
n=lambda m:reduce(lambda (s,c),y:(s+(c^y,),c&y),m,((),1))[0]
print s[:112]
t=n(t)
print "t=(%s,)+(0,)*%s"%(t[0],len(t)-1)
for i in range(len(t)-1):
    print i*' '+'for i in range(2):'
    print ' '+i*' '+['pass','t=n(t)'][t[i+1]]
print s[113:-1]
"""

print 's='+'"'+'"'+'"'+s+'"'+'"'+'"'
n=lambda m:reduce(lambda (s,c),y:(s+(c^y,),c&y),m,((),1))[0]
print s[:112]
t=(0,)+(0,)*10
for i in range(2):
 t=n(t)
 for i in range(2):
  t=n(t)
  for i in range(2):
   t=n(t)
   for i in range(2):
    t=n(t)
    for i in range(2):
     pass
     for i in range(2):
      t=n(t)
      for i in range(2):
       pass
       for i in range(2):
        pass
        for i in range(2):
         pass
         for i in range(2):
          t=n(t)
t=n(t)
print "t=(%s,)+(0,)*%s"%(t[0],len(t)-1)
for i in range(len(t)-1):
    print i*' '+'for i in range(2):'
    print ' '+i*' '+['pass','t=n(t)'][t[i+1]]
print s[113:-1]

我可能会感到困惑吗?看起来输出是否与源相同(不是此挑战的目标)?
加菲2012年

查看嵌套块。 pass将以t=n(t)2 ^ n个组合来回切换。
deskby 2012年

我现在看到了。你把我的重复弄糊涂了!
加菲2012年

22
由于某种原因,我喜欢很长的高尔夫解决方案,而且分数很少。
standby 2012年

哇,您完全拥有它!非常好。
Claudiu 2014年

4

Perl,得分为110.25

我必须承认,我对藜不太满意。我100%肯定还有改进的空间。该解决方案基于以下元素解决方案的相同原理。

第一个程序是264个字符。

$s='$a=chr(39);print"\$s=$a$s$a;";$s=reverse$s;for(1..87){chop$s}$s=reverse$s;print$s;$f++;if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}';$a=chr(39);print"\$s=$a$s$a;";$s=reverse$s;for(1..87){chop$s}$s=reverse$s;print$s;$f++;if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}

第二个程序是177个字符。

$s='$a=chr(39);print"\$s=$a$s$a;";$s=reverse$s;for(1..87){chop$s}$s=reverse$s;print$s;$f++;if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}';if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}

我正在为此条目(和Element条目)开发AST。


元素,得分47.25

第一个程序是105个字符。

\ \3\:\$\'\[\\\\\`\(\`\]\#\2\1\'\[\(\#\]\`\ \3\:\$\'\[\\\\\`\(\`\]\#\` 3:$'[\\`(`]#21'[(#]` 3:$'[\\`(`]#`

第二个程序是84个字符。

\ \3\:\$\'\[\\\\\`\(\`\]\#\2\1\'\[\(\#\]\`\ \3\:\$\'\[\\\\\`\(\`\]\#\` 3:$'[\\`(`]#`

我确信还有很多改进的余地。

在第一个程序中,有一个字符串(尽管有很多冗余,每个字符都被转义了),其后是可执行部分A和B。部分A执行了几件事:打印字符串并转出每个字符,打印最后一半字符串(这是B部分的源),然后阻止跟随它的B部分执行任何操作。

第二个程序是相同的字符串,后跟B部分。B部分基于简单的字符串;它会打印一个字符串,并在其后进行转义。这意味着它将打印字符串,以及部分A和B。


我认为,毫无疑问,这无疑证明了Element作为编程语言的有效性。它是如此易于使用,以至于我经验不足,我只设法为Element编写了一个完整的口译员,就能够在这70亿人口的整个星球上的任何其他人之前回答这个问题。Element的“一个字符,一个功能,一直”的范例意味着所有代码都是完全明确的。该语言用途广泛:除了[]{},任何命令都可以放置在整个程序中的任何位置,而不会引起语法错误。这十分完美。
PhiNotPi 2012年

4
有点偏见,是吗?;-)
Gaffi 2012年

3

VBA:(251 + 216)/ 2/2 = 116.75

251

Sub a()
r=vbCrLf:c="If b.Lines(4, 4) = c Then"&r &"b.InsertLines 8, d"&r &"b.DeleteLines 4, 4"&r &"End If":d="b.InsertLines 6, c"&r &"b.DeleteLines 4, 2"
Set b=Modules("Q")
If b.Lines(4, 4) = c Then
b.InsertLines 8, d
b.DeleteLines 4, 4
End If
End Sub

216

Sub a()
r=vbCrLf:c="If b.Lines(4, 4) = c Then"&r &"b.InsertLines 8, d"&r &"b.DeleteLines 4, 4"&r &"End If":d="b.InsertLines 6, c"&r &"b.DeleteLines 4, 2"
Set b=Modules("Q")
b.InsertLines 6,c
b.DeleteLines 4,2
End Sub

它在MSAccess中运行以利用该Module对象。该模块"Q"用于打高尔夫球。语法上的差异来自If ... Then较短版本的缺失。


你可以最有可能逃脱改变vbCrLFvbCr
泰勒斯科特

3

C ++,分数0.734194

以下源代码在控制台上打印了一个阶数为999的meta quine(以下说明):

#define X 1*(1+1)
#include<iostream>
#include<vector>
#define Q(S)auto q=#S;S
Q( \
  main() \
  { \
      using namespace std; \
      cout<<"#define X 1"; \
      int x=X==2?1000:X-1; \
      vector<int> factors; \
      for ( int p = 2; p <= x; ++p) \
      { \
        while ( x % p == 0 ) \
        { \
          factors.push_back( p ); \
          x /= p; \
        } \
      } \
      for ( int factor : factors ) \
      { \
        cout<<"*(1"; \
        for ( int i=1;i<factor;++i) \
          cout<<"+1"; \
        cout<<")"; \
      } \
      cout<<"\n#include<iostream>\n#include<vector>\n#define Q(S)auto q=#S;S\nQ("<<q<<")"; \
  })

唯一更改的行是第一行。的值X将是1000、999、998,...,3、2,然后它将重新开始。但是,为了每次都获得不同的语法树X,用素数分解表示,每个素数写为1s 的和。AST不同,因为每个值的整数素数分解都不同。

该程序将自行打印,除了更改第一行,并Q(...)删除其中的反斜杠,换行符和缩进。

以下程序计算我的答案的分数:

#include <iostream>

const int n = 1000;

int getProgramLength( int n )
{
  int sum = 442;
  for ( int p = 2; p*p <= n; ++p )
  {
    while ( n % p == 0 )
    {
      sum += 2 * ( 1 + p );
      n /= p;
    }
  }
  if ( n > 1 )
    sum += 2 * ( 1 + n );
  return sum;
}

int main()
{
  int sum = 0;
  for ( int i = 2; i <= n; ++i )
    sum += getProgramLength( i );
  std::cout << (double)sum/(n-1)/(n-1) << '\n';
}

它在控制台上打印了0.734194。显然,可以用较大的整数代替1000,并且得分将接近0作为其限制。数学证明涉及黎曼的Zeta函数有些复杂。我把它作为练习留给读者。;)


2

JavaScript,84.5 64 61

两种方案,两者长度169 128 122。

(function c(){alert(/*
2/*/1/**/);return ('('+c+')()').replace(/\/([/\*])/,function(m,a){return a=='*'?'/\/':'/\*'});
})()

在我打高尔夫球之前,为了您的观赏乐趣:

(function c() {
    var r = /\/([/\*])/;
    var f = function(m, a) { return a === '*' ? '/\/' : '/\*' };
    var p = '(' + c + ')();';
    p = p.replace(r, f);
    /* This is just a comment!
    console.log('Quine, part two!'); /*/
    console.log('Quine, part one!'); /**/
    return p;
})();

返回新程序并输出当前零件! 没有函数正则表达式,我可能可以使它更短一些,但是……我不想这么做。


不,它们在语法上是不同的。添加换行符后,即是。
Ry-

2

J-(24 + 30)/ 2/2 = 13.5分

请注意,J中的字符串不是用反斜杠转义,而是用Pascal:引号转义'I can''t breathe!'

30$(,5#{.)'''30$(,5#{.)'         NB. program 1, 24 char
'30$(,5#{.)''''''30$(,5#{.)'''   NB. program 2, 30 char

程序1具有AST noun verb hook noun,程序2具有AST noun。程序2是程序1的引用版本,运行时将仅返回程序1,因此该方法不能轻易扩展为三个副本:P

程序1的操作是获取源代码部分的副本,并在其前面附加一个引号,然后将其中五个引号添加到末尾((,5#{.))。然后,它从该16个字符的字符串中循环抽取30个字符,从而准确给出了程序2。

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.