Bạn có thể Meta Quine không?


25

Tương tự như các câu đố quine khác (cụ thể hơn là câu đố này ), hãy viết một chương trình tạo nguồn cho chính nó.

Đây là khuynh hướng mới: Mã được tạo ra KHÔNG phải giống hệt với nguồn. Thay vào đó, nó sẽ xuất ra một chương trình khác sẽ tạo ra chương trình đầu tiên.

Thử thách liên quan đến ở trên đã đạt được điều đó bằng cách nhảy giữa hai ngôn ngữ. Tôi nghĩ rằng điều này sẽ được thực hiện chỉ bằng một ngôn ngữ , nhưng hai phiên bản (hoặc nhiều hơn) của nguồn sẽ khác nhau đáng kể (xem quy tắc bên dưới). Với sự hạn chế này, các câu trả lời của một nhân vật sẽ không được phép, do đó đòi hỏi một chút suy nghĩ sẽ được đưa vào một bài nộp cuối cùng.


QUY TẮC

  1. Mã của bạn phải được sản xuất chỉ bằng một ngôn ngữ. (Nhiều bài nộp, một cho mỗi ngôn ngữ là hoàn toàn chấp nhận được.)
  2. Các phiên bản mã khác nhau của bạn phải được phân biệt cú pháp. Nói cách khác, nếu bạn muốn vẽ một cây cú pháp trừu tượng cho mã của mình, thì nên có ít nhất một nút khác nhau.
    • Cung cấp AST sẽ không cần thiết, nhưng nếu bạn cảm thấy có xu hướng cung cấp một cho mỗi chương trình của mình, điều đó sẽ giúp ích trong việc đánh giá.
  3. Bạn có thể tạo ra nhiều lần lặp như bạn muốn, miễn là tất cả chúng vẫn khác biệt về mặt cú pháp. (Nhiều hơn sẽ giúp điểm số của bạn, xem bên dưới.)

KIẾM

Điểm cuối cùng của bạn sẽ là độ dài trung bình của tất cả các chương trình của bạn, chia cho số lượng chương trình.

Ví dụ 1:

A (nguồn cho B) = 50 ký tự
B (nguồn cho A) = 75 ký tự
Điểm cuối cùng = 31,25

Ví dụ 2:

A (nguồn cho B) = 50 ký tự
B (nguồn cho C) = 75 ký tự
C (nguồn cho A) = 100 ký tự
Điểm cuối = 25


18
Tôi meta quine một lần.
mellamokb

1
@mellamokb har har ;-)
Gaffi

Đây thực sự chỉ là một phiên bản tổng quát hơn của thử thách quine này , và các câu trả lời được đưa ra cũng sẽ giành chiến thắng ở đây.
đã ngừng quay ngược chiều

@leftaroundabout, yêu cầu về sự khác biệt cú pháp làm mất hiệu lực một 'quine xoay', vì vậy điều này không chung chung hơn.
gian hàng

2
Không bao giờ meta quine tôi không thích.
Stack Tracer

Câu trả lời:


35

Python, 0 (giới hạn của (68 + 3 n ) / (16 n ))

Nếu hai cây cú pháp trừu tượng khác nhau nếu chúng có các hằng số khác nhau,

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

có 16 n chương trình có độ dài tối đa 68 + 3n, cho điểm không có triệu chứng là 0.

Nếu bạn muốn các chương trình có cấu trúc biến, chúng ta có thể triển khai bộ cộng nhị phân trên n bit. Ở đây, có 2 n chương trình có độ dài O ( n 2 ). Đi trong một chu kỳ do bit mang bị rơi.

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]

Tôi có thể bối rối? Có vẻ như đầu ra giống hệt với nguồn (không phải mục tiêu của thử thách này)?
Gaffi

Nhìn vào khối lồng nhau. passsẽ thay đổi thành t=n(t)và quay lại, trong tất cả các kết hợp 2 ^ n.
gian hàng

Tôi thấy điều đó bây giờ. Bạn làm tôi bối rối với tất cả sự lặp lại!
Gaffi

22
vì một số lý do, tôi thích các giải pháp golf rất dài với điểm số nhỏ.
gian hàng

Wow, bạn hoàn toàn sở hữu điều đó! Rất đẹp.
Claudiu

4

Perl, điểm 110,25

Tôi phải thừa nhận, tôi không giỏi lắm với những điều khoản. Tôi chắc chắn 100% rằng có chỗ để cải thiện. Giải pháp dựa trên cùng một nguyên tắc của giải pháp Element bên dưới.

Chương trình đầu tiên là 264 ký tự.

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

Chương trình thứ hai là 177 ký tự.

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

Tôi đang làm việc trên AST cho mục này (và mục Element).


Yếu tố , điểm 47,25

Chương trình đầu tiên là 105 ký tự.

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

Chương trình thứ hai là 84 ký tự.

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

