Mini Flak, 6851113 devir
Program (kelimenin tam anlamıyla)
Çoğu insanın bir Mini Flak kınının yazdırılamayan karakterler ve hatta çok baytlık karakterler kullanmasını beklemeyeceğini biliyorum (kodlamayı alakalı kılar). Bununla birlikte, bu quine ve quine boyutuyla birleştirilen yazdırılamayanlar (UTF-8'in 102646 baytı olarak kodlanan 93919 karakter), programı bu yazıya yerleştirmeyi oldukça zorlaştırır.
Ancak, program çok tekrarlayan ve bu nedenle, gerçekten iyi sıkıştırır . Böylece, tüm program tam anlamıyla Stack Exchange'den temin edilebilmesi için, aşağıda kapatılabilir olanın arkasına gizlenmiş tam sıranın sıkıştırılmış bir versiyonunun xxd
geri dönüşümlü bir gzip
hexdump değeri vardır:
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.......
(Evet, o kadar tekrarlıdır ki, sıkıştırıldıktan sonra tekrarları bile görebilirsiniz ).
"Programınızı TIO'da çalıştırmamanızı kesinlikle tavsiye ederim. TIO yalnızca masaüstü tercümandan daha yavaş değil, aynı zamanda bir dakika içinde zaman aşımına uğrayacak. TIO önce programları zaman aşımına uğradı. " Bunu yapabilirim! Ruby tercümanını kullanarak TIO'yu çalıştırmak yaklaşık 20 saniye sürüyor: Çevrimiçi deneyin!
Program (kolayca okunabilir)
Şimdi bilgisayarların okuyabileceği programın bir sürümünü verdim, hadi insanların okuyabildiği bir sürümünü deneyelim. Çeki oluşturan baytları kod sayfası 437'ye (yüksek bit kümesine sahiplerse) veya Unicode kontrol resimlerine (ASCII kontrol kodlarıysa) dönüştürdüm, boşluk ekledi (önceden var olan herhangi bir boşluk, kontrol resimlerine dönüştürüldü. ), sözdizimi kullanılarak kodlanmış çalışma uzunluğu «string×length»
ve elde edilen bazı veri ağırlıklı bitler:
␠
(((()()()()){}))
{{}
(({})[(()()()())])
(({})(
{{}{}((()[()]))}{}
(((((((({})){}){}{})){}{}){}){}())
{
({}(
(␀␀!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␡┬ü
)[{}()])
}{}
{}({}())
)[{}])
(({})(()()()()){})
}{}{}␊
("Neredeyse 241", 241'inci kopyanın izini kaybetmemesi '
, ancak diğer 240 ile aynı olması nedeniyledir.)
açıklama
Yorumlar hakkında
Açıklanacak ilk şey, Mini-Flak komutları olmayan yazdırılamayan karakterlerin ve diğer önemsiz şeylerin nesi var? Maddelere yorum eklemenin sadece işleri zorlaştırdığını düşünebilirsiniz, ancak bu bir hız yarışmasıdır (büyüklük yarışması değil); Bu arada, Brain-Flak ve dolayısıyla Mini-Flak, yığının içeriğini standart çıktıya döktü; yığının yalnızca içerdiğinden emin olmak zorundaysanızProgramınızın komutlarını oluşturan karakterler, yığını temizlemek için döngü harcamak zorunda kalacaksınız. Olduğu gibi, Brain-Flak çoğu karakteri görmezden geliyor, bu yüzden önemsiz yığın öğelerinin geçerli Brain-Flak komutları olmadığından (bunu Brain-Flak / Mini-Flak polyglot yapıyoruz) ve negatif ya da dışarda olmadığından emin olduğumuz sürece Unicode serisi, onları yığında bırakabilir, çıktısını almalarına izin verebilir ve quine özelliğini korumak için aynı karakteri programımıza koyabiliriz.
Bundan yararlanmamızın özellikle önemli bir yolu var. Quine, uzun bir veri dizgesi kullanılarak çalışır ve temel olarak diziden tüm çıktı, veri dizisini çeşitli yollarla biçimlendirerek üretilir. Programın birden fazla parçaya sahip olmasına rağmen, yalnızca bir veri dizgisi var; bu nedenle programın farklı bölümlerini yazdırmak için aynı veri dizisini kullanabilmemiz gerekir. "Önemsiz veriler önemli değil" numarası, bunu çok basit bir şekilde yapmamıza izin veriyor; ASCII koduna bir değer ekleyerek veya çıkararak programı oluşturan karakterleri veri dizisinde saklarız. Spesifik olarak, programın başlangıcını oluşturan karakterler ASCII kodu + 4, ASCII kodu olarak neredeyse 241 kez tekrarlanan bölümü oluşturan karakterler - 4,veri dizisinin bir karakteri olan her karakter; örneğin, her karakter koduna 4 eklenmiş olarak basarsak, tekrarlanan bölümden bir tekrar alırız, önce ve sonra bazı yorumlar. (Bu yorumlar basitçe programın diğer bölümleridir, karakter kodları değiştirilerek geçerli bir Brain-Flak komutu oluşturmazlar, çünkü yanlış ofset eklenir. Sadece Mini değil, Brain-Flak komutlarından kaçınmalıyız. Flak , sorunun kısıtlı kaynak kısmını ihlal etmemek için, ofset seçimi, bunu sağlamak için tasarlandı.)
Bu yorum numarası nedeniyle, aslında sadece iki farklı şekilde biçimlendirilmiş veri dizisini çıktılayabiliyoruz: a) kaynaktakiyle aynı şekilde kodlanmış, b) her koda eklenmiş bir ofset ile karakter kodları gibi. Bu, eklenen uzunluğu tamamen değecek kılan büyük bir basitleştirmedir.
Program yapısı
Bu program dört bölümden oluşur: intro, data dizesi, data dizesi formatlayıcısı ve outro. Giriş ve çıkış temel olarak veri dizgisini ve formatlayıcısını bir döngüde çalıştırmaktan, her seferinde uygun formatı belirlemek (yani kodlanıp kodlanmama veya dengelenme ve hangi ofsetin kullanılacağı) belirtilmesinden sorumludur. Veri dizgisi sadece veridir ve onu oluşturan karakterlerin veri dizgisinde kelimenin tam anlamıyla belirtilmediği tek sıranın parçasıdır (bunu yapmak, kendisinden daha uzun olması gerektiği için açıkça imkansız olurdu); bu nedenle, kendisinden yenilenmek için özellikle kolay bir şekilde yazılmıştır. Veri dizgisi formatlayıcısı, her biri veri dizisindeki 241'den belirli bir veriyi biçimlendiren 241 neredeyse aynı parçadan oluşur.
Programın her bölümü aşağıdaki gibi veri dizgisi ve biçimlendiricisi aracılığıyla üretilebilir:
- Outro'yu üretmek için, veri dizisini +8 ofset ile biçimlendirin
- Veri dizgisi biçimlendiricisini üretmek için, veri dizgisini +4, 241 kez ofsetle biçimlendirin
- Veri dizesini üretmek için veri dizisini kaynak biçimine kodlayarak biçimlendirin.
- Intro'yu üretmek için, veri dizisini -4 ofsetiyle biçimlendirin
Tek yapmamız gereken programın bu bölümlerinin nasıl çalıştığına bakmak.
Veri dizesi
(«()×35» («()×44» («()×44» («()×44» («()×44» («()×45» …
Mini-Flak kodunda kodlamayı tersine çevirebilmemiz gerektiğinden, veri dizisi için basit bir kodlamaya ihtiyacımız var. Bundan daha basit olamazsın!
Bu sıranın arkasındaki ana fikir (yorum numarasının dışında) temelde büyük miktarda veri depolayabileceğimiz tek bir yer olduğunu belirtmek: program kaynağının çeşitli yuvalama seviyelerinde "komut dönüş değerlerinin toplamı". (Bu genellikle üçüncü yığın olarak bilinir., Mini-Flak'ın ikinci bir yığını olmamasına rağmen, "çalışan yığın", Mini-Flak bağlamında daha iyi bir isim olabilir.) Veri depolama için diğer olasılıklar ana / ilk yığın olacaktır (bu çalışmaz) çünkü çıktımızın gitmesi gereken yer, ve çıktıyı uzaktan verimli bir şekilde depodan geçiremedik) ve tek bir yığın öğesinde bignum olarak kodlandı (bu sorun için uygun değil çünkü ondan veri çıkarmak); Bunları ortadan kaldırdığınızda, çalışma yığını kalan tek konumdur.
Verileri bu yığında "saklamak" için, (…)
daha sonra veri dizgisi biçimlendiricisi içinde dengelenecek dengesiz komutları (bu durumda, komutun ilk yarısı ) kullanırız. Biçimlendirici içindeki bu komutlardan birini kapattığımız her seferinde, veri dizgisinden alınan bir verinin toplamını ve biçimlendirici içindeki bu yerleştirme seviyesindeki tüm komutların dönüş değerlerini itecektir; ikincisinin sıfıra eklenmesini sağlayabiliriz, bu nedenle biçimlendirici yalnızca veri dizesinden alınan tek değerleri görür.
Biçimi çok basittir: n'in(
ardından n kopyaları ()
, n saklamak istediğimiz sayıdır. (Bunun yalnızca negatif olmayan sayıları depolayabileceğimiz anlamına geldiğini ve veri dizisinin son öğesinin pozitif olması gerektiğini unutmayın.)
Veri dizgisi hakkında biraz sezgisel bir nokta hangi sırayla olduğu. Veri dizisinin "başlangıcı", programın başlangıcına, yani en dışa yerleştirme seviyesine yakın olan uçtur; bu kısım en son formatlanır (formatlayıcı en içten dışa doğru iç içe geçme seviyelerine kadar uzanır). Ancak, en son biçimlendirilmesine rağmen, önce basılır , çünkü önce yığına basılan değerler en son Mini-Flak yorumlayıcısı tarafından yazdırılır. Aynı ilke programın tamamı için de geçerlidir; önce outro'yu, sonra veri dizgisi biçimlendiricisini, sonra veri dizesini, sonra introyu, yani programda depolandıkları sıranın tersini biçimlendirmemiz gerekir.
Veri dizesi biçimlendirici
)[({})(
([({})]({}{}))
{
((()[()]))
}{}
{
{
({}(((({}())[()])))[{}()])
}{}
(({}))
((()[()]))
}{}
)]{}
Veri dizgisi formatlayıcısı, her biri veri dizisinin belirli bir karakterini biçimlendiren, her biri özdeş koda (24 bölümden biri marjinal olarak farklı yorumlara sahip) olan 241 bölümden oluşur. (Burada bir döngü kullanamadık: dengesini )
eşleştirerek veri dizisini okumak için dengesiz bir şeye ihtiyacımız var (
ve bunlardan birini bir {…}
döngü içine koyamıyoruz , var olan tek döngü biçimi. Öyleyse biz " "biçimlendiricinin kilidini kaldırın ve veri dizisini biçimlendiricinin 241 kez kaymasıyla çıkarmak için giriş / çıkış alın.
)[({})( … )]{}
Bir biçimlendirici öğesinin en dış kısmı, veri dizesinin bir öğesini okur; veri dizisinin kodlamasının sadeliği, onu okumakta biraz karmaşıklığa yol açar. Eşleştirilmemiş (…)
veri dizgisini kapatıp başlıyoruz , sonra […]
iki değeri negate ( ) iki değeri: sadece veri dizesinden ( ({})
) okuduğumuz veri ( ) ve programın geri kalanının dönüş değeri. Formatlayıcı öğenin geri kalanının dönüş değerini ile(…)
kopyalarız ve kopyasını olumsuzlanan sürüme ekleriz {}
. Sonuç, veri dizisi öğesinin ve biçimlendirici öğesinin dönüş değerinin birlikte veri eksi veri eksi veri dönüş değeri artı dönüş değeri, veya 0; Bu, bir sonraki veri dizgisi elemanının doğru değeri üretmesini sağlamak için gereklidir.
([({})]({}{}))
Formatlayıcı, hangi modda olduğunu bilmek için üst stack öğesini kullanır (0 = veri dizgisi formatında format, herhangi bir değer = çıktısı olan uzaklık). Bununla birlikte, sadece veri dizgisini okumuş olmak üzere, veri yığındaki formatın üstündedir ve onlardan tam tersi olmasını istiyoruz. Bu kod alarak beyin-Flak takas kodunun kısa bir varyantı olan bir yukarıdaki B için b , yukarıda bir + b ; ilave yan etkisi nedeniyle, sadece bu, daha yararlı daha kısa (bu özel durumda), aynı zamanda var olan b için bir zaman sorun değildir b 0 olduğu zaman, ve b 0 değil, bizim için ofset hesaplama yapar.
{
((()[()]))
}{}
{
…
((()[()]))
}{}
Brain-Flak sadece bir kontrol akış yapısına sahiptir, bu yüzden bir while
döngüden başka bir şey istiyorsak biraz çalışacağız. Bu bir "olumsuz" yapıdır; yığının üstüne 0 varsa, kaldırır, aksi halde yığının üstüne 0 yerleştirir. (Çok basit bir şekilde çalışır: yığının üstünde 0 olmadıkça, yığının üstüne 1 - 1 iki kez itin; işiniz bittiğinde, üst yığın öğesini açın.)
Kodu, burada görüldüğü gibi olumsuz bir yapının içine yerleştirmek mümkündür. Kod yalnızca yığının üstü sıfır olmadığında çalışır; bu nedenle, iki negatif yapımız varsa, ilk iki yığın öğesinin her ikisi de sıfır olmadığını varsayarsak , birbirlerini iptal ederler, ancak ilk yapı içindeki herhangi bir kod yalnızca üst yığın öğesi sıfır olmadığında çalışır ve kodun içindeki ikinci yapı sadece üst yığın elemanı sıfır olduğunda çalışacaktır. Başka bir deyişle, bu bir if-then-else ifadesinin karşılığıdır.
Eğer format sıfır değilse, çalışan "o zaman" cümlesinde, aslında yapacak bir şeyimiz yok; İstediğimiz şey data + offset'i ana yığına itmek (programın sonunda çıkarılabilmesi için), ama zaten orada. Bu yüzden sadece veri dizgisi elemanını kaynak biçiminde kodlama ile ilgilenmeliyiz.
{
({}(((({}())[()])))[{}()])
}{}
(({}))
İşte böyle yaparız. {({}( … )[{}()])}{}
Yapı çalışma yığına döngü sayacı hareket etmesini ve orada tutarak çalışır yineleme belirli bir sayıda (bir döngü olarak sahibi olmalıdır, çalışma yığına erişim bağlı olduğu için, herhangi bir başka bir kod güvenli olacak Programın yuvalanma düzeyi). Döngünün gövdesi ((({}())[()]))
, üst yığın elemanının üç kopyasını çıkarır ve en düşük 1 ekler. Diğer bir deyişle, bu 41 üzerinde 40 üzerinde 40 içine yığını üstüne bir 40 dönüşümleri veya ASCII olarak görülebilir (
içine (()
; yapacak defalarca bu çalışan (
içine (()
içine (()()
içine (()()()
böylece vb ve bizim veri dize oluşturmak için basit bir yoludur (a var olduğunu varsayarak (
yığının üstünde zaten).
Döngü bittikten sonra (({}))
, yığının üstünü çoğaltır (böylece şimdi ((()…
yerine şimdi başlar (()…
. Baştaki (
, bir sonraki karakteri biçimlendirmek için veri dizesi biçimlendiricinin bir sonraki kopyası tarafından kullanılır (genişletir) (()(()…
sonra (()()(()…
, ve benzerleri, bu (
, veri dizisinde ayırmayı oluşturur ).
%Wwy$%Y%ywywy$wy$%%%WwyY%$$wy%$$%$%$%$%%wy%ywywy'
Veri dizgisi formatlayıcısında son bir ilgi alanı var. Tamam, bu yüzden çoğunlukla bu sadece 4 kod noktası aşağı doğru kayan outro; ancak, sondaki kesme işareti yerinden görünmeyebilir. '
(kod noktası 39) +
bir Brain-Flak komutu olmayan (kod noktası 43) olur, bu nedenle başka bir amaç için orada olduğunu tahmin etmiş olabilirsiniz.
Bunun nedeni, veri dizgisi formatlayıcısının orada (
zaten bir yığında olmasını beklemektir (herhangi bir yerde hazır bilgi 40 içermez). '
aslında veri dizisi biçimlendiriciyi, sonunu değil, diziyi oluşturmak için tekrarlanan bloğun başlangıcındadır, bu yüzden veri dizesi biçimlendiricisinin karakterleri yığının üzerine itildikten sonra (ve kod veri dizisini yazdırmak üzere hareket etmek üzeredir). kendisi), outro, yığının üstündeki 39'u 40'lık bir değere ayarlar, onu kullanmak için biçimlendiriciye (bu durumda çalışan biçimlendiricinin kendisi değil kaynak gösterimi için) hazırlar. Bu yüzden biçimlendiricinin "neredeyse 241" kopyası var; ilk kopya ilk karakterinde eksik. Ve bu karakter, kesme işareti, programın herhangi bir yerinde Mini-Flak koduna karşılık gelmeyen veri dizisindeki sadece üç karakterden biridir; sadece bir sabit sağlama yöntemi olarak var.
Giriş ve çıkış
(((()()()()){}))
{{}
(({})[(()()()())])
(({})(
{{}{}((()[()]))}{}
(((((((({})){}){}{})){}{}){}){}())
{
({}(
(␀␀!S␠su! … many more comment characters … oq␝qoqoq)
…
)[{}()])
}{}
{}({}())
)[{}])
(({})(()()()()){})
}{}{}␊
Giriş ve çıkış kavramsal olarak programın aynı kısmıdır; Bir ayrım yapmamızın tek nedeni, outro'nun veri dizesinden önce çıktısının alınması ve biçimlendiricisinin (onlardan sonra yazdırılması için) olması ve intro'nun onlardan sonra çıkması gerektiğidir (onlardan önce basılması).
(((()()()()){}))
Yığına 8 adet iki kopya koyarak başlıyoruz. Bu ilk yinelemenin ofsetidir. İkinci kopya, ana döngünün yığının üstündeki yığının üzerinde bir önemsiz eleman olmasını beklediği, ana döngünün var olup olmayacağına karar veren testten geride bıraktığı ve bu yüzden de bir istenmeyen eleman yerleştirmemiz gerektiği içindir. gerçekte istediğimiz öğeyi atmaz; Bir kopya bunun en kısa yoludur (bu nedenle çıktıya en hızlı şekilde).
8 sayısının bundan daha uzun olmayan başka gösterimleri var. Ancak, en hızlı kod için giderken, bu kesinlikle en iyi seçenektir. Birincisi, ()()()()
kullanım, örneğin, (()()){}
her ikisi de 8 karakter uzunluğunda olmasına rağmen, birincisi daha hızlı olduğundan, çünkü daha hızlıdır, çünkü (…)
2 döngü olarak sayılır, ancak ()
sadece tek olarak. Bununla birlikte, bir çevrimi kaydetmek, bir quine için çok daha büyük bir düşünceye kıyasla önemsizdir : (
ve )
daha düşük kod noktalarına sahiptir {
ve }
bu nedenle, onlar için veri parçasını oluşturmak çok daha hızlı olacaktır (ve veri parçası kodda daha az yer kaplar, çok).
{{} … }{}{}
Ana döngü. Bu, yinelemeleri saymaz (bu bir while
döngüdür, bir for
döngü değildir ve ayrılmak için bir test kullanır). Çıktıktan sonra, ilk iki yığın öğesini atıyoruz; üst öğe zararsız bir 0'dır, ancak aşağıdaki öğe "sonraki yinelemede kullanılacak biçim" olacaktır; bu (negatif bir öteleme) negatif bir sayıdır ve Mini -Flak programı çıkar, tercüman onları çıkarmaya çalışırken çöker.
Bu döngü, kesmek için açık bir test kullandığından, bu testin sonucu yığında bırakılacaktır, bu nedenle yaptığımız ilk şey olarak atıyoruz (değeri faydalı değildir).
(({})[(()()()())])
Bu kod 4 ve f - 4'ü bir istif elemanının f üzerine iterken , bu elemanı yerinde bırakır. Bir sonraki yinelemenin formatını önceden hesaplıyoruz (sürekli 4 kullanışlı olmasına rağmen) ve yığını aynı anda programın sonraki birkaç kısmı için doğru sıraya sokuyoruz: f için format olarak kullanacağız: Bu yineleme ve 4 daha önce gereklidir.
(({})( … )[{}])
Bu , çalışma yığında f - 4 kopyasını kaydeder , böylece bir sonraki yineleme için kullanabiliriz. (Değeri f biz doğru yere manevra olabilir bile hala bu noktada mevcut olacak, ancak yığın garip bir yerde olacak ve biz döngüleri ondan 4 çıkarılarak geçirmek olurdu, ve bu çıkarma işlemini yapmak için kodu yazdırma döngüleri. Şimdi depolamak çok daha kolay.)
{{}{}((()[()]))}{}
Ofsetin 4 olup olmadığını görmek için bir test (yani f - 4, 0'dır). Eğer öyleyse, veri dizgisi formatlayıcısını yazdırıyoruz, bu nedenle veri dizgisini ve formatlayıcısını bu ofsette bir kez değil 241 kez çalıştırmamız gerekiyor. Kod oldukça basittir: f - 4 sıfır değilse , f - 4 ile 4'ün kendisini bir çift sıfırla değiştirin; sonra her iki durumda da üst yığın öğesini açın. Şimdi yığında f üzerinde bir sayı var , 4 (bu yinelemeyi 241 kez yazdırmak istiyorsak) veya 0 (sadece bir kez yazdırmak istiyorsak).
(
((((((({})){}){}{})){}{}){}){}
()
)
Bu ilginç bir Brain-Flak / Mini-Flak sabiti çeşididir; Buradaki uzun çizgi 60 sayısını temsil eder. ()
Normal olarak Brain-Flak sabitlerinde yer alan eksiklikten dolayı kafanız karışabilir ; bu normal bir sayı değil, sayıları çoğaltma işlemi olarak yorumlayan bir Kilise sayısıdır. Örneğin, burada görülen 60 numaralı Kilise rakamı, girişinin 60 kopyasını çıkarır ve hepsini bir araya getirir; Brain-Flak'ta birleştirebileceğimiz tek şey normal sayılardır, ayrıca ek olarak, yığının üst kısmına 60 kopya ekleyerek yığının tepesini 60 ile çarptık.
Bir yandan not olarak, Mini-Flak'ta da uygun sayıyı bulmak için, Underload sözdiziminde Church rakamları üreten bir Underload rakam bulucusunu kullanabilirsiniz . Düşük yük sayıları (sıfırdan farklı) "yinelenen üst yığın öğesi" :
ve "ilk iki yığın öğelerini birleştir" işlemlerini kullanır *
; hem bu işlemler sadece tercüme yüzden, Beyin Flak var :
etmek )
, *
için {}
, başa getirebilir {}
ve yeterli eklemek (
dengesine başında (bu ana yığını ve çalışma yığının garip karışımı kullanıyor, ama çalışıyor).
Bu özel kod parçası, 60 x + 1 ifadesini üretmek için, 60 nolu kilisenin sayısını (etkili bir şekilde "60 ile çarpma" pasajı), bir artış ile birlikte kullanır; 241'den veya 0'a sahip olsaydık, sadece 1 değerini alırız, yani bu, ihtiyacımız olan yineleme sayısını doğru olarak hesaplar.
241'in seçimi tesadüfi değil; a) seçilen bir değerdi, yaklaşık olarak programın ne kadar süreceği ve b) 1 bir tur sayısının 4 katından fazla. Bu durumda 60 olan yuvarlak sayılar, Kilise sayıları olarak daha kısa gösterime sahip olma eğilimindedir, çünkü kopyalamak için faktörlerde daha fazla esnekliğe sahipsiniz. Program daha sonra uzunluğu tam olarak 241'e getirmek için dolguyu içerir.
{
({}(
…
)[{}()])
}{}
Bu bir for döngüsü, daha önce görüldüğü gibi, içindeki kodu basitçe ana yığının tepesine eşit miktarda (tükettiği; döngü sayacının kendisi çalışma yığında saklanır, ancak görünürlüğü) çalıştırır. bu, programın yuva seviyesine bağlıdır ve bu nedenle for döngüsünün kendisiyle etkileşime girmesi dışında hiçbir şeyin imkansız olması). Bu aslında veri dizgisini ve formatlayıcısını 1 veya 241 kez çalıştırıyor ve şimdi ana yığından kontrol akışını hesaplama için kullandığımız tüm değerleri attığımız için, bunun için hazır olacak formata sahibiz. kullanılacak formatlayıcı.
(␀␀!S␠su! … many more comment characters … oq␝qoqoq)
Buradaki yorum tamamen ilgisiz değil. Birincisi, birkaç Brain-Flak komutu var; )
ucunda doğal bir program işin çeşitli kesimleri arasındaki geçişler, bu şekilde bir yan etkisi olarak oluşturulur (
Yorum iç koyarak başlangıcında el ile denge (ve açıklama içinde uzunluğuna rağmen ilave edildi bir ()
komut hala bir ()
komuttur, bu nedenle tek yapması gereken, veri dizgisinin ve formatlayıcısının dönüş değerine 1 eklemesidir;
Daha da önemlisi, yorumun başlangıcındaki bu NUL karakterleri açıkça hiçbir şeyden mahsup edilmez (+8 ile -4 arasındaki fark bile (
bir NUL'a dönüşmek için yeterli değildir ). Bunlar, 239 elemanlı veri dizisini 241 elemana kadar getirecek saf dolgulardır (kendileri için kolayca öderler: gerekli yinelemelerin sayısını hesaplarken 1 ile 241 yerine 1 - 239 üretmek için iki bayttan çok daha fazla zaman alırlardı. ). Dolgu karakteri olarak NUL kullanıldı çünkü mümkün olan en düşük kod noktasına sahip (veri dizgisi için kaynak kodunu daha kısa ve böylece daha hızlı çıkış).
{}({}())
Üst yığın öğesini (kullandığımız biçim) bırakın, bir sonrakine 1 ekleyin (çıkacak olan son karakter, yani yazdırılacak ilk karakter, yeni biçimlendirdiğimiz program bölümünün). Artık eski formata ihtiyacımız yok (yeni format, çalışma yığınında saklanıyor); ve artış, çoğu durumda zararsızdır '
ve veri dizgisi biçimlendiricisinin kaynak gösteriminin bir ucunda bir olarak değiştirir (
(bu, veri dizgisini biçimlendirmek için biçimlendiriciyi bir sonraki çalıştırmamız için gerekli olan yığın). Outro veya intro'da bunun gibi bir dönüşüme ihtiyacımız var, çünkü her veri dizesi biçimlendirici öğesini başlangıçta zorlamak (
biraz daha karmaşık hale getirecek (daha (
sonra kapatıp ardından etkisini geri almamız gerektiği gibi ) veBir şekilde fazladan üretmek gerekiyordu (
biz sadece çünkü bir yerlerde neredeyse (bunu zararsız bir karakter yapılacak en iyi şeydir nedenle tüm 241 biçimlendiricinin 241 kopya, '
eksik olan biridir).
(({})(()()()()){})
Son olarak, döngü çıkış testi. Ana yığının şu anki tepesi, bir sonraki yineleme için ihtiyaç duyduğumuz formattır (çalışma yığınından yeni çıkmış). Bu kopyalar ve kopyaya 8 ekler; Elde edilen değer bir sonraki döngüde atılır. Ancak, introyu yeni basarsak, ofset -4'tür, böylece "sonraki yineleme" için ofset -8 olur; -8 + 8, 0 olur, bu yüzden döngü daha sonra yinelemeye devam etmek yerine çıkar.