Radiasi Quine Hardened


39

Seperti yang seharusnya (semoga) Anda ketahui, quine hardened radiasi adalah quine yang dapat Anda hapus satu karakter dari dan masih mencetak aslinya, sumber yang telah dimodifikasi. Masalahnya adalah, dengan sebagian besar dari ini Anda hanya dapat menghapus satu karakter; kalau tidak semuanya rusak. Di sinilah ini masuk; tujuan Anda adalah membangun quine yang dikeraskan dengan radiasi yang dapat mengambil sebanyak mungkin pemindahan karakter. Bahasa apa pun yang mematuhi aturan tidak masalah.

Aturan

  • Panjang program minimal harus satu karakter
  • Bahasa yang digunakan harus turing lengkap (Jadi bahasa seperti HQ9 + tidak memenuhi syarat)
  • Semua aturan lain yang berlaku untuk quine normal juga berlaku di sini.
  • Solusi dengan yang paling sedikit program_length^(2/n)di mana setiap set nkarakter yang tepat dapat dihapus saat masih mencetak kode sumber asli menang.

1
Saya mencoba mencari solusi Subleq. Saya pikir ini akan ideal untuk tantangan semacam ini!


Mungkin ganti namanya, mengingat ini tidak sama dengan radiasi yang dikuatkan quine? Mungkin " quine tahan radiasi "?
Cyoce

@Cyoce Satu-satunya perbedaan yang dapat saya katakan adalah bahwa tantangan ini adalah untuk sejumlah pemindahan, sementara sebagian besar (jika tidak semua) quines lain yang dikeraskan dengan radiasi hanya memungkinkan untuk satu.
takra

Solusi Ruby dari "mame" yang terkenal. github.com/mame/radiation-hardened-quine
mbomb007

Jawaban:


57

Perl, 1116 1124 byte, n = 3, skor = 1124 ^ (2/3) atau sekitar 108.1

Memperbarui : Saya sekarang telah memverifikasi bahwa ini bekerja dengan n = 3 via brute force (yang membutuhkan beberapa hari); dengan program kompleks ini, sulit untuk memeriksa ketahanan radiasi dengan tangan (dan saya membuat satu kesalahan dalam versi sebelumnya, itulah sebabnya jumlah byte meningkat). Akhiri pembaruan

Saya sarankan mengarahkan stderr di suatu tempat yang Anda tidak akan melihatnya; program ini menghasilkan satu ton peringatan tentang sintaksis yang meragukan bahkan ketika Anda tidak menghapus karakter darinya.

Mungkin saja program ini dapat dipersingkat. Mengerjakan ini cukup menyakitkan, membuatnya mudah kehilangan kemungkinan optimasi mikro. Saya sebagian besar bertujuan untuk mendapatkan jumlah karakter yang dapat dihapus setinggi mungkin (karena itu benar-benar menantang dari program ini), dan memperlakukan tiebreak sebagai sesuatu yang menyenangkan untuk dibidik tetapi sebagai sesuatu yang saya tidak ingin taruh. upaya konyol untuk mengoptimalkan (atas dasar itu sangat mudah untuk mematahkan resistensi radiasi secara tidak sengaja).

Program

Catatan: ada _karakter Kontrol literal (ASCII 31) segera sebelum masing-masing dari empat kejadian -+. Saya tidak berpikir itu menyalin dan menempel ke StackOverflow dengan benar, jadi Anda harus menambahkannya kembali sebelum menjalankan program.

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)####>####>####>####>####>####>
;
;
;
;

Penjelasan

Program ini, cukup jelas, terbuat dari empat program kecil yang identik digabung bersama. Ide dasarnya adalah bahwa setiap salinan program akan memverifikasi apakah sudah rusak terlalu buruk untuk dijalankan atau tidak; jika sudah, ia tidak akan melakukan apa-apa (selain kemungkinan memuntahkan peringatan) dan membiarkan salinan selanjutnya dijalankan; jika belum (yaitu tidak ada penghapusan, atau karakter yang dihapus adalah sesuatu yang tidak membuat perbedaan pada operasi program), itu akan melakukan hal yang quiny (mencetak kode sumber program lengkap; ini adalah quine yang tepat, dengan setiap bagian yang berisi penyandian seluruh kode sumber) dan kemudian keluar (mencegah salinan tidak rusak lainnya dari mencetak kode sumber lagi dan dengan demikian merusak quine dengan mencetak terlalu banyak teks).

