メタクインできますか?


25

他のクインパズル(より具体的には、これ)と同様に、それ自体のソースを生成するプログラムを作成します。

ここに新しい工夫があります:生成されるコードはソースと同一であってはなりません。むしろ、最初のものを作成する別のプログラムを出力する必要があります。

上記に関連する課題は、2つの言語間をジャンプすることで達成されました。これはたった1つの言語で行われると思っていますが、ソースの2つ(またはそれ以上)のバージョンは大きく異なるはずです(以下のルールを参照)。この制約により、単一文字の回答は許可されないため、最終的な提出にはもう少し考えを加える必要があります。


ルール

  1. コードは1つの言語でのみ作成する必要があります。(複数の提出物、各言語に1つは完全に受け入れられます。)
  2. 異なるコードバージョンは、構文的に明確でなければなりません。つまり、コードの抽象構文ツリーを作成する場合、少なくとも1つのノードが異なる必要があります。
    • 供給ASTは必要ではないだろうが、あなたはあなたのプログラムのそれぞれについて、1を提供するために、傾斜して感じた場合、それは考え判断に役立ちます。
  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 ;-)
ガフィ

これは実際にこの馬の挑戦のより一般的なバージョンであり、そこに与えられた答えもここで勝ちます。
反時計回りに

@leftaroundabout、構文の違いの要件は「回転する馬」を無効にするため、これはより一般的ではありません。
ブースバイ

2
私が好きではなかったメタクインはありません。
スタックトレーサー

回答:


35

Python、0((68 + 3 n)/(16 n)の制限)

2つの抽象構文ツリーが異なる定数を持つ場合に異なる場合、

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

最大68 + 3nの長さの16 n個のプログラムがあり、漸近スコアは0です。

可変構造のプログラムが必要な場合は、nビットにバイナリ加算器を実装できます。ここでは、長さOn 2)の2 n個のプログラムがあります。キャリービットのドロップにより、サイクルになります。

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]

混乱する可能性がありますか?出力はソースと同じように見えます(このチャレンジの目的ではありません)?
ガフィ

ネストされたブロックを見てください。 すべての2 ^ nの組み合わせで、前後にpass変化しt=n(t)ます。
ブースバイ

私は今それを見る。あなたはすべての繰り返しで私を混乱させました!
ガフィ

22
何らかの理由で、私は小さなスコアを持つ非常に長いゴルフソリューションが好きです。
ブースバイ

わあ、あなたはそれを完全に所有しました!非常に素晴らしい。
クラウディウ14年

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"}

2番目のプログラムは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"}

このエントリ(および要素エントリ)のASTに取り組んでいます。


要素、47.25のスコア

最初のプログラムは105文字です。

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

2番目のプログラムは84文字です。

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

改善の余地はたくさんあると確信しています。

最初のプログラムには、1つの文字列(冗長性が非常に高いにもかかわらずすべての文字がエスケープされる)があり、その後に実行可能な部分AとBが続きます。文字列(パートBのソース)を使用し、その後に続くパートBが何もしないようにします。

2番目のプログラムは、同じ文字列の後にパートBが続きます。パートBは単純なクインに基づいています。エスケープされたバージョンが前にある文字列を出力します。これは、文字列、およびAとBの両方の部分を印刷することを意味します


これは間違いなく間違いなく、プログラミング言語としてのElementの有効性を証明していると思います。とても使いやすいので、私は経験が浅いため、Elementの完全なインタープリターを1つしか作成できず、この質問に回答することができました。要素の「1文字、1関数、常に」というパラダイムは、すべてのコードが完全に明確であることを意味します。言語は多用途です:を除いて[]{}、構文エラーを引き起こすことなく、すべてのコマンドをプログラム全体のどこにでも配置できます。それは完璧です。
PhiNotPi

4
少し偏っていますか?;-)
Gaffi

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のメタキインをコンソールに出力します(以下の説明)。

#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<<")"; \
  })

変更される唯一の行は最初の行です。の値はX1000、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に近づきます。数学的な証明には、リーマンのゼータ関数が多少入り組んでいます。読者への演習として残しておきます。;)


2

JavaScript、84.5 64 61

2つのプログラム、両方の長さ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;
})();

新しいプログラムを返し、現在の部分を出力します! おそらく関数regexなしで短くすることができますが、...したくありません。


いいえ、それらは構文的に区別されます。改行を追加したら、それが可能です。
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を返すだけなので、このメソッドを簡単に3つのコピーに拡張することはできません:P

プログラム1は、ソー​​スのコード部分のコピーを取得し、引用符を先頭に追加し、それらの引用符の5つを末尾に追加することで動作します((,5#{.))。次に、この16文字の文字列から30文字を周期的に取得し、結果としてプログラム2を正確に取得します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.