Quine cứng bức xạ


39

Như bạn nên (hy vọng) biết, một quine cứng bức xạ là một quine mà bạn có thể loại bỏ bất kỳ một ký tự nào và vẫn in nguồn gốc đã được sửa đổi trước của nó. Vấn đề là, với hầu hết những thứ này, bạn chỉ có thể loại bỏ một ký tự; nếu không thì mọi thứ đổ vỡ. Đây là nơi mà điều này đến trong; Mục tiêu của bạn là xây dựng một quine làm cứng bức xạ có thể loại bỏ càng nhiều ký tự càng tốt. Bất kỳ ngôn ngữ tuân thủ các quy tắc là tốt.

Quy tắc

  • Chương trình phải dài ít nhất một ký tự
  • Ngôn ngữ được sử dụng phải được hoàn thành (Vì vậy, các ngôn ngữ như HQ9 + không đủ điều kiện)
  • Tất cả các quy tắc khác áp dụng cho quines bình thường cũng áp dụng ở đây.
  • Các giải pháp với ít nhất program_length^(2/n)trong đó bất kỳ bộ chính xác nký tự có thể được gỡ bỏ khi vẫn in thắng mã nguồn gốc.

1
Tôi đang cố gắng đưa ra một giải pháp Subleq. Tôi nghĩ rằng nó sẽ là lý tưởng cho loại thử thách này!


Có thể thay đổi tên, vì điều này không giống như một quine cứng bức xạ? Có lẽ " quine chống bức xạ "?
Cyoce

@Cyoce Sự khác biệt duy nhất tôi có thể nói là thử thách này dành cho bất kỳ số lần loại bỏ nào, trong khi hầu hết (nếu không phải tất cả) các loại thuốc làm cứng bức xạ khác chỉ cho phép một loại.
luân xa

Giải pháp Ruby từ "mame" nổi tiếng. github.com/mame/radiation-hardened-quine
mbomb007

Câu trả lời:


57

Perl, 1116 1124 byte, n = 3, điểm = 1124 ^ (2/3) hoặc khoảng 108,1

Cập nhật : Bây giờ tôi đã xác minh rằng điều này hoạt động với n = 3 thông qua lực lượng vũ phu (mất vài ngày); với một chương trình phức tạp này, thật khó để kiểm tra khả năng chống bức xạ bằng tay (và tôi đã mắc một lỗi trong phiên bản trước, đó là lý do tại sao số byte tăng lên). Kết thúc cập nhật

Tôi khuyên bạn nên chuyển hướng stderr ở đâu đó mà bạn sẽ không thấy nó; chương trình này tạo ra rất nhiều cảnh báo về cú pháp đáng ngờ ngay cả khi bạn không xóa các ký tự khỏi nó.

Có thể chương trình có thể rút ngắn. Làm việc trên điều này là khá đau đớn, làm cho nó dễ dàng bỏ lỡ tối ưu hóa vi mô có thể. Tôi chủ yếu nhắm đến việc có được số lượng nhân vật có thể xóa càng nhiều càng tốt (vì đó là phần thực sự khó khăn của chương trình), và coi việc bẻ khóa là một điều gì đó tốt đẹp để nhắm đến nhưng như một điều gì đó tôi sẽ không đặt nỗ lực vô lý để tối ưu hóa (trên cơ sở rằng nó rất dễ phá vỡ sự kháng bức xạ do tai nạn).

Chương trình

Lưu ý: có ký tự Điều khiển theo nghĩa đen _(ASCII 31) ngay trước mỗi bốn lần xuất hiện của -+. Tôi không nghĩ rằng nó sao chép và dán chính xác vào StackOverflow, vì vậy bạn sẽ phải thêm lại nó trước khi chạy chương trình.

eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;

Lời giải thích

Chương trình này, khá rõ ràng, được tạo thành từ bốn chương trình nhỏ hơn giống hệt nhau được nối với nhau. Ý tưởng cơ bản là mỗi bản sao của chương trình sẽ xác minh xem nó có bị hỏng quá nặng khi chạy hay không; nếu có, nó sẽ không làm gì cả (ngoài các cảnh báo có thể phun ra) và để bản sao tiếp theo chạy; nếu nó không bị xóa (tức là không xóa hoặc ký tự bị xóa là một thứ không có gì khác biệt đối với hoạt động của chương trình), thì nó sẽ thực hiện điều đó (in ra mã nguồn của chương trình đầy đủ; đây là một câu hỏi đúng đắn, với mỗi phần có chứa một mã hóa toàn bộ mã nguồn) và thoát sau đó (ngăn chặn bất kỳ bản sao không bị hư hại khác từ in mã nguồn ra một lần nữa và do đó làm hỏng Quine bằng cách in quá nhiều văn bản).

Mỗi phần lần lượt được làm bằng hai phần độc lập về chức năng; một trình bao bọc bên ngoài và một số mã nội bộ. Như vậy, chúng ta có thể xem xét chúng một cách riêng biệt.

Bao bọc bên ngoài