Setiap bagian pada gilirannya terbuat dari dua bagian yang secara fungsional independen secara efektif; bungkus luar dan beberapa kode internal. Dengan demikian, kita dapat mempertimbangkannya secara terpisah.

Pembungkus luar

Pembungkus luar, pada dasarnya, eval<+eval<+eval< ... >####>####...>### (ditambah banyak titik koma dan baris baru yang tujuannya harus cukup jelas; itu untuk memastikan bahwa bagian-bagian dari program akan tetap terpisah terlepas dari apakah beberapa titik koma, atau baris baru sebelum mereka, dihapus ). Ini mungkin terlihat cukup sederhana, tetapi halus dalam beberapa cara, dan alasan saya memilih Perl untuk tantangan ini.

Pertama, mari kita lihat bagaimana fungsi wrapper dalam salinan program yang tidak rusak. evalmem-parsing sebagai fungsi bawaan, yang mengambil satu argumen. Karena sebuah argumen diharapkan, +ini adalah unary +(yang akan sangat akrab bagi pegolf Perl sekarang; mereka sering berguna secara mengejutkan). Kami masih mengharapkan argumen (kami baru saja melihat operator yang tidak waspada), sehingga <yang datang selanjutnya ditafsirkan sebagai awal dari <>operator (yang tidak menggunakan argumen awalan atau postfix, dan dengan demikian dapat digunakan dalam posisi operan).

<>adalah operator yang cukup aneh. Tujuan biasanya adalah untuk membaca filehandles, dan Anda menempatkan nama filehandle di dalam kurung sudut. Atau, jika ekspresi tidak valid sebagai nama filehandle, itu globbing (pada dasarnya, proses yang sama yang digunakan shell UNIX untuk menerjemahkan teks yang dimasukkan oleh pengguna ke urutan argumen baris perintah; versi Perl yang lebih lama sebenarnya digunakan) shell untuk ini, tetapi sekarang Perl menangani globbing secara internal). Penggunaan yang dimaksudkan, oleh karena itu, di sepanjang garis <*.c>, yang biasanya akan mengembalikan daftar seperti ("foo.c", "bar.c"). Dalam konteks skalar (seperti argumen untukeval), ia hanya mengembalikan entri pertama yang ditemukan pertama kali dijalankan (setara dengan argumen pertama), dan akan mengembalikan entri lain pada hipotetis masa depan yang tidak pernah terjadi.

Sekarang, kerang sering menangani argumen baris perintah; jika Anda memberikan sesuatu seperti -rtanpa argumen, itu hanya akan diteruskan ke program kata demi kata, terlepas dari apakah ada file dengan nama itu atau tidak. Perl bertindak dengan cara yang sama, jadi selama kami memastikan bahwa tidak ada karakter yang khusus untuk shell atau untuk Perl antara <dan yang cocok >, kami dapat secara efektif menggunakan ini seperti bentuk string literal yang benar-benar canggung. Bahkan lebih baik, parser Perl untuk operator seperti kutipan memiliki kecenderungan kompulsif untuk mencocokkan tanda kurung bahkan dalam konteks seperti ini di mana tidak masuk akal, jadi kita bisa membuat sarang <>dengan aman (yang merupakan penemuan yang diperlukan untuk program ini dimungkinkan). Kelemahan utama dari semua ini <>adalah bahwa melarikan diri dari isi<>hampir mustahil; tampaknya ada dua lapisan unescaping dengan masing-masing <>, jadi untuk menghindari sesuatu di dalam ketiganya, perlu didahului dengan 63 backslash. Saya memutuskan bahwa meskipun ukuran kode hanya pertimbangan sekunder dalam masalah ini, hampir pasti tidak ada gunanya membayar hukuman seperti ini untuk skor saya, jadi saya hanya memutuskan untuk menulis sisa program tanpa menggunakan karakter yang menyinggung.

Jadi apa yang terjadi jika bagian pembungkus terhapus?

  • Penghapusan kata evalmenyebabkannya berubah menjadi kata kunci , string tanpa arti. Perl tidak suka ini, tetapi memperlakukan mereka seolah-olah mereka dikelilingi dengan tanda kutip; dengan demikian eal<+eval<+...ditafsirkan sebagai"eal" < +eval<+.... Ini tidak berpengaruh pada operasi program, karena pada dasarnya hanya mengambil hasil dari evals yang sangat bersarang (yang tidak kita gunakan lagi), melemparkannya ke integer, dan melakukan beberapa perbandingan yang tidak berguna di atasnya. (Hal semacam ini menyebabkan banyak spam peringatan karena ini jelas bukan hal yang berguna untuk dilakukan dalam keadaan normal; kami hanya menggunakannya untuk menyerap penghapusan.) Ini mengubah jumlah kurung sudut penutup yang kami butuhkan (karena braket pembuka sekarang ditafsirkan sebagai operator perbandingan sebagai gantinya), tetapi rantai komentar pada akhirnya memastikan string akan berakhir dengan aman tidak peduli berapa kali bersarang. (Ada lebih banyak #tanda daripada yang dibutuhkan di sini; saya menulisnya seperti yang saya lakukan untuk membuat program lebih kompresibel, membiarkan saya menggunakan lebih sedikit data untuk menyimpan quine.)
  • Jika a <dihapus, kode sekarang diuraikan sebagai eval(eval<...>). Yang sekunder, di luar evaltidak memiliki efek, karena program yang kami evaluasi tidak mengembalikan apa pun yang memiliki efek nyata sebagai program (jika mereka kembali secara normal, itu biasanya berupa string nol atau kata kunci; lebih umum mereka kembali melalui pengecualian, yang menyebabkan evaluntuk mengembalikan string nol, atau gunakan exituntuk menghindari kembali sama sekali).
  • Jika +terhapus, ini tidak memiliki efek langsung jika kode yang berdekatan itu utuh; unary +tidak berpengaruh pada program. (Alasan yang asli +ada untuk membantu memperbaiki kerusakan; mereka meningkatkan jumlah situasi di mana <ditafsirkan sebagai unary <>daripada sebagai operator relasional, artinya Anda perlu lebih banyak penghapusan untuk menghasilkan program yang tidak valid.)

Pembungkus dapat rusak dengan penghapusan yang cukup, tetapi Anda perlu melakukan serangkaian penghapusan untuk menghasilkan sesuatu yang tidak diuraikan. Dengan empat penghapusan, Anda dapat melakukan ini:

eal<evl<eval+<...

dan di Perl, operator relasional <adalah nonassociative, dan dengan demikian Anda mendapatkan kesalahan sintaksis (yang sama dengan yang Anda dapatkan 1<2<3). Dengan demikian, batas atas program yang ditulis adalah n = 3. Menambahkan lebih banyak unary +tampaknya merupakan cara yang menjanjikan untuk meningkatkannya, tetapi karena hal itu akan membuat semakin mungkin bahwa bagian dalam bungkusnya juga dapat rusak, memverifikasi bahwa versi baru dari program ini bekerja bisa sangat sulit.

Alasan pembungkus sangat berharga adalah bahwa evaldi Perl menangkap pengecualian, seperti (misalnya) pengecualian yang Anda dapatkan ketika Anda mencoba untuk mengkompilasi kesalahan sintaks. Karena ini evaladalah string literal, kompilasi string terjadi saat runtime, dan jika literal gagal dikompilasi, pengecualian yang dihasilkan tertangkap. Hal ini menyebabkan evaluntuk mengembalikan string nol dan mengatur indikator kesalahan $@, tetapi kami tidak pernah memeriksa keduanya (kecuali dengan sesekali mengeksekusi string null yang dikembalikan dalam beberapa versi program yang dimutasi). Yang terpenting, ini berarti bahwa jika terjadi sesuatu pada kode di dalamnyawrapper, menyebabkan kesalahan sintaks, maka wrapper hanya akan menyebabkan kode tidak melakukan apa-apa sebagai gantinya (dan program akan terus mengeksekusi dalam upaya untuk menemukan salinan dirinya sendiri yang tidak rusak). Oleh karena itu, kode di dalam tidak harus hampir seperti radiasi sebagai pembungkus; semua yang kami pedulikan adalah bahwa jika rusak, ia akan bertindak secara identik dengan versi program yang tidak rusak, atau akan macet (memungkinkan evaluntuk menangkap pengecualian dan melanjutkan) atau keluar secara normal tanpa mencetak apa pun.

Di dalam bungkusnya

Kode di dalam pembungkus, pada dasarnya, terlihat seperti ini (sekali lagi, ada Kontrol - _bahwa Stack Exchange tidak akan ditampilkan segera sebelum -+):

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

Kode ini ditulis seluruhnya dengan karakter glob-safe, dan tujuannya adalah untuk menambahkan alfabet tanda baca baru yang memungkinkan untuk menulis program nyata, melalui transliterasi dan evaluasi string literal (kami tidak dapat menggunakan 'atau "sebagai kutipan kami tanda, tapi q(... )juga merupakan cara yang valid untuk membentuk string dalam Perl). (Alasan untuk karakter yang tidak diinginkan adalah bahwa kita perlu mentransliterasi sesuatu ke dalam karakter ruang tanpa karakter spasi literal dalam program; sehingga kita membentuk rentang mulai dari ASCII 31, dan menangkap ruang sebagai elemen kedua dari jangkauan.) jelas, jika kita memproduksi beberapa karakter melalui transliterasi, kita harus mengorbankan karakter untuk transliterasi mereka dari, tetapi huruf besar tidak terlalu berguna dan lebih mudah untuk menulis tanpa akses ke mereka daripada tanpa akses ke tanda baca.

Berikut adalah alfabet tanda baca yang tersedia sebagai hasil dari glob (baris atas menunjukkan pengodean, semakin rendah karakter yang dikodekan):

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

Terutama, kami memiliki banyak tanda baca yang tidak aman-glob tetapi berguna dalam menulis program Perl, bersama dengan karakter luar angkasa. Saya juga menyimpan dua huruf besar, literal Adan Z(yang mengkodekan bukan untuk diri mereka sendiri, tetapi untuk Tdan U, karena Adiperlukan sebagai titik akhir atas dan bawah kisaran); ini memungkinkan kita untuk menulis instruksi transliterasi itu sendiri menggunakan set karakter yang disandikan baru (meskipun huruf besar tidak berguna, mereka berguna dalam menentukan perubahan pada huruf besar). Karakter paling terkenal yang tidak kami miliki adalah [,, \dan ], tetapi tidak diperlukan (ketika saya membutuhkan baris baru dalam output, saya memproduksinya menggunakan baris baru implisit darisaydaripada perlu menulis \n; chr 10akan bekerja tetapi lebih verbose).

Seperti biasa, kita perlu khawatir tentang apa yang terjadi jika bagian dalam bungkusnya rusak di luar string literal. Seorang yang rusak evalakan mencegah apa pun berjalan; kami baik-baik saja dengan itu. Jika tanda kutip rusak, bagian dalam string tidak Perl valid, dan dengan demikian pembungkus akan menangkapnya (dan banyak pengurangan pada string berarti bahwa bahkan jika Anda bisa membuatnya Perl valid, itu tidak akan melakukan apa pun, yang adalah hasil yang dapat diterima). Kerusakan transliterasi, jika itu bukan kesalahan sintaks, akan mangle string sedang dievaluasi, biasanya menyebabkan hal itu menjadi kesalahan sintaks; Saya tidak 100% yakin tidak ada kasus di mana ini rusak, tapi saya brute-memaksa saat ini untuk memastikan, dan itu harus cukup mudah untuk memperbaikinya jika ada.

Program yang disandikan

Melihat ke dalam string literal, membalikkan pengkodean yang saya gunakan, dan menambahkan spasi putih untuk membuatnya lebih mudah dibaca, kita mendapatkan ini (sekali lagi, bayangkan garis bawah kontrol sebelum -+, yang dikodekan sebagai 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

Orang yang terbiasa dengan quines akan mengenali struktur umum ini. Bagian yang paling penting adalah di awal, di mana kami memverifikasi bahwa $ o tidak rusak; jika karakter telah dihapus, panjangnya tidak akan cocok 181, jadi kami berjalan zzzz((()))yang, jika tidak kesalahan sintaks karena kurung tak tertandingi, akan menjadi kesalahan runtime bahkan jika Anda menghapus tiga karakter, karena tidak ada zzzz, zzz, zz, dan zmerupakan fungsi, dan tidak ada cara untuk mencegahnya parsing sebagai fungsi selain menghapus (((dan menyebabkan kesalahan sintaks yang tidak jelas. Cek itu sendiri juga kebal terhadap kerusakan; yang ||bisa rusak ke |tapi itu akan menyebabkan zzzz((()))panggilan untuk menjalankan tanpa syarat; variabel atau konstanta yang rusak akan menyebabkan ketidakcocokan karena Anda membandingkan salah satu dari 0,180, 179, 178Kesetaraan untuk beberapa subset dari digit 181; dan menghapus satu =akan menyebabkan kegagalan parse, dan dua =tidak dapat dihindari menyebabkan LHS untuk mengevaluasi baik integer 0 atau string nol, yang keduanya falsey.

Pembaruan : Pemeriksaan ini sedikit salah dalam versi program sebelumnya, jadi saya harus mengeditnya untuk memperbaiki masalah. Versi sebelumnya tampak seperti ini setelah decode:

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

dan dimungkinkan untuk menghapus tiga tanda baca pertama untuk mendapatkan ini:

lengtho179||zzz((()))

lengtho179, menjadi juru kunci, adalah benar dan dengan demikian merusak cek. Saya memperbaikinya dengan menambahkan dua Bkarakter tambahan (yang menyandikan karakter spasi), artinya versi terbaru dari quine melakukan ini:

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

Sekarang tidak mungkin menyembunyikan =tanda dan $tanda tanpa menghasilkan kesalahan sintaksis. (Saya harus menambahkan dua spasi daripada satu karena panjang 180akan menempatkan 0karakter literal ke dalam sumber, yang dapat disalahgunakan dalam konteks ini untuk integer-bandingkan nol dengan bareword, yang berhasil.) Akhiri pembaruan

Setelah pemeriksaan panjang berlalu, kita tahu salinannya tidak rusak, setidaknya dalam hal penghapusan karakter dari itu, jadi itu semua hanya langsung quining dari sana (penggantian tanda baca karena tabel decoding yang rusak tidak akan tertangkap dengan pemeriksaan ini , tapi saya sudah memverifikasi melalui brute-forcing bahwa tidak ada tiga penghapusan dari hanya tabel decoding yang memecahkan quine; mungkin sebagian besar dari mereka menyebabkan kesalahan sintaksis). Kita sudah memiliki $ovariabel, jadi yang perlu kita lakukan hanyalah meng-hardcode pembungkus luar (dengan sedikit tingkat kompresi; saya tidak melewatkan bagian dari pertanyaan sepenuhnya ). Salah satu triknya adalah kita menyimpan sebagian besar tabel penyandian di$r; kita dapat mencetaknya secara harfiah untuk menghasilkan bagian tabel penyandian dari pembungkus dalam, atau menggabungkan beberapa kode di sekitarnya dan evalitu untuk menjalankan proses decoding secara terbalik (memungkinkan kita untuk mencari tahu apa versi $ o yang dikodekan adalah , hanya memiliki versi yang diterjemahkan yang tersedia pada saat ini).

Akhirnya, jika kami adalah salinan utuh dan dengan demikian dapat menampilkan seluruh program asli, kami memanggil exituntuk mencegah salinan lain juga mencoba untuk mencetak program.

Skrip verifikasi

Tidak terlalu cantik, tetapi mempostingnya karena seseorang bertanya. Saya menjalankan ini beberapa kali dengan berbagai pengaturan (biasanya berubah $mindan $maxuntuk memeriksa berbagai bidang yang menarik); itu bukan proses yang sepenuhnya otomatis. Ini memiliki kecenderungan untuk berhenti berjalan karena beban CPU yang berat di tempat lain; ketika ini terjadi, saya baru saja mengubah $minke nilai pertama $xyang tidak sepenuhnya diperiksa dan terus menjalankan skrip (sehingga memastikan bahwa semua program dalam jangkauan akhirnya diperiksa). Saya hanya memeriksa penghapusan dari salinan pertama program, karena cukup jelas bahwa penghapusan dari salinan lain tidak dapat berbuat lebih banyak.

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 sedikit ambigu; tapi saya pikir nilainya (1116 * 1116) / 3.
Greg Martin

@GregMartin: (1116 * 1116) / 3 adalah 415152, jadi entri ini masih akan menang dalam kondisi tersebut. Namun, saya tidak berpikir OP dapat berarti karena itu akan memberikan insentif yang sangat kecil untuk dapat menangani penghapusan beberapa karakter. Quine ini bisa kurang dari setengah panjangnya jika Anda hanya perlu menangani satu penghapusan karakter; itu akan memberi saya nilai ÷ 4 yang efektif jika kita menafsirkannya seperti itu, yang akan lebih besar dari that 3 yang saya dapatkan dari n = 3, dan dengan demikian berarti bahwa entri n = 1 yang kurang menarik sebenarnya adalah skor yang lebih baik.

2
Saya membuat skor lebih jelas. Bagaimanapun, ini benar-benar luar biasa; tidak mengira ada orang yang akan mendapatkan> 1.
takra

1
Ia mengatakan sesuatu tentang Perl yang lebih mudah untuk menulis sebuah program tanpa surat daripada tanpa tanda baca
Robert Fraser

35

Befunge-98 , 884, n = 14, skor ≈ 2.636

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

Cobalah online!

Ini tidak hanya berfungsi ketika Anda menghapus tepat 14 karakter, tetapi bahkan ketika Anda menghapus jumlah apa pun hingga 14 karakter.

n = 14mungkin tampak seperti pilihan yang sangat sewenang-wenang, tetapi teknik yang saya gunakan sebenarnya hanya dapat digunakan untuk pesanan pengerasan radiasi dari 1 hingga 14, tetapi tidak mudah di luar itu (mungkin saja tetapi saya tidak tahu bagaimana). Kueri urutan-1 hanya 73 byte (meskipun menggunakan beberapa trik golf yang tidak berlaku untuk yang lebih besar n):

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

Penjelasan

Ketika saya mengerjakan jawaban ini, saya menemukan bahwa mungkin untuk mengatur delta penunjuk instruksi ke (2,0)dalam kondisi yang dikeraskan dengan cuplikan berikut:

20020xx

Lihat jawaban itu untuk alasan mengapa ini berhasil. Saya menemukan ini hanya dengan sedikit mengutak-atik sendiri, tetapi ini menimbulkan pertanyaan apakah ada pola yang sama yang kuat di bawah penghapusan beberapa karakter. Jadi saya menulis naskah Mathematica pendek untuk mencari ini dengan kekerasan:

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}
  ] &
];

Ini dengan sangat cepat mengungkapkan sebuah pola. Untuk mendapatkan potongan yang sesuai yang bekerja untuk menghilangkan hingga nkarakter, Anda dapat menggunakan (m0x){n}m0di mana madalah n+1dan xadalah baik matau 0. Jadi semua yang berikut ini akan berfungsi untuk menghapus hingga dua karakter:

30030030
30030330
30330030
30330330

Saya yakin itu mungkin untuk membuktikan ini, tetapi saya hanya memverifikasi nhingga 7. Tentu saja, ini hanya berfungsi selama kita dapat mewakili n+1sebagai satu digit, dan digit terbesar semacam itu di Befunge 98 adalah fyang mewakili 15. Karena itulah pendekatan saya terbatas n = 14. Jika seseorang menemukan cara untuk secara andal mengatur delta menjadi lebih besar n+1, kemungkinan akan mungkin untuk meningkatkan urutan quine yang mengeras radiasi ini tanpa batas.

Mari kita lihat kode yang sebenarnya. Pada dasarnya ada dua bagian untuk itu. Pertama kita atur delta (15,0)seperti yang baru saja saya sebutkan:

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx

Dan sisa kode memiliki setiap perintah diulang 15 kali dan mencetak sumber. Jika kami menghapus pengulangan, sepertinya ini:

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

Ini "adalah teknik quining 2D standar: ini memulai mode string, mendorong semua karakter (kecuali dirinya sendiri) ke stack dan mengakhiri mode string lagi setelah membungkus. Ini membantu kami mendapatkan semua poin kode dari babak kedua, tetapi akan gagal untuk memberi kami apa pun yang berguna dari babak pertama, karena sepanjang f00f00...f0bit, itu hanya akan merekam dua karakter (yang dapat berupa fatau 0tergantung pada karakter yang dihapus) ). Tetapi karena bagian itu tidak terdiri dari karakter yang diulang 15 kali, kita harus mencetaknya secara terpisah.

Lebih mudah, di quine yang tidak dimodifikasi, panjang string sebelum "itu -1 (mod 15). Ini menjamin bahwa tidak peduli berapa banyak karakter (hingga 14) yang kami hapus, jumlah karakter yang direkam selalu ada 3 (satu xdan dua dari fdan 0). Ini sebenarnya berlaku untuk urutan radiasi hingga 14.

Kami sekarang mulai dengan mencetak f00f00...f0bagian:

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.

Selanjutnya 3k$hanya membuang itu 0serta tiga karakter yang didorong oleh "dari awal program. Tumpukan sekarang hanya berisi karakter setelah "dan beberapa sampah di bawah dari aslinya f00f00...f0tergantung pada karakter yang dihapus.

Sekarang kita hanya perlu membalikkan bagian atas tumpukan (berisi karakter yang tersisa) dan mencetak masing-masing 15 kali.

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.
;

Dan itu saja. :)


16

JavaScript (ES6), 927 byte, n = 1, skor = 859329

Catatan: jangan gunakan REPL (seperti konsol browser) untuk menjalankan ini.

Ini ditulis sebelum panjang kode adalah faktor, jadi belum ada golf.

Ini sangat sulit, dan pantas mendapat penjelasan menyeluruh. Yang akan saya tulis nanti, setelah saya mengeksplorasi tantangan ini sedikit lagi!

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)//`///`

Catatan: ada baris baru yang tertinggal

Pada dasarnya, baris pertama dibangun dengan hati-hati untuk mengubah nama semua 'salah ejaan' setTimeoutmenjadi fungsi yang valid, sehingga jika karakter dihapus dari salah satu setTimeoutkode tidak akan keluar kesalahan dan versi tanpa cedera dapat berjalan. Itu juga ditulis sehingga jika ada satu karakter dihapus dari baris pertama, tidak akan ada kesalahan dan sisa kode dapat berjalan tidak terpengaruh.

Blok kedua dan ketiga persis sama. Jika satu berjalan sampai selesai, ia menetapkan _variabel sehingga yang lain tahu untuk tidak menduplikasi quine. Jika salah satu dari blok ini keluar, itu tidak mempengaruhi blok yang lain karena itu disebut asynchronous using setTimeout. Kesalahan akan menyebabkan _tidak disetel, sehingga blok lainnya akan berhasil quine. Kode utama dalam string, yang diperiksa panjangnya di setiap blok untuk memastikan bahwa tidak ada pemindahan.

String template pada baris berikutnya dengan beberapa komentar di akhir string template melindungi kode dari kesalahan jika salah satu backticks yang membentuk string template dihapus. Jika backtick akhir dihapus, string template diakhiri oleh backtick dalam komentar. Jika backtick awal dihapus, setTimeout dievaluasi sebagai fungsi yang tidak ditetapkan (no-op) dan kode berjalan seperti biasa, tanpa setTimeout. Backtick akhir dibatalkan oleh komentar lain.


Apa yang kamu katakan? Anda ingin mencobanya? Jangan katakan lagi!

Mode halaman penuh direkomendasikan.

Abaikan kotak input, potongan ini tidak membutuhkan input.

Coba hapus satu karakter dari kode!

Tidak percaya itu Kode normal masih akan berfungsi (tetapi tidak akan ...) Cobalah sesuatu seperti console.log(5)!

catatan: cuplikan harus sedikit dimodifikasi untuk menonaktifkan fitur REPL, jadi saya menghapus beberapa kemampuan keluaran hanya untuk jawaban ini.

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>

Penjelasan yang lebih baik akan datang. Sementara itu jangan ragu untuk melakukan ping ke saya di chat @ jrich dengan komentar / pertanyaan / kritik!


ah oke, whoops: |
Downgoat

4
Gunakan thissebagai ganti window.
Mama Fun Roll

3
+1 untuk memasukkan makna kehidupan dalam kode sumber Anda
Cyoce
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.