Mini-Flak, 6851113 siklus
Program (secara harfiah)
Saya tahu kebanyakan orang sepertinya tidak mengharapkan Mini-Flak quine menggunakan karakter yang tidak patut dan bahkan karakter multi-byte (membuat pengkodean menjadi relevan). Namun, quine ini, dan unsintables, dikombinasikan dengan ukuran quine (93919 karakter yang dikodekan sebagai 102646 bytes UTF-8), membuatnya cukup sulit untuk menempatkan program ke dalam postingan ini.
Namun, program ini sangat berulang, dan dengan demikian, kompres sangat baik. Agar seluruh program tersedia secara harfiah dari Stack Exchange, ada xxd
hexdump yang dapat dibalik dari gzip
versi lengkap dari quine lengkap yang tersembunyi di belakang yang dapat dilipat di bawah ini:
00000000: 1f8b 0808 bea3 045c 0203 7175 696e 652e .......\..quine.
00000010: 6d69 6e69 666c 616b 00ed d9db 6a13 4118 miniflak....j.A.
00000020: 0060 2f8b f808 0d64 a1c1 1dc8 4202 c973 .`/....d....B..s
00000030: 4829 4524 0409 22e2 5529 a194 1242 1129 H)E$..".U)...B.)
00000040: d2d7 ca93 f9cf 4c4c d45b 9536 e6db 6967 ......LL.[.6..ig
00000050: 770e 3bc9 ffed eca9 edb7 b1a4 9ad2 6a1d w.;...........j.
00000060: bfab 75db c6c6 6c5f 3d4f a5a6 8da6 dcd8 ..u...l_=O......
00000070: 465b d4a5 5a28 4bd9 719d 727b aa79 f9c9 F[..Z(K.q.r{.y..
00000080: 43b6 b9d7 8b17 cd45 7f79 d3f4 fb65 7519 C......E.y...eu.
00000090: 59ac 9a65 bfdf 8f86 e6b2 69a2 bc5c 4675 Y..e......i..\Fu
000000a0: d4e4 bcd9 5637 17b9 7099 9b73 7dd3 fcb2 ....V7..p..s}...
000000b0: 4773 b9bc e9bd b9ba 3eed 9df7 aeaf 229d Gs......>.....".
000000c0: e6ed 5eae 3aef 9d46 21b2 5e4d bd28 942e ..^.:..F!.^M.(..
000000d0: 6917 d71f a6bf 348c 819f 6260 dfd9 77fe i.....4...b`..w.
000000e0: df86 3e84 74e4 e19b b70e 9af0 111c fa0d ..>.t...........
000000f0: d29c 75ab 21e3 71d7 77f6 9d8f f902 6db2 ..u.!.q.w.....m.
00000100: b8e1 0adf e9e0 9009 1f81 f011 18d8 1b33 ...............3
00000110: 72af 762e aac2 4760 6003 1bd8 698c c043 r.v...G``...i..C
00000120: 8879 6bde 9245 207c 04ae 5ce6 2d02 e1bb .yk..E |..\.-...
00000130: 7291 4540 57f8 fe0d 6546 f89b a70b 8da9 r.E@W...eF......
00000140: f5e7 03ff 8b8f 3ad6 a367 d60b f980 679d ......:..g....g.
00000150: d3d6 1c16 f2ff a767 e608 57c8 c27d c697 .......g..W..}..
00000160: 4207 c140 9e47 9d57 2e50 6e8e c215 b270 B..@.G.W.Pn....p
00000170: bdf6 9926 9e47 9d05 ce02 0ff0 5ea7 109a ...&.G......^...
00000180: 8ba6 b5db 880b 970b 9749 2864 47d8 1b92 .........I(dG...
00000190: 39e7 9aec 8f0e 9e93 117a 6773 b710 ae53 9........zgs...S
000001a0: cd01 17ee b30e d9c1 15e6 6186 7a5c dc26 ..........a.z\.&
000001b0: 9750 1d51 610a d594 10ea f3be 4b7a 2c37 .P.Qa.......Kz,7
000001c0: 2f85 7a14 8fc4 a696 304d 4bdf c143 8db3 /.z.....0MK..C..
000001d0: d785 8a96 3085 2acc 274a a358 c635 8d37 ....0.*.'J.X.5.7
000001e0: 5f37 0f25 8ff5 6854 4a1f f6ad 1fc7 dbba _7.%..hTJ.......
000001f0: 51ed 517b 8da2 4b34 8d77 e5b2 ec46 7a18 Q.Q{..K4.w...Fz.
00000200: ffe8 3ade 6fed b2f2 99a3 bae3 c949 9ab5 ..:.o........I..
00000210: ab75 d897 d53c b258 a555 1b07 63d6 a679 .u...<.X.U..c..y
00000220: 4a51 5ead a23a 6a72 9eb6 d569 960b f3dc JQ^..:jr...i....
00000230: 9ceb 53fa 658f 345f ad07 6f6f efce 06ef ..S.e.4_..oo....
00000240: 0677 b791 cef2 f620 57bd 1b9c 4521 b241 .w..... W...E!.A
00000250: 4d83 2894 2eaf a140 8102 050a 1428 50a0 M.(....@.....(P.
00000260: 4081 0205 0a14 2850 a040 8102 050a 1428 @.....(P.@.....(
00000270: 50a0 4081 0205 0a14 2850 a040 8102 050a P.@.....(P.@....
00000280: 1428 50a0 4081 0205 0a14 2850 a040 8102 .(P.@.....(P.@..
00000290: 050a 1428 50a0 4081 0205 0a14 2850 a040 ...(P.@.....(P.@
000002a0: 8102 050a 1428 50a0 4081 0205 0a14 2850 .....(P.@.....(P
000002b0: a040 8102 050a 1428 50a0 4081 0205 0a14 .@.....(P.@.....
000002c0: 2850 a040 8102 050a 1428 50a0 4081 0205 (P.@.....(P.@...
000002d0: 0a14 2850 a040 8102 050a 1428 50a0 4081 ..(P.@.....(P.@.
000002e0: 0205 0a14 2850 a040 8102 050a 1428 50a0 ....(P.@.....(P.
000002f0: 4081 0205 0a14 2850 a040 8102 050a 1428 @.....(P.@.....(
00000300: 50a0 4081 0205 0a14 2850 a040 8102 050a P.@.....(P.@....
00000310: 1428 50a0 4081 0205 0a14 2850 a040 8102 .(P.@.....(P.@..
00000320: 050a 1428 50a0 4081 0205 0a14 2850 a040 ...(P.@.....(P.@
00000330: 8102 050a 1428 50a0 4081 0205 0a14 2850 .....(P.@.....(P
00000340: a040 8102 050a 1428 50a0 4081 0205 0a14 .@.....(P.@.....
00000350: 2850 a040 8102 050a 1428 50a0 4081 0205 (P.@.....(P.@...
00000360: 0a14 2850 a040 8102 050a 1428 50a0 4081 ..(P.@.....(P.@.
00000370: 0205 0a14 2850 a01c 14ca 7012 cbb4 a6e9 ....(P....p.....
00000380: e6db e6b1 e4b1 9e4c 4ae9 d3be f5f3 745b .......LJ.....t[
00000390: 37a9 3d6a af49 7489 a6e9 ae5c 96dd 488f 7.=j.It....\..H.
000003a0: d31f 5da7 fbad 5d56 3e73 5277 7cf5 aa7b ..]...]V>sRw|..{
000003b0: 3fbc df7c e986 c3ba 5ee4 3c6f 74f7 c3e1 ?..|....^.<ot...
000003c0: 301a bb45 d795 9afb fbdc 1495 65d5 6d9b 0..E........e.m.
000003d0: baf7 a5b4 a87d 4a5b d7fd b667 b788 ec27 .....}J[...g...'
000003e0: c5d8 28bc b96a 9eda 7a50 524d 290a a5cb ..(..j..zPRM)...
000003f0: cbef 38cb c3ad f690 0100 ..8.......
(Ya, itu sangat berulang sehingga Anda bahkan dapat melihat pengulangan setelah dikompresi).
Pertanyaannya mengatakan, "Saya juga sangat merekomendasikan untuk tidak menjalankan program Anda di TIO. Bukan hanya TIO lebih lambat dari penerjemah desktop, tetapi juga akan habis dalam waktu sekitar satu menit. Akan sangat mengesankan jika seseorang berhasil mencetak skor yang cukup rendah untuk dijalankan. program mereka sebelum TIO habis. " Saya bisa melakukan itu! Dibutuhkan sekitar 20 detik untuk berjalan di TIO, menggunakan interpreter Ruby: Cobalah online!
Program (dapat dibaca)
Sekarang saya telah memberikan versi program yang dapat dibaca komputer, mari kita coba versi yang dapat dibaca manusia. Saya telah mengkonversi byte yang membentuk quine menjadi codepage 437 (jika mereka memiliki bit set tinggi) atau gambar kontrol Unicode (jika mereka kode kontrol ASCII), menambahkan spasi putih (spasi yang sudah ada sebelumnya dikonversi ke gambar kontrol ), run-length-encoded menggunakan sintaks «string×length»
, dan beberapa bit data-berat elided:
␠
(((()()()()){}))
{{}
(({})[(()()()())])
(({})(
{{}{}((()[()]))}{}
(((((((({})){}){}{})){}{}){}){}())
{
({}(
(␀␀!S␠su! … many more comment characters … oq␝qoqoq)
(«()×35» («()×44» («()×44» («()×44» («()×44» («()×45»
… much more data encoded the same way …
(«()×117»(«()×115»(«()×117»
«000010101011┬â┬ … many more comment characters … ┬â0┬â┬à00␈␈
)[({})(
([({})]({}{}))
{
((()[()]))
}{}
{
{
({}(((({}())[()])))[{}()])
}{}
(({}))
((()[()]))
}{}
)]{}
%Wwy$%Y%ywywy$wy$%%%WwyY%$$wy%$$%$%$%$%%wy%ywywy'×almost 241»
,444454545455┬ç┬ … many more comment characters … -a--┬ü␡┬ü-a␡┬ü
)[{}()])
}{}
{}({}())
)[{}])
(({})(()()()()){})
}{}{}␊
("Hampir 241" adalah karena salinan ke-241 tidak ada yang tertinggal '
, tetapi sebaliknya identik dengan 240 lainnya.)
Penjelasan
Tentang komentar
Hal pertama yang harus dijelaskan adalah, ada apa dengan karakter yang tidak patut dicetak dan sampah lain yang bukan perintah Mini-Flak? Anda mungkin berpikir bahwa menambahkan komentar ke quine hanya membuat segalanya lebih sulit, tetapi ini adalah kompetisi kecepatan (bukan kompetisi ukuran), yang berarti bahwa komentar tidak merusak kecepatan program. Sementara itu, Brain-Flak, dan dengan demikian Mini-Flak, hanya membuang isi stack ke output standar; jika Anda harus memastikan bahwa tumpukan itu hanya berisikarakter yang membentuk perintah program Anda, Anda harus menghabiskan siklus membersihkan tumpukan. Karena itu, Brain-Flak mengabaikan sebagian besar karakter, jadi selama kami memastikan bahwa elemen junk stack tidak valid perintah Brain-Flak (menjadikan ini polyglot Brain-Flak / Mini-Flak), dan tidak negatif atau di luar kisaran Unicode, kita bisa membiarkannya di stack, membiarkannya menjadi output, dan meletakkan karakter yang sama di program kita di tempat yang sama untuk mempertahankan properti quine.
Ada satu cara yang sangat penting untuk memanfaatkan ini. Quine bekerja dengan menggunakan string data yang panjang, dan pada dasarnya semua output dari quine diproduksi dengan memformat string data dengan berbagai cara. Hanya ada satu string data, meskipun faktanya program ini memiliki banyak bagian; jadi kita harus dapat menggunakan string data yang sama untuk mencetak berbagai bagian program. Trik "data sampah tidak penting" memungkinkan kita melakukan ini dengan cara yang sangat sederhana; kami menyimpan karakter yang membentuk program dalam string data dengan menambahkan atau mengurangi nilai ke atau dari kode ASCII mereka. Secara khusus, karakter yang membentuk awal program disimpan sebagai kode ASCII mereka + 4, karakter yang membentuk bagian yang diulang hampir 241 kali sebagai kode ASCII mereka - 4,setiap karakter string data dengan offset; jika, misalnya, kami mencetaknya dengan 4 ditambahkan ke setiap kode karakter, kami mendapatkan satu pengulangan dari bagian yang diulang, dengan beberapa komentar sebelum dan sesudah. (Komentar itu hanyalah bagian lain dari program, dengan kode karakter digeser sehingga mereka tidak membentuk perintah Brain-Flak yang valid, karena offset yang salah telah ditambahkan. Kita harus menghindari perintah Brain-Flak, bukan hanya Mini- Perintah Flak, untuk menghindari pelanggaran bagian sumber terbatas dari pertanyaan; pilihan offset dirancang untuk memastikan hal ini.)
Karena trik komentar ini, kita sebenarnya hanya perlu dapat menampilkan string data yang diformat dalam dua cara berbeda: a) disandikan dengan cara yang sama seperti pada sumber, b) sebagai kode karakter dengan offset tertentu ditambahkan ke setiap kode. Itu penyederhanaan besar yang membuat panjang tambahan benar-benar berharga.
Struktur program
Program ini terdiri dari empat bagian: intro, string data, formatter string data, dan outro. Intro dan outro pada dasarnya bertanggung jawab untuk menjalankan string data dan pemformatnya dalam satu lingkaran, menentukan format yang sesuai setiap waktu (yaitu apakah akan menyandikan atau mengimbangi, dan apa yang digunakan untuk mengimbangi). Data string hanyalah data, dan merupakan satu-satunya bagian dari quine di mana karakter yang menyusunnya tidak ditentukan secara harfiah dalam string data (melakukan hal itu jelas tidak mungkin, karena harus lebih lama dari itu sendiri); dengan demikian ditulis dengan cara yang sangat mudah dibuat kembali dari dirinya sendiri. Pemformat string data terbuat dari 241 bagian yang hampir identik, yang masing-masing memformat datum spesifik dari 241 dalam string data.
Setiap bagian dari program dapat diproduksi melalui data string dan pemformatnya sebagai berikut:
- Untuk menghasilkan outro, format string data dengan offset +8
- Untuk menghasilkan pemformat string data, format string data dengan offset +4, 241 kali
- Untuk menghasilkan string data, format string data melalui penyandian ke dalam format sumber
- Untuk menghasilkan intro, format string data dengan offset -4
Jadi yang harus kita lakukan adalah melihat bagaimana bagian-bagian dari program ini bekerja.
String data
(«()×35» («()×44» («()×44» («()×44» («()×44» («()×45» …
Kita memerlukan pengodean sederhana untuk string data karena kita harus dapat membalikkan pengodean dalam kode Mini-Flak. Anda tidak bisa menjadi lebih sederhana dari ini!
Gagasan kunci di balik quine ini (terlepas dari trik komentar) adalah untuk mencatat bahwa pada dasarnya hanya ada satu tempat kita dapat menyimpan data dalam jumlah besar: "jumlah nilai pengembalian perintah" dalam berbagai tingkat bersarang dari sumber program. (Ini umumnya dikenal sebagai tumpukan ketiga, meskipun Mini-Flak tidak memiliki tumpukan kedua, jadi "tumpukan kerja" kemungkinan adalah nama yang lebih baik dalam konteks Mini-Flak.) Kemungkinan lain untuk menyimpan data adalah tumpukan utama / pertama (yang tidak berfungsi karena di situlah output kita harus pergi, dan kita tidak bisa memindahkan output melewati penyimpanan dengan cara yang jauh efisien), dan dikodekan ke dalam bignum dalam elemen tumpukan tunggal (yang tidak cocok untuk masalah ini karena butuh waktu eksponensial untuk ekstrak data dari itu); ketika Anda menghilangkannya, tumpukan kerja adalah satu-satunya lokasi yang tersisa.
Untuk "menyimpan" data pada tumpukan ini, kami menggunakan perintah yang tidak seimbang (dalam hal ini, bagian pertama dari suatu (…)
perintah), yang akan diseimbangkan dalam pemformat string data nanti. Setiap kali kita menutup salah satu dari perintah ini di dalam formatter, itu akan mendorong jumlah dari datum yang diambil dari string data, dan mengembalikan nilai semua perintah pada level yang bersarang di dalam formatter; kita dapat memastikan bahwa yang terakhir ditambahkan ke nol, sehingga formatter hanya melihat nilai tunggal yang diambil dari string data.
Formatnya sangat sederhana (
:, diikuti oleh n salinan ()
, di mana n adalah nomor yang ingin kita simpan. (Perhatikan bahwa ini berarti kami hanya dapat menyimpan angka non-negatif, dan elemen terakhir dari string data harus positif.)
Satu poin yang sedikit tidak intuitif tentang string data adalah urutan urutannya. "Awal" dari string data adalah akhir yang lebih dekat dengan awal program, yaitu level bersarang terluar; bagian ini diformat terakhir (karena formatter berjalan dari tingkat sarang paling dalam ke terluar). Namun, meskipun diformat terakhir, ia akan dicetak terlebih dahulu, karena nilai yang didorong ke tumpukan pertama dicetak terakhir oleh juru bahasa Mini-Flak. Prinsip yang sama berlaku untuk program secara keseluruhan; kita perlu memformat outro terlebih dahulu, kemudian formatter data string, kemudian data string, kemudian intro, yaitu kebalikan dari urutan penyimpanannya dalam program.
Pemformat string data
)[({})(
([({})]({}{}))
{
((()[()]))
}{}
{
{
({}(((({}())[()])))[{}()])
}{}
(({}))
((()[()]))
}{}
)]{}
Pemformat string data terdiri dari 241 bagian yang masing-masing memiliki kode identik (satu bagian memiliki komentar yang sedikit berbeda), masing-masing memformat satu karakter spesifik dari string data. (Kami tidak dapat menggunakan loop di sini: kami membutuhkan yang tidak seimbang )
untuk membaca string data melalui pencocokan yang tidak seimbang (
, dan kami tidak dapat menempatkan salah satu dari mereka di dalam satu {…}
loop, satu-satunya bentuk loop yang ada. Jadi alih-alih, kita " membuka gulungan formatter, dan cukup dapatkan intro / outro untuk menampilkan string data dengan offset formatter 241 kali.)
)[({})( … )]{}
Bagian terluar dari elemen formatter membaca satu elemen dari string data; kesederhanaan pengkodean string data menyebabkan sedikit kerumitan dalam membacanya. Kita mulai dengan menutup yang tidak cocok (…)
dalam string data, kemudian meniadakan ( […]
) dua nilai: datum yang baru saja kita baca dari string data ( ({})
) dan nilai kembali dari sisa program. Kami menyalin nilai pengembalian sisa elemen formatter dengan (…)
dan menambahkan salinan ke versi yang dinegasikan {}
. Hasil akhirnya adalah bahwa nilai kembali elemen string data dan elemen formatter bersama-sama adalah datum dikurangi datum dikurangi nilai balik ditambah nilai balik, atau 0; ini diperlukan untuk membuat elemen string data berikutnya menghasilkan nilai yang benar.
([({})]({}{}))
Pemformat menggunakan elemen tumpukan atas untuk mengetahui mode yang ada di dalamnya (0 = format dalam pemformatan string data, nilai lain = offset dengan output dengan). Namun, hanya setelah membaca string data, datum berada di atas format pada stack, dan kami ingin mereka sebaliknya. Kode ini adalah varian yang lebih pendek dari kode Swap Brain-Flak, mengambil sebuah atas b ke b di atas sebuah + b ; tidak hanya itu pendek, itu juga (dalam kasus khusus ini) lebih berguna, karena efek samping menambahkan b untuk sebuah tidak bermasalah ketika b adalah 0, dan ketika b tidak 0, itu perhitungan offset untuk kita.
{
((()[()]))
}{}
{
…
((()[()]))
}{}
Brain-Flak hanya memiliki satu struktur aliran kontrol, jadi jika kita menginginkan yang lain selain while
loop, itu akan membutuhkan sedikit kerja. Ini adalah struktur "negasi"; jika ada 0 di atas tumpukan, itu menghilangkannya, jika tidak, tempatkan 0 di atas tumpukan. (Ini bekerja cukup sederhana: selama tidak ada 0 di atas tumpukan, tekan 1 - 1 ke tumpukan dua kali; ketika Anda selesai, pop elemen tumpukan atas.)
Dimungkinkan untuk menempatkan kode di dalam struktur negate, seperti terlihat di sini. Kode hanya akan berjalan jika bagian atas tumpukan bukan nol; jadi jika kita memiliki dua struktur peniadaan, dengan asumsi dua elemen tumpukan teratas tidak sama - sama nol, mereka akan membatalkan satu sama lain, tetapi kode apa pun di dalam struktur pertama akan berjalan hanya jika elemen tumpukan atas adalah nol, dan kode di dalamnya struktur kedua hanya akan berjalan jika elemen tumpukan atas adalah nol. Dengan kata lain, ini setara dengan pernyataan if-then-else.
Di klausa "lalu", yang berjalan jika formatnya bukan nol, sebenarnya kita tidak ada hubungannya; apa yang kita inginkan adalah mendorong data + ofset ke tumpukan utama (sehingga dapat menjadi output di akhir program), tetapi sudah ada di sana. Jadi kita hanya harus berurusan dengan kasus pengkodean elemen string data dalam bentuk sumber.
{
({}(((({}())[()])))[{}()])
}{}
(({}))
Begini cara kami melakukannya. The {({}( … )[{}()])}{}
Struktur harus akrab sebagai loop dengan jumlah tertentu iterasi (yang bekerja dengan memindahkan loop counter untuk tumpukan bekerja dan memegang di sana, itu akan aman dari kode lainnya, karena akses ke tumpukan bekerja terikat tingkat program bersarang). Tubuh loop adalah ((({}())[()]))
, yang membuat tiga salinan elemen tumpukan atas dan menambahkan 1 ke terendah. Dengan kata lain, itu mengubah 40 di atas tumpukan menjadi 40 di atas 40 di atas 41, atau dipandang sebagai ASCII, (
menjadi (()
; menjalankan ini berulang kali akan membuat (
ke (()
dalam (()()
ke dalam (()()()
dan seterusnya, dan dengan demikian adalah cara sederhana untuk menghasilkan data string kami (dengan asumsi bahwa ada (
di atas tumpukan sudah).
Setelah kita selesai dengan loop, (({}))
duplikat bagian atas tumpukan (sehingga sekarang mulai ((()…
daripada (()…
. Pimpinan (
akan digunakan oleh salinan berikutnya dari pemformat string data untuk memformat karakter berikutnya (itu akan memperluasnya menjadi (()(()…
kemudian (()()(()…
, dan seterusnya, jadi ini menghasilkan pemisahan (
dalam string data).
%Wwy$%Y%ywywy$wy$%%%WwyY%$$wy%$$%$%$%$%%wy%ywywy'
Ada sedikit minat terakhir dalam formatter data string. OK, jadi kebanyakan ini hanya outro yang menggeser 4 codepoint ke bawah; Namun, apostrof pada akhirnya mungkin terlihat tidak pada tempatnya. '
(codepoint 39) akan berubah menjadi +
(codepoint 43), yang bukan perintah Brain-Flak, jadi Anda mungkin menduga bahwa itu ada di sana untuk tujuan lain.
Alasan ini ada di sini adalah karena pemformat string data mengharapkan sudah ada (
pada stack (tidak mengandung literal 40 di mana pun). Itu'
sebenarnya di awal blok yang diulang untuk membuat formatter data string, bukan akhir, jadi setelah karakter formatter data string telah didorong ke stack (dan kode akan pindah ke mencetak string data) itu sendiri), outro menyesuaikan 39 di atas tumpukan menjadi 40, siap untuk formatter (formatter berjalan sendiri kali ini, bukan representasi di sumbernya) untuk memanfaatkannya. Itu sebabnya kami memiliki "hampir 241" salinan formatter; salinan pertama tidak ada karakter pertamanya. Dan karakter itu, tanda kutip, adalah satu dari hanya tiga karakter dalam string data yang tidak sesuai dengan kode Mini-Flak di suatu tempat dalam program; itu ada di sana murni sebagai metode menyediakan konstanta.
Intro dan outro
(((()()()()){}))
{{}
(({})[(()()()())])
(({})(
{{}{}((()[()]))}{}
(((((((({})){}){}{})){}{}){}){}())
{
({}(
(␀␀!S␠su! … many more comment characters … oq␝qoqoq)
…
)[{}()])
}{}
{}({}())
)[{}])
(({})(()()()()){})
}{}{}␊
Intro dan outro secara konseptual adalah bagian yang sama dari program; satu-satunya alasan kami menarik perbedaan adalah bahwa outro perlu di-output sebelum data string dan formatter-nya (sehingga ia mencetak setelah mereka), sedangkan intro perlu menjadi output setelah mereka (mencetak sebelum mereka).
(((()()()()){}))
Kami mulai dengan menempatkan dua salinan 8 di tumpukan. Ini adalah offset untuk iterasi pertama. Salinan kedua adalah karena loop utama mengharapkan ada elemen sampah di atas tumpukan di atas offset, tertinggal dari tes yang memutuskan apakah ada loop utama, dan jadi kita perlu meletakkan elemen sampah di sana sehingga itu tidak membuang elemen yang sebenarnya kita inginkan; salinan adalah cara tersest (dengan demikian tercepat untuk menghasilkan) untuk melakukan itu.
Ada representasi lain dari nomor 8 yang tidak lebih dari yang ini. Namun, ketika mencari kode tercepat, ini jelas merupakan pilihan terbaik. Untuk satu hal, menggunakan ()()()()
lebih cepat daripada, katakanlah, (()()){}
karena meskipun keduanya panjangnya 8 karakter, yang pertama adalah siklus yang lebih cepat, karena (…)
dihitung sebagai 2 siklus, tetapi ()
hanya sebagai satu. Menyimpan satu siklus dapat diabaikan dibandingkan dengan pertimbangan yang lebih besar untuk quine , meskipun: (
dan )
memiliki titik temu yang jauh lebih rendah daripada {
dan }
, sehingga menghasilkan fragmen data untuk mereka akan jauh lebih cepat (dan fragmen data akan memakan lebih sedikit ruang dalam kode, terlalu).
{{} … }{}{}
Loop utama. Ini tidak menghitung iterasi (ini adalah while
loop, bukan for
loop, dan menggunakan tes untuk keluar). Setelah keluar, kami membuang dua elemen tumpukan teratas; elemen atas adalah 0 yang tidak berbahaya, tetapi elemen di bawah ini akan menjadi "format untuk digunakan pada iterasi berikutnya", yang (menjadi offset negatif) adalah angka negatif, dan jika ada angka negatif di stack ketika Mini Program -Flak keluar, penerjemah crash mencoba untuk output mereka.
Karena loop ini menggunakan tes eksplisit untuk keluar, hasil tes itu akan ditinggalkan di tumpukan, jadi kami membuangnya sebagai hal pertama yang kami lakukan (nilainya tidak berguna).
(({})[(()()()())])
Kode ini mendorong 4 dan f - 4 di atas elemen tumpukan f , sambil membiarkan elemen itu berada di tempatnya. Kami sedang menghitung format untuk iterasi berikutnya di muka (sementara kami memiliki konstanta 4 berguna), dan secara bersamaan memasukkan tumpukan ke urutan yang benar untuk beberapa bagian berikutnya dari program: kami akan menggunakan f sebagai format untuk iterasi ini, dan 4 diperlukan sebelum itu.
(({})( … )[{}])
Ini menyimpan salinan f - 4 pada stack yang berfungsi, sehingga kita dapat menggunakannya untuk iterasi berikutnya. (Nilai f masih akan ada pada saat itu, tetapi itu akan berada di tempat yang canggung pada tumpukan, dan bahkan jika kita bisa memindahkannya ke tempat yang benar, kita harus menghabiskan siklus dengan mengurangi 4 dari itu, dan siklus mencetak kode untuk melakukan pengurangan itu. Jauh lebih mudah untuk menyimpannya sekarang.)
{{}{}((()[()]))}{}
Tes untuk melihat apakah offsetnya 4 (yaitu f - 4 adalah 0). Jika ya, kami sedang mencetak formatter data string, jadi kita perlu menjalankan string data dan formatter-nya 241 kali daripada hanya sekali pada offset ini. Kode ini cukup sederhana: jika f - 4 bukan nol, ganti f - 4 dan 4 itu sendiri dengan sepasang nol; maka dalam kedua kasus, pop elemen tumpukan atas. Kami sekarang memiliki nomor di atas f pada tumpukan, baik 4 (jika kita ingin mencetak iterasi ini 241 kali) atau 0 (jika kita ingin mencetaknya hanya sekali).
(
((((((({})){}){}{})){}{}){}){}
()
)
Ini adalah semacam konstanta Brain-Flak / Mini-Flak yang menarik; garis panjang di sini mewakili angka 60. Anda mungkin bingung karena kekurangan ()
, yang biasanya ada di semua tempat dalam konstanta Brain-Flak; ini bukan angka biasa, tetapi angka Gereja, yang menafsirkan angka sebagai operasi duplikasi. Misalnya, angka Gereja untuk 60, terlihat di sini, membuat 60 salinan inputnya dan menggabungkan semuanya menjadi satu nilai tunggal; di Brain-Flak, satu-satunya hal yang dapat kita gabungkan adalah angka reguler, dengan tambahan, jadi kita akhirnya menambahkan 60 salinan bagian atas tumpukan dan dengan demikian mengalikan bagian atas tumpukan dengan 60.
Sebagai catatan tambahan, Anda dapat menggunakan pencari angka Underload , yang menghasilkan angka Gereja dalam sintaks Underload, untuk menemukan nomor yang sesuai di Mini-Flak juga. Angka underload (selain nol) menggunakan operasi "duplikat elemen tumpukan atas" :
dan "menggabungkan dua elemen tumpukan atas" *
; kedua operasi tersebut ada di Brain-Flak, jadi Anda hanya menerjemahkan :
ke )
, *
untuk {}
, menambahkan {}
, dan menambahkan cukup (
di awal untuk menyeimbangkan (ini menggunakan campuran aneh dari tumpukan utama dan tumpukan kerja, tetapi berfungsi).
Fragmen kode khusus ini menggunakan angka gereja 60 (secara efektif potongan "kalikan dengan 60"), bersama dengan kenaikan, untuk menghasilkan ekspresi 60 x + 1. Jadi jika kita memiliki 4 dari langkah sebelumnya, ini memberi kita nilai dari 241, atau jika kita memiliki 0, kita hanya mendapatkan nilai 1, yaitu ini dengan benar menghitung jumlah iterasi yang kita butuhkan.
Pilihan 241 bukanlah kebetulan; itu adalah nilai yang dipilih untuk menjadi a) kira-kira berapa lama program akan berakhir dan b) 1 lebih dari 4 kali angka bulat. Angka bulat, 60 dalam hal ini, cenderung memiliki representasi yang lebih pendek sebagai angka Gereja karena Anda memiliki lebih banyak faktor fleksibilitas untuk disalin. Program ini berisi padding kemudian untuk membawa panjang hingga 241 tepat.
{
({}(
…
)[{}()])
}{}
Ini adalah untuk loop, seperti yang terlihat sebelumnya, yang hanya menjalankan kode di dalamnya beberapa kali sama dengan bagian atas tumpukan utama (yang dikonsumsi; penghitung lingkaran itu sendiri disimpan di tumpukan kerja, tetapi visibilitas dari yang terkait dengan level nesting program dan oleh karena itu tidak mungkin untuk apa pun kecuali untuk loop itu sendiri untuk berinteraksi dengannya). Ini benar-benar menjalankan string data dan pemformatnya 1 atau 241 kali, dan seperti yang sekarang kita telah muncul semua nilai yang kami gunakan untuk perhitungan aliran kontrol kami dari tumpukan utama, kami memiliki format untuk digunakan di atasnya, siap untuk formatter untuk digunakan.
(␀␀!S␠su! … many more comment characters … oq␝qoqoq)
Komentar di sini tidak sepenuhnya tanpa minat. Untuk satu hal, ada beberapa perintah Brain-Flak; yang )
pada akhirnya secara alami dihasilkan sebagai efek samping dari cara transisi antara berbagai segmen dari program kerja, sehingga (
di awal secara manual ditambahkan untuk menyeimbangkan itu (dan meskipun panjang komentar dalam, menempatkan komentar dalam sebuah ()
perintah masih berupa ()
perintah, jadi yang dilakukannya hanyalah menambahkan 1 ke nilai balik dari string data dan pemformatnya, sesuatu yang for the loop sepenuhnya abaikan).
Lebih khusus lagi, karakter-karakter NUL di awal komentar jelas tidak diimbangi dengan apa pun (bahkan perbedaan antara +8 dan -4 tidak cukup untuk mengubah a (
menjadi NUL). Itu adalah padding murni untuk menghadirkan string data 239 elemen hingga 241 elemen (yang dengan mudah membayar sendiri: dibutuhkan lebih dari dua byte untuk menghasilkan 1 vs 239, bukan 1 vs 241 saat menghitung jumlah iterasi yang diperlukan ). NUL digunakan sebagai karakter padding karena memiliki codepoint serendah mungkin (membuat kode sumber untuk string data lebih pendek dan dengan demikian lebih cepat untuk output).
{}({}())
Jatuhkan elemen tumpukan atas (format yang kami gunakan), tambahkan 1 ke yang berikutnya (karakter terakhir yang akan ditampilkan, yaitu karakter pertama yang akan dicetak, dari bagian program yang baru saja kami format). Kami tidak memerlukan format lama lagi (format baru disembunyikan di tumpukan kerja); dan peningkatannya tidak berbahaya dalam banyak kasus, dan mengubah '
representasi salah satu sumber formatter data di salah satu ujungnya (
(yang diperlukan pada stack untuk kali berikutnya kita menjalankan formatter, untuk memformat string data itu sendiri). Kita memerlukan transformasi seperti itu di outro atau intro, karena memaksa setiap elemen formatter data string untuk memulai (
akan membuatnya agak lebih kompleks (karena kita harus menutup (
dan kemudian membatalkan efeknya nanti), danentah bagaimana kita perlu membuat tambahan di (
suatu tempat karena kita hanya memiliki hampir 241 salinan formatter, tidak semua 241 (jadi yang terbaik adalah karakter yang tidak berbahaya seperti '
yang hilang).
(({})(()()()()){})
Akhirnya, tes keluar loop. Bagian atas tumpukan utama saat ini adalah format yang kita butuhkan untuk iterasi berikutnya (yang baru saja kembali dari tumpukan kerja). Ini menyalin dan menambahkan 8 ke salinan; nilai yang dihasilkan akan dibuang kali berikutnya di loop. Namun, jika kita baru saja mencetak intro, offsetnya adalah -4 sehingga offset untuk "iterasi berikutnya" akan menjadi -8; -8 + 8 adalah 0, jadi loop akan keluar daripada melanjutkan ke iterasi sesudahnya.