Về cơ bản, trình bao bọc bên ngoài, eval<+eval<+eval< ... >####>####...>###(cộng với một loạt dấu chấm phẩy và dòng mới có mục đích khá rõ ràng; để đảm bảo rằng các phần của chương trình sẽ được tách ra bất kể nếu một số dấu chấm phẩy, hoặc dòng mới trước chúng, sẽ bị xóa ). Điều này có thể trông khá đơn giản, nhưng nó tinh tế theo một số cách và lý do tôi chọn Perl cho thử thách này.

Trước tiên, hãy xem cách trình bao bọc hoạt động trong một bản sao không bị hư hại của chương trình. evalphân tích cú pháp như là một hàm dựng sẵn, trong đó có một đối số. Bởi vì một cuộc tranh luận được mong đợi, +đây là một unary +(điều này sẽ rất quen thuộc với những người chơi golf Perl; chúng thường có ích một cách đáng ngạc nhiên). Chúng tôi vẫn đang mong đợi một đối số (chúng tôi chỉ thấy một toán tử đơn nguyên), do đó, toán tử <tiếp theo được hiểu là bắt đầu của <>toán tử (không có đối số tiền tố hoặc hậu tố, và do đó có thể được sử dụng ở vị trí toán hạng).

<>là một toán tử khá kỳ lạ. Mục đích thông thường của nó là để đọc các tập tin và bạn đặt tên tập tin bên trong dấu ngoặc nhọn. Ngoài ra, nếu biểu thức không hợp lệ như một tên tệp, thì nó sẽ tạo ra toàn cầu (về cơ bản, cùng một quy trình mà các shell UNIX sử dụng để dịch văn bản được người dùng nhập vào một chuỗi các đối số dòng lệnh; thực tế đã sử dụng các phiên bản cũ hơn của Perl cái vỏ cho cái này, nhưng ngày nay Perl xử lý toàn cầu trong nội bộ). Do đó, mục đích sử dụng là dọc theo dòng <*.c>, thường sẽ trả về một danh sách như thế nào ("foo.c", "bar.c"). Trong ngữ cảnh vô hướng (chẳng hạn như đối sốeval), nó chỉ trả về mục đầu tiên mà nó tìm thấy lần đầu tiên nó chạy (tương đương với đối số đầu tiên) và sẽ trả về các mục khác trong các lần chạy giả định trong tương lai không bao giờ xảy ra.

Bây giờ, shell thường xử lý các đối số dòng lệnh; nếu bạn đưa ra một cái gì đó giống như -rkhông có đối số, nó sẽ được chuyển đến nguyên văn chương trình, bất kể có tệp nào có tên đó hay không. Perl hoạt động theo cùng một cách, miễn là chúng tôi đảm bảo rằng không có ký tự nào đặc biệt với vỏ hoặc Perl giữa <khớp và khớp >, chúng tôi có thể sử dụng hiệu quả này giống như một dạng chuỗi ký tự thực sự khó xử. Thậm chí tốt hơn, trình phân tích cú pháp của Perl cho các toán tử giống như trích dẫn có xu hướng bắt buộc khớp với các dấu ngoặc ngay cả trong các bối cảnh như thế này khi nó không có ý nghĩa, vì vậy chúng ta có thể lồng <>một cách an toàn (đó là phát hiện cần thiết cho chương trình này). Nhược điểm chính của tất cả các lồng nhau <>này là thoát khỏi nội dung của<>là gần như không thể; Dường như có hai lớp không xác định với nhau <>, vì vậy để thoát khỏi thứ gì đó ở bên trong cả ba, nó cần phải được đi trước với 63 dấu gạch chéo ngược. Tôi đã quyết định rằng mặc dù kích thước mã chỉ là vấn đề thứ yếu trong vấn đề này, nhưng gần như chắc chắn không đáng để trả loại hình phạt này cho điểm của tôi, vì vậy tôi chỉ quyết định viết phần còn lại của chương trình mà không sử dụng các ký tự vi phạm.