Tôi chắc chắn rằng có rất nhiều chỗ để cải thiện.

Trong chương trình đầu tiên, có một chuỗi (trong đó mọi ký tự được thoát, mặc dù có rất nhiều dư thừa) theo sau là các phần thực thi A và B. Phần A thực hiện một số điều: in chuỗi và thoát ra khỏi mọi ký tự, in nửa cuối của chuỗi (là nguồn cho phần B), và sau đó ngăn phần B theo sau nó làm bất cứ điều gì.

Chương trình thứ hai là cùng một chuỗi theo sau là phần B. Phần B dựa trên một câu hỏi đơn giản; nó in một chuỗi trước một phiên bản thoát của nó. Điều này có nghĩa là nó in chuỗi và cả hai phần A và B.


Tôi nghĩ điều này dứt khoát, vượt ra ngoài mọi nghi ngờ, chứng minh tính hợp lệ của Element là ngôn ngữ lập trình. Thật dễ sử dụng đến nỗi tôi, thiếu kinh nghiệm đến nỗi tôi chỉ có thể viết một trình thông dịch hoàn chỉnh cho Element, đã có thể trả lời câu hỏi này trước bất kỳ người nào khác trên toàn hành tinh 7.000.000.000 người này. Mô hình "một ký tự, một hàm, mọi lúc" của phần tử có nghĩa là tất cả các mã hoàn toàn không rõ ràng. Ngôn ngữ rất linh hoạt: ngoại trừ []{}, bất kỳ lệnh nào cũng có thể được đặt ở bất kỳ đâu trong toàn bộ chương trình mà không gây ra lỗi cú pháp. Nó là hoàn hảo.
PhiNotPi

4
Một chút thiên vị, phải không? ;-)
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

Điều này được chạy trong MSAccess để sử dụng Moduleđối tượng. Các mô-đun được đặt tên "Q"cho golf. Sự khác biệt trong cú pháp đến từ If ... Thenthiếu từ phiên bản ngắn hơn.


rất có thể bạn sẽ thoát khỏi việc thay đổi vbCrLFthànhvbCr
Taylor Scott

3

C ++, điểm 0,734194

Mã nguồn sau đây in một quine meta thứ tự 999 vào bàn điều khiển (giải thích bên dưới):

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

Dòng duy nhất thay đổi là dòng đầu tiên. Giá trị của Xsẽ là 1000, 999, 998, ..., 3, 2 và sau đó nó sẽ bắt đầu lại. Tuy nhiên, để có được các cây cú pháp khác nhau mỗi lần, Xđược biểu diễn theo hệ số nguyên tố của nó, trong đó mọi số nguyên tố được viết dưới dạng tổng của 1s. AST là khác nhau, bởi vì hệ số nguyên tố của số nguyên là khác nhau đối với mỗi giá trị.

Chương trình sẽ tự in, ngoại trừ dòng đầu tiên được thay đổi và dấu gạch chéo ngược, ngắt dòng và thụt lề bên trong Q(...)sẽ bị xóa.

Chương trình sau đây tính điểm của câu trả lời của tôi:

#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';
}

Nó được in 0,734194 đến bàn điều khiển. Rõ ràng, 1000 có thể được thay thế bằng các số nguyên lớn hơn và điểm sẽ đạt 0 là giới hạn của nó. Bằng chứng toán học liên quan đến chức năng Zeta của Riemann có phần phức tạp. Tôi để nó như một bài tập cho người đọc. ;)


2

JavaScript, 84,5 64 61

Hai chương trình, cả hai chiều dài 169 128 122.

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

Trước khi tôi đánh gôn, vì niềm vui của bạn:

(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;
})();

Trả về chương trình mới và xuất ra phần hiện tại! Tôi có thể làm cho nó ngắn hơn mà không cần chức năng regex, nhưng ... tôi không muốn.


Không, chúng khác biệt về mặt cú pháp. Một khi bạn thêm các dòng mới, đó là.
Ry-

2

J - (24 + 30) / 2/2 = 13,5 điểm

Lưu ý rằng các chuỗi trong J không phải là dấu gạch chéo ngược, mà là trích dẫn à la Pascal : 'I can''t breathe!'.

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

Chương trình 1 có AST noun verb hook nounvà chương trình 2 có AST noun. Chương trình 2 là phiên bản được trích dẫn của chương trình 1, sẽ chỉ trả về chương trình 1 khi chạy, vì vậy phương pháp này không thể được mở rộng thành ba bản sao dễ dàng: P

Chương trình 1 hoạt động bằng cách lấy một bản sao của phần mã nguồn, với một trích dẫn được nối ở phía trước và thêm năm trong số các trích dẫn đó vào cuối ( (,5#{.)). Sau đó, nó lấy theo chu kỳ 30 ký tự từ chuỗi 16 ký tự này, kết quả sẽ cung cấp chính xác Chương trình 2.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.