Vì vậy, điều gì xảy ra nếu các phần của trình bao bọc bị xóa?

  • Việc xóa trong từ evalkhiến nó biến thành một bareword , một chuỗi không có ý nghĩa. Perl không thích những thứ này, nhưng nó đối xử với họ như thể chúng được bao quanh với các trích dẫn; do đó eal<+eval<+...được hiểu là"eal" < +eval<+.... Điều này không ảnh hưởng gì đến hoạt động của chương trình, vì về cơ bản, nó chỉ lấy kết quả từ các evals lồng nhau (mà chúng ta không sử dụng bằng cách nào), chuyển nó thành một số nguyên và thực hiện một số so sánh vô nghĩa về nó. (Loại điều này gây ra rất nhiều thư rác cảnh báo vì rõ ràng đây không phải là điều hữu ích để thực hiện trong các trường hợp thông thường; chúng tôi chỉ sử dụng nó để xóa các xóa.) Điều này thay đổi số lượng dấu ngoặc góc mà chúng tôi cần (vì dấu ngoặc mở hiện đang được hiểu là một toán tử so sánh thay thế), nhưng chuỗi bình luận ở cuối đảm bảo chuỗi sẽ kết thúc an toàn cho dù nó được lồng bao nhiêu lần. (Có nhiều #dấu hiệu hơn mức cần thiết nghiêm ngặt ở đây; tôi đã viết nó giống như tôi đã làm để làm cho chương trình có thể nén hơn, cho phép tôi sử dụng ít dữ liệu hơn để lưu trữ quine.)
  • Nếu một <bị xóa, mã bây giờ phân tích như là eval(eval<...>). Thứ cấp, bên ngoài evalkhông có tác dụng, bởi vì các chương trình mà chúng tôi đánh giá không trả lại bất kỳ thứ gì có tác dụng thực sự như một chương trình (nếu chúng trở lại bình thường, đó thường là một chuỗi null hoặc một bareword; thông thường chúng sẽ quay trở lại thông qua ngoại lệ, nguyên nhân evaltrả về chuỗi null hoặc sử dụng exitđể tránh trả về tất cả).
  • Nếu +bị xóa, điều này không có hiệu lực ngay lập tức nếu mã liền kề còn nguyên vẹn; unary +không có hiệu lực trên chương trình. (Lý do của các bản gốc +là để giúp sửa chữa thiệt hại; chúng làm tăng số lượng tình huống <được hiểu là đơn nhất <>thay vì là toán tử quan hệ, nghĩa là bạn cần xóa nhiều hơn để tạo chương trình không hợp lệ.)

Trình bao bọc thể bị hỏng với số lần xóa đủ, nhưng bạn cần thực hiện một loạt thao tác xóa để tạo ra thứ gì đó không phân tích cú pháp. Với bốn lần xóa, bạn có thể làm điều này:

eal<evl<eval+<...

và trong Perl, toán tử quan hệ <là không liên kết và do đó bạn gặp lỗi cú pháp (giống như lỗi bạn gặp phải 1<2<3). Như vậy, giới hạn cho chương trình như đã viết là n = 3. Thêm nhiều unary +có vẻ như là một cách đầy hứa hẹn để tăng nó, nhưng vì điều đó sẽ làm cho ngày càng nhiều khả năng bên trong trình bao bọc cũng có thể bị hỏng, việc xác minh rằng phiên bản mới của chương trình hoạt động có thể rất khó khăn.

Lý do trình bao bọc rất có giá trị là vì evaltrong Perl bắt được các ngoại lệ, chẳng hạn như (ví dụ) ngoại lệ mà bạn nhận được khi bạn cố gắng biên dịch lỗi cú pháp. Bởi vì đây evallà một chuỗi ký tự, nên quá trình biên dịch chuỗi xảy ra trong thời gian chạy và nếu nghĩa đen không biên dịch được, ngoại lệ kết quả sẽ bị bắt. Điều này gây ra evaltrả về một chuỗi null và đặt chỉ báo lỗi $@, nhưng chúng tôi không bao giờ kiểm tra (trừ khi thỉnh thoảng thực hiện chuỗi null được trả về trong một vài phiên bản đột biến của chương trình). Điều quan trọng, điều này có nghĩa là nếu một cái gì đó sẽ xảy ra với mã bên trongtrình bao bọc, gây ra lỗi cú pháp, sau đó trình bao bọc sẽ chỉ khiến mã không làm gì thay vào đó (và chương trình sẽ tiếp tục thực thi trong nỗ lực tìm bản sao không bị hư hại của chính nó). Do đó, mã bên trong không nhất thiết phải có khả năng chống bức xạ như trình bao bọc; tất cả những gì chúng tôi quan tâm là nếu bị hỏng, nó sẽ hoạt động giống hệt với phiên bản không bị hư hại của chương trình, nếu không nó sẽ bị hỏng (cho phép evalbắt ngoại lệ và tiếp tục) hoặc thoát bình thường mà không in bất cứ điều gì.

Bên trong bọc

Mã bên trong trình bao bọc, về cơ bản, trông như thế này (một lần nữa, có một Control - _mà Stack Exchange sẽ không hiển thị ngay trước khi -+):

eval+(q(...)=~y=A-Z=-+;-AZz-~=r)

Mã này được viết hoàn toàn bằng các ký tự an toàn toàn cầu và mục đích của nó là thêm một bảng chữ cái mới về dấu chấm câu để có thể viết một chương trình thực, thông qua phiên âm và đánh giá một chuỗi ký tự (chúng tôi không thể sử dụng 'hoặc "làm trích dẫn của chúng tôi nhãn hiệu, nhưng q(... )cũng là một cách hợp lệ để tạo thành một chuỗi trong Perl). (Lý do cho ký tự không thể in được là vì chúng ta cần phiên âm thứ gì đó thành ký tự không gian mà không có ký tự khoảng trắng trong chương trình; do đó chúng ta tạo thành một phạm vi bắt đầu từ ASCII 31 và bắt khoảng trắng là thành phần thứ hai của phạm vi.) Rõ ràng, nếu chúng ta sản xuất một số ký tự thông qua phiên âm, chúng ta phải hy sinh các ký tự để phiên âm chúng từ, nhưng chữ in hoa không hữu ích và viết dễ dàng hơn nhiều nếu không truy cập vào các chữ cái hơn là không truy cập vào dấu chấm câu.

Đây là bảng chữ cái các dấu chấm câu có sẵn do kết quả của toàn cầu (dòng trên hiển thị mã hóa, dòng dưới ký tự mà nó mã hóa):

BCDEFGHIJKLMNOPQRSTUVWXYZ
 ! "# $% & '() * +; <=>? @ AZz {|} ~ 

Đáng chú ý nhất, chúng ta có một loạt các dấu chấm câu không an toàn toàn cầu nhưng rất hữu ích trong việc viết các chương trình Perl, cùng với ký tự khoảng trắng. Tôi cũng đã lưu hai chữ cái viết hoa, nghĩa đen AZ(mã hóa không phải cho chính họ, mà là TU, bởi vì nó Alà cần thiết như một điểm cuối cũng như một điểm cuối phạm vi thấp hơn); điều này cho phép chúng ta tự viết hướng dẫn chuyển ngữ bằng cách sử dụng bộ ký tự được mã hóa mới (mặc dù các chữ cái viết hoa không hữu ích, nhưng chúng hữu ích trong việc chỉ định các thay đổi cho các chữ cái viết hoa). Các ký tự đáng chú ý nhất mà chúng tôi không có sẵn là [, \], nhưng không cần thiết (khi tôi cần một dòng mới trong đầu ra, tôi đã tạo ra nó bằng cách sử dụng dòng mới ẩnsaythay vì cần phải viết \n; chr 10cũng sẽ làm việc nhưng dài dòng hơn).

Như thường lệ, chúng ta cần lo lắng về những gì sẽ xảy ra nếu bên trong của trình bao bọc bị hỏng bên ngoài chuỗi ký tự. Một hỏng evalsẽ ngăn chặn bất cứ điều gì chạy; chúng tôi ổn với điều đó. Nếu dấu ngoặc kép bị hỏng, bên trong chuỗi không hợp lệ Perl, và do đó trình bao bọc sẽ bắt được nó (và rất nhiều phép trừ trên chuỗi có nghĩa là ngay cả khi bạn có thể làm cho Perl hợp lệ, thì nó sẽ không làm gì cả là một kết quả chấp nhận được). Làm hỏng việc chuyển ngữ, nếu đó không phải là lỗi cú pháp, sẽ xâu chuỗi được đánh giá, thường khiến trở thành lỗi cú pháp; Tôi không chắc chắn 100% không có trường hợp nào xảy ra sự cố này, nhưng tôi chắc chắn sẽ buộc nó vào lúc này để đảm bảo, và nó có thể dễ dàng sửa chữa nếu có.

Chương trình được mã hóa

Nhìn vào bên trong chuỗi ký tự, đảo ngược mã hóa tôi đã sử dụng và thêm khoảng trắng để dễ đọc hơn, chúng ta có được điều này (một lần nữa, hãy tưởng tượng một dấu gạch dưới điều khiển trước -+, được mã hóa dưới dạng A):

$o=q<
  length$o  ==181 || zzzz((()));
  do {
    chop ($t = "eval+<"x4);
    $r = '=-+;-AZz-~=';
    $s = '$o=q<' . $o . '>;eval$o';
    eval '$s=~y' . $r . 'A-Z=';
    say "$t(q($s)=~y=A-Z${r}r)" . "####>"x6;
    say ";" for 1..4
  } for 1..4;
  exit>;
eval $o

Những người đã quen với quines sẽ nhận ra cấu trúc chung này. Phần quan trọng nhất là khi bắt đầu, nơi chúng tôi xác minh rằng $ o không bị hư hại; nếu nhân vật đã bị xóa, chiều dài của nó sẽ không phù hợp 181, vì vậy chúng tôi chạy zzzz((()))mà, nếu nó không phải là một lỗi cú pháp do ngoặc chưa từng có, sẽ là một lỗi thời gian chạy ngay cả khi bạn xóa bất kỳ ba nhân vật, bởi vì không ai trong số zzzz, zzz, zz, và zlà một hàm và không có cách nào để ngăn chặn nó phân tích cú pháp như một hàm ngoài việc xóa (((và gây ra lỗi cú pháp đáng ghét. Bản thân việc kiểm tra cũng miễn nhiễm với thiệt hại; các ||thể bị hư hỏng để |nhưng điều đó sẽ gây ra các zzzz((()))cuộc gọi để chạy vô điều kiện; các biến hoặc hằng làm hỏng sẽ gây ra sự không khớp vì bạn đang so sánh một trong số 0,180, 179, 178Bình đẳng đối với một số tập hợp con của các chữ số của 181; và loại bỏ một =sẽ gây ra lỗi phân tích cú pháp và hai =chắc chắn sẽ khiến LHS đánh giá thành số nguyên 0 hoặc chuỗi null, cả hai đều là falsey.

Cập nhật : Kiểm tra này hơi sai trong phiên bản trước của chương trình, vì vậy tôi phải chỉnh sửa nó để khắc phục sự cố. Phiên bản trước trông như thế này sau khi giải mã:

length$o==179||zzzz((()))

và có thể xóa ba dấu chấm câu đầu tiên để có được điều này:

lengtho179||zzz((()))

lengtho179, là một bareword, là sự thật và do đó phá vỡ kiểm tra. Tôi đã sửa lỗi này bằng cách thêm hai Bký tự (mã hóa ký tự khoảng trắng), nghĩa là phiên bản mới nhất của quine thực hiện điều này:

length$o  ==181||zzzz((()))

Bây giờ không thể ẩn cả =dấu và $dấu mà không tạo ra lỗi cú pháp. (Tôi đã có thêm hai khoảng trống chứ không phải là một vì chiều dài 180sẽ đặt một chữ 0nhân vật vào nguồn, có thể bị lạm dụng trong bối cảnh này để nguyên-so sánh số không với một bareword, mà thành công.) Cập nhật End

Khi kiểm tra độ dài trôi qua, chúng tôi biết rằng bản sao không bị hư hại, ít nhất là về việc xóa ký tự khỏi nó, vì vậy tất cả chỉ đơn giản là trích dẫn từ đó (thay thế dấu chấm câu do bảng giải mã bị hỏng sẽ không bị bắt với kiểm tra này , nhưng tôi đã xác minh qua brute-buộc rằng không có ba xóa từ chỉ bảng giải mã phá vỡ Quine; có lẽ hầu hết trong số họ gây ra lỗi cú pháp). Chúng tôi có $otrong một biến đã có, vì vậy tất cả chúng ta cần làm là hardcode giấy gói bên ngoài (với một mức độ nhỏ nén, tôi đã không bỏ ra một phần của câu hỏi hoàn toàn ). Một mẹo nhỏ là chúng tôi lưu trữ phần lớn bảng mã hóa trong$r; chúng ta có thể in nó theo nghĩa đen để tạo phần bảng mã hóa của trình bao bọc bên trong hoặc nối một số mã xung quanh nó và evalđể chạy quá trình giải mã ngược lại (cho phép chúng ta tìm ra phiên bản được mã hóa của $ o là gì , chỉ có phiên bản được giải mã có sẵn tại thời điểm này).

Cuối cùng, nếu chúng tôi là một bản sao nguyên vẹn và do đó có thể xuất toàn bộ chương trình gốc, chúng tôi gọi exitđể ngăn các bản sao khác cũng cố gắng in chương trình ra.

Kịch bản xác minh

Không đẹp lắm, nhưng đăng nó vì có người hỏi. Tôi đã chạy nó nhiều lần với nhiều cài đặt khác nhau (thường thay đổi $min$maxđể kiểm tra các lĩnh vực quan tâm khác nhau); đó không phải là một quá trình hoàn toàn tự động. Nó có xu hướng ngừng chạy do tải CPU nặng ở nơi khác; Khi điều này xảy ra, tôi chỉ thay đổi $minthành giá trị đầu tiên $xkhông được kiểm tra đầy đủ và tiếp tục chạy tập lệnh (do đó đảm bảo rằng tất cả các chương trình trong phạm vi cuối cùng đã được kiểm tra). Tôi chỉ kiểm tra xóa từ bản sao đầu tiên của chương trình, vì khá rõ ràng rằng việc xóa từ các bản sao khác không thể làm gì hơn.

use 5.010;
use IPC::Run qw/run/;
undef $/;
my $program = <>;
my $min = 1;
my $max = (length $program) / 4 - 3;
for my $x ($min .. $max) {
    for my $y ($x .. $max) {
        for my $z ($y .. $max) {
            print "$x, $y, $z\n";
            my $p = $program;
            substr $p, $x, 1, "";
            substr $p, $y, 1, "";
            substr $p, $z, 1, "";
            alarm 4;
            run [$^X, '-M5.010'], '<', \$p, '>', \my $out, '2>', \my $err;
            if ($out ne $program) {
                print "Failed deleting at $x, $y, $z\n";
                print "Output: {{{\n$out}}}\n";
                exit;
            }
        }
    }
}

say "All OK!";

3
OP hơi mơ hồ; nhưng tôi nghĩ điểm sẽ là (1116 * 1116) / 3.
Greg Martin

@GregMartin: (1116 * 1116) / 3 là 415152, vì vậy mục này vẫn sẽ chiến thắng trong những trường hợp đó. Tuy nhiên, tôi không nghĩ OP có thể có nghĩa là bởi vì nó mang lại rất ít động lực để có thể xử lý việc loại bỏ nhiều ký tự. Quine này có thể nhỏ hơn một nửa chiều dài nếu bạn chỉ cần nó để xử lý loại bỏ một ký tự; điều đó sẽ mang lại cho tôi hiệu quả ÷ 4 về điểm số nếu chúng ta diễn giải nó như thế, nó sẽ vượt xa that 3 mà tôi nhận được từ n = 3, và do đó có nghĩa là các mục n = 1 ít thú vị hơn thực sự ghi điểm tốt hơn.

2
Tôi đã ghi bàn rõ ràng hơn. Dù sao, điều này là hoàn toàn không thể tin được; không nghĩ ai sẽ nhận được n> 1.
takra

1
Nó nói điều gì đó về Perl rằng việc viết một chương trình không có chữ cái dễ dàng hơn là không có dấu câu
Robert Fraser

35

Befunge-98 , 884, n = 14, điểm ≈ 2.636

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx"""""""""""""""fffffffffffffff'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''fffffffffffffff\\\\\\\\\\\\\\\111111111111111---------------:::::::::::::::!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!000000000000000aaaaaaaaaaaaaaa---------------bbbbbbbbbbbbbbb---------------***************jjjjjjjjjjjjjjj$$$$$$$$$$$$$$$'''''''''''''''+++++++++++++++kkkkkkkkkkkkkkk,,,,,,,,,,,,,,,333333333333333kkkkkkkkkkkkkkk$$$$$$$$$$$$$$$000000000000000{{{{{{{{{{{{{{{'''''''''''''''888888888888888uuuuuuuuuuuuuuu'''''''''''''''!!!!!!!!!!!!!!!111111111111111+++++++++++++++'''''''''''''''xxxxxxxxxxxxxxx###############;;;;;;;;;;;;;;;:::::::::::::::!!!!!!!!!!!!!!!kkkkkkkkkkkkkkk@@@@@@@@@@@@@@@dddddddddddddddkkkkkkkkkkkkkkk:::::::::::::::eeeeeeeeeeeeeeekkkkkkkkkkkkkkk,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;

Hãy thử trực tuyến!

Điều này không chỉ hoạt động khi bạn xóa chính xác 14 ký tự, nhưng ngay cả khi bạn xóa bất kỳ số lượng nào lên đến 14 ký tự.

n = 14có thể có vẻ như là một sự lựa chọn rất độc đoán, nhưng trên thực tế, kỹ thuật tôi sử dụng chỉ có thể được sử dụng cho các đơn đặt hàng làm cứng bức xạ, nhưng không dễ dàng vượt quá điều đó (có thể là có thể nhưng tôi không biết làm thế nào). Quine order-1 chỉ là 73 byte (mặc dù nó sử dụng một số thủ thuật đánh gôn không áp dụng cho lớn hơn n):

200 20 xx""''ÈÈ..aa22**..33kk$$00{{''!!uu''!!11++''xx##;;::!!kk@@::,,,,;;

Giải trình

Khi tôi thực hiện câu trả lời này, tôi thấy rằng có thể đặt delta của con trỏ lệnh (2,0)trong điều kiện cứng bằng bức xạ với đoạn mã sau:

20020xx

Xem câu trả lời cho lý do tại sao điều này làm việc. Tôi đã tìm thấy điều này chỉ với một chút nghịch ngợm bằng tay, nhưng điều này đặt ra câu hỏi liệu có những mô hình tương tự mạnh mẽ khi loại bỏ nhiều ký tự hay không. Vì vậy, tôi đã viết một kịch bản Mathicala ngắn để tìm kiếm những thứ này bằng vũ lực:

n = 14;
m = 4;
Print @ FromDigits @ {
      m + 1, 0, 
      ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
      m + 1, 0
} & /@ Select[
   Range[0, 2^(n - 4) - 1], 
   AllTrue[
     Subsets[{
         m + 1, 0, 
         ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
         m + 1, 0
       }, 
       {n - m, n - 1}
     ] //. {a___, _, m + 1} | {a___, 0, _} :> {a}, 
     MatchQ@{___, m + 1, 0}
  ] &
];

Điều này rất nhanh chóng tiết lộ một mô hình. Để có được một đoạn tương ứng mà làm việc cho loại bỏ lên đến nký tự, bạn có thể sử dụng (m0x){n}m0ở đâu mn+1xlà một trong hai mhoặc 0. Vì vậy, tất cả những điều sau đây sẽ hoạt động để loại bỏ tối đa hai ký tự:

30030030
30030330
30330030
30330330

Tôi chắc chắn có thể chứng minh điều này, nhưng tôi chỉ đơn giản xác minh ntối đa 7. Tất nhiên, điều này chỉ hoạt động miễn là chúng ta có thể biểu thị n+1dưới dạng một chữ số và chữ số lớn nhất như vậy trong Befunge 98 là fđại diện cho 15. Đó là lý do tại sao cách tiếp cận của tôi bị giới hạn n = 14. Nếu ai đó tìm ra một cách đáng tin cậy để đặt đồng bằng lớn hơn n+1, có khả năng sẽ tăng thứ tự của quine cứng hóa bức xạ này vô thời hạn.

Hãy nhìn vào mã thực tế. Về cơ bản có hai phần. Đầu tiên chúng ta đặt delta (15,0)là như tôi vừa đề cập:

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx

Và phần còn lại của mã có mỗi lệnh được lặp lại 15 lần và in nguồn. Nếu chúng ta loại bỏ sự lặp lại, nó sẽ trông như thế này:

"f'0\'0\'f\1-:!!0a-b-*j$'+k,3k$0{'8u'!1+'x#;:!k@dk:ek,;

Đây "là một kỹ thuật phân loại 2D tiêu chuẩn: nó khởi động chế độ chuỗi, đẩy tất cả các ký tự (trừ chính nó) lên ngăn xếp và kết thúc chế độ chuỗi một lần nữa sau khi quấn quanh. Điều này giúp chúng tôi có được tất cả các điểm mã của nửa sau, nhưng sẽ không giúp chúng tôi có được bất cứ điều gì hữu ích từ nửa đầu, bởi vì trong suốt f00f00...f0bit, nó sẽ chỉ ghi hai ký tự (có thể fhoặc 0tùy thuộc vào ký tự nào bị xóa ). Nhưng vì phần đó không được tạo thành từ các ký tự được lặp lại 15 lần, nên chúng ta sẽ cần in riêng nó.

Thuận tiện hơn, trong quine không thay đổi, độ dài của chuỗi trước "-1 (mod 15). Điều này đảm bảo rằng cho dù chúng tôi có xóa bao nhiêu ký tự (tối đa 14 ký tự) thì số lượng ký tự được ghi luôn luôn có 3 (một xvà hai f0). Điều này thực sự đúng với bất kỳ thứ tự bức xạ nào lên đến 14.

Bây giờ chúng tôi bắt đầu bằng cách in f00f00...f0phần:

f'0\'0\'f\1-:!!0a-b-*j$'+k,

f          Push 15, a loop counter.
'0\'0\'f\  Put "00f" underneath the loop counter.
1-         Decrement the loop counter.
:!!        Copy it, and turn it into a 1 if it's positive.
0a-b-      Push -21.
*          Multiply by 0 if the loop counter is zero, or by 1 otherwise.
j          Jump that many steps. If the value was 0, this is a no-op and
           the loop ends. Otherwise, this brings us back after the f.
$          Pop the loop counter (which is now 0).
'+k,       Print the top of the stack 43 times, which gives us all of
           the "f00f00...f0" and leaves one "0" on top of the stack.

Việc tiếp theo 3k$chỉ đơn giản là loại bỏ 0cũng như ba nhân vật đã được thúc đẩy "từ đầu chương trình. Bây giờ ngăn xếp chỉ chứa các ký tự sau "cũng như một số rác bên dưới bản gốc f00f00...f0tùy thuộc vào ký tự nào đã bị xóa.

Bây giờ chúng ta chỉ cần đảo ngược đỉnh của ngăn xếp (chứa các ký tự còn lại) và in mỗi một trong số chúng 15 lần.

0{     Start a new, empty stack. This pushes two zeros onto the original stack.
'8u    Move the top 56 values from the original stack to the new one, which
       is the 54 characters after the " as well as those two zeros. This is
       implemented as pop-push loop, so it reverses the order of those elements.
'!1+   Push a " by incrementing a !.
'x     Push an x. Now we've got all the characters that are repeated 15 times.
#;     Enter a loop. This is a standard technique for Befunge-98: the ; is
       a bit like a comment character, that ignores everything until the next
       ;, but we jump over the first one with #, so that from now on only
       the code inside will be executed (over and over).
  :!     Copy the top of the stack, and compute logical NOT (1 if 0, 0 otherwise).
  k@     Terminate the program that many times (i.e. when the top of the
         stack is zero).
  dk:    Make 14 copies of the top of the stack.
  ek,    Print 15 characters from the top of the stack.
;

Và đó là nó. :)


16

JavaScript (ES6), 927 byte, n = 1, điểm = 859329

lưu ý: không sử dụng REPL (như bảng điều khiển trình duyệt) để chạy cái này.

Điều này đã được viết trước khi độ dài mã là một yếu tố, vì vậy nó chưa được đánh gôn.

Điều này rất khó khăn, và xứng đáng được giải thích kỹ lưỡng. Mà tôi sẽ viết sau, sau khi tôi khám phá thử thách này thêm một chút nữa!

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

lưu ý: có một dòng mới

Về cơ bản, dòng đầu tiên được xây dựng cẩn thận để đổi tên tất cả các 'lỗi chính tả' thành các setTimeouthàm hợp lệ, do đó, nếu một ký tự được xóa khỏi một trong setTimeoutcác mã sẽ không bị lỗi và phiên bản không bị lỗi có thể chạy. Nó cũng được viết để nếu bất kỳ một ký tự nào bị xóa khỏi dòng đầu tiên, sẽ không có lỗi và phần còn lại của mã có thể chạy không bị ảnh hưởng.

Các khối thứ hai và thứ ba là chính xác tương đương. Nếu một cái chạy đến hoàn thành, nó đặt _biến để cái kia biết không trùng lặp quine. Nếu một trong các khối này bị lỗi, nó không ảnh hưởng đến khối kia vì nó được gọi là sử dụng không đồng bộ setTimeout. Lỗi sẽ _không được đặt, do đó, khối khác sẽ kiểm tra thành công. Mã chính nằm trong một chuỗi, được kiểm tra độ dài trong mỗi khối để đảm bảo rằng không có loại bỏ.

Chuỗi mẫu trên dòng tiếp theo với một số nhận xét ở cuối chuỗi mẫu bảo vệ mã không bị lỗi nếu một trong các backticks tạo thành chuỗi mẫu bị xóa. Nếu backtick kết thúc bị loại bỏ, chuỗi mẫu được kết thúc bằng backtick trong bình luận. Nếu backtick bắt đầu bị loại bỏ, setTimeout được đánh giá là một hàm chưa được gán (không có op) và mã chạy như bình thường, không có setTimeout. Backtick kết thúc bị vô hiệu hóa bởi một bình luận khác.


Những gì bạn nói? Bạn muốn thử nó? Không nói nữa!

Chế độ toàn trang được đề nghị.

Bỏ qua hộp đầu vào, đoạn mã này không có đầu vào.

Hãy thử xóa bất kỳ một ký tự khỏi mã!

Đừng tin điều đó? Mã thông thường sẽ vẫn hoạt động (nhưng nó sẽ không hoạt động ...) Hãy thử một cái gì đó như console.log(5)!

lưu ý: đoạn mã phải được sửa đổi một chút để tắt tính năng REPL, vì vậy tôi chỉ loại bỏ nhiều khả năng đầu ra cho câu trả lời này.

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`
<!--                               Try the test suite below!                              --><strong id="bytecount" style="display:inline; font-size:32px; font-family:Helvetica"></strong><strong id="bytediff" style="display:inline; margin-left:10px; font-size:32px; font-family:Helvetica; color:lightgray"></strong><br><br><pre style="margin:0">Code:</pre><textarea id="textbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><pre style="margin:0">Input:</pre><textarea id="inputbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><button id="testbtn">Test!</button><button id="resetbtn">Reset</button><br><p><strong id="origheader" style="font-family:Helvetica; display:none">Original Code Output:</strong><p><div id="origoutput" style="margin-left:15px"></div><p><strong id="newheader" style="font-family:Helvetica; display:none">New Code Output:</strong><p><div id="newoutput" style="margin-left:15px"></div><script type="text/javascript" id="golfsnippet">var bytecount=document.getElementById("bytecount");var bytediff=document.getElementById("bytediff");var textbox=document.getElementById("textbox");var inputbox=document.getElementById("inputbox");var testbtn=document.getElementById("testbtn");var resetbtn=document.getElementById("resetbtn");var origheader=document.getElementById("origheader");var newheader=document.getElementById("newheader");var origoutput=document.getElementById("origoutput");var newoutput=document.getElementById("newoutput");textbox.style.width=inputbox.style.width=window.innerWidth-50+"px";var _originalCode=null;function getOriginalCode(){if(_originalCode!=null)return _originalCode;var allScripts=document.getElementsByTagName("script");for(var i=0;i<allScripts.length;i++){var script=allScripts[i];if(script.id!="golfsnippet"){originalCode=script.textContent.trim();return originalCode}}}function getNewCode(){return textbox.value.trim()}function getInput(){try{var inputText=inputbox.value.trim();var input=eval("["+inputText+"]");return input}catch(e){return null}}function setTextbox(s){textbox.value=s;onTextboxChange()}function setOutput(output,s){output.innerHTML=s}function addOutput(output,data){output.innerHTML='<pre style="background-color:'+(data.type=="err"?"lightcoral":"lightgray")+'">'+escape(data.content)+"</pre>"}function getByteCount(s){return(new Blob([s],{encoding:"UTF-8",type:"text/plain;charset=UTF-8"})).size}function onTextboxChange(){var newLength=getByteCount(getNewCode());var oldLength=getByteCount(getOriginalCode());bytecount.innerHTML=newLength+" bytes";var diff=newLength-oldLength;if(diff>0){bytediff.innerHTML="(+"+diff+")";bytediff.style.color="lightcoral"}else if(diff<0){bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgreen"}else{bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgray"}}function onTestBtn(evt){origheader.style.display="inline";newheader.style.display="inline";setOutput(newoutput,"");setOutput(origoutput,"");var input=getInput();if(input===null){addOutput(origoutput,{type:"err",content:"Input is malformed. Using no input."});addOutput(newoutput,{type:"err",content:"Input is malformed. Using no input."});input=[]}doInterpret(getNewCode(),input,function(data){addOutput(newoutput,data)});doInterpret(getOriginalCode(),input,function(data){addOutput(origoutput,data)});evt.stopPropagation();return false}function onResetBtn(evt){setTextbox(getOriginalCode());origheader.style.display="none";newheader.style.display="none";setOutput(origoutput,"");setOutput(newoutput,"")}function escape(s){return s.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}window.alert=function(){};window.prompt=function(){};function doInterpret(code,input,cb){var workerCode=interpret.toString()+";function stdout(s){ self.postMessage( {'type': 'out', 'content': s} ); }"+" function stderr(s){ self.postMessage( {'type': 'err', 'content': s} ); }"+" function kill(){ self.close(); }"+" self.addEventListener('message', function(msg){ interpret(msg.data.code, msg.data.input); });";var interpreter=new Worker(URL.createObjectURL(new Blob([workerCode])));interpreter.addEventListener("message",function(msg){cb(msg.data)});interpreter.postMessage({"code":code,"input":input});setTimeout(function(){interpreter.terminate()},1E4)}setTimeout(function(){getOriginalCode();textbox.addEventListener("input",onTextboxChange);testbtn.addEventListener("click",onTestBtn);resetbtn.addEventListener("click",onResetBtn);setTextbox(getOriginalCode())},100);function interpret(code,input){_=undefined;window={};alert=function(s){stdout(s)};window.alert=alert;console.log=alert;prompt=function(s){if(input.length<1)stderr("not enough input");else{var nextInput=input[0];input=input.slice(1);return nextInput.toString()}};window.prompt=prompt;(function(){try{_=undefined;eval(code);if(typeof evalResult=="disabled_function_evaluation"){var callResult=evalResult.apply(this,input);if(typeof callResult!="undefined")stdout(callResult)}}catch(e){stderr(e.message)}})()};</script>

Một lời giải thích tốt hơn là sắp tới. Trong lúc này, vui lòng ping tôi trong trò chuyện @jrich với bất kỳ nhận xét / câu hỏi / chỉ trích nào!


ah được rồi, rất tiếc: |
Hạ cấp

4
Sử dụng thisthay vì window.
Mama Fun Roll

3
+1 để bao gồm ý nghĩa của cuộc sống trong mã nguồn của bạn
Cyoce
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.