BrainF ** k, 396 391 bayt
>+>>++++[-<++++++++>]->,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-<+[-<+]->>+[-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>[[->+]->>+<<<+[-<+]->]>+[-<->[[->+]->+>>+<<<<+[-<+]->]<+>->+[->+]->>[->+<]>+>++++++++++>>-<<[-<-[>>]<]<->>>+[-<<<+>>>[-<->]<+++++++++>>>+]++++++++[-<++++<++++++>>]<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]>.>.[-]<[-]<<<[->+<]<<+[-<+]>+]>>[-]<<<-<+[-<+]->>+]
Bunu yapma isteğine karşı koyamadım. En azından üçgen sivri tarafı aşağı.
Girdi, sayısal bir karakter dizisi olarak gelir ve bunu tek bir satırsonu izler.
Çıktı, her satırda tek bir boşluk bırakacaktır.
Örnekler:
$ bf sd.bf
010
0 1 0
1 1
2
$ bf sd.bf
123456
1 2 3 4 5 6
3 5 7 9 1
8 2 6 0
0 8 6
8 4
2
$ bf sd.bf
9245322
9 2 4 5 3 2 2
1 6 9 8 5 4
7 5 7 3 9
2 2 0 2
4 2 2
6 4
0
açıklama
Kodu işlevsel bir perspektiften açıklamak oldukça zor olduğu için, bunun yerine çeşitli zamanlarda bantın durumu açısından bakabiliriz. Buradaki ana fikir, çıktığımız üçgenin, bir döngünün her yinelemesinde 1 ile küçülen, sıkıca paketlenmiş (BF için, yine de) bir dizi olarak başlatılmış olmasıdır. Bir diğer önemli düşünce, 255
kasette arayabileceğimiz bir "yer tutucu" olduğunu belirtmek için kullandığımızdır .
Başlatma
Bu en kolay adım. Programın başında, aşağıdakileri yürütürüz:
>+>>++++[-<++++++++>]->
Bu, bandı aşağıdaki duruma zorlar (burada >N<
, işaretçinin banttaki konumunu gösterir)
[ 0 1 32 255 >0< 0 0 ...]
Buradaki ilk sayı bir "tampon" konumdur. Uzun vadeli kullanmayacağız, ancak küçük işlemleri basitleştirmek ve verileri kopyalamak için kullanışlıdır.
İkinci sayı, her satırın başında , ilk satırdan sonra başlayacağımız boşluk sayısıdır . İlk satırın başlarında boşluk kalmayacak.
Üçüncü sayı, çıkardığımız boşluk karakteridir.
Dördüncü sayı 255'teki bir yer tutucudur, böylece bu pozisyona nispeten kolayca geri dönebiliriz.
Giriş
Bu pozisyondan itibaren tüm karakterleri okuyacağız. Bu adımın sonunda aşağıdaki durumda olmayı umuyoruz:
[ 0 1 32 255 a b c d e f ... >255< 0 0 ... ]
Nerede a b c d e f ...
giriş oldu sayısal karakter dizesini (değil satır) gösterir.
Bunu aşağıdakilerle başardık:
,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-
Bunun için bazı nüanslar var. Her şeyden önce, her bir karakteri onları aldıkça çıkartacağız ve daha sonra bir boşluk çıkartacağız. İkincisi, ASCII değerini teybe kopyalamak istemiyoruz, gerçek sayısal basamağı kopyalamak istiyoruz. Üçüncüsü, yeni bir hatta çarptığımızda durup, o zaman kendimizi iyi bir yerde bırakmak istiyoruz.
Diyelim ki girişimiz 6723
. Sonra, ilkini okuduktan sonra 6
kasetimiz şöyle görünür:
[ 0 1 32 255 >54< 0 0 ...]
Bu değerin 10
(bir ASCII newline) ile eşit olmadığını kontrol ederiz ,----------[++++++++++
. Ardından değeri yazdırır ve eşzamanlı olarak 48'i giriş değerinden çıkartarak ve yanındaki değere 32 ekleyerek devam ederiz ( >>++++++++[-<++++<------>>]<
), bizi burada bırakır:
[ 0 1 32 255 6 >32< 0 ...]
Bu süreç boyunca girdilerimizin sağındaki tüm rakamların 0 olduğunu kabul edebileceğimize dikkat edin - bu, hesaplama hakkını kullanırsak 6 * 8
ve önceki herhangi bir durumu mahvetme tehlikesi altında olmadığımız anlamına gelir ve 4 * 8
.
Şimdi yeni oluşturduğumuz boşluk karakterini çıkarıyoruz ve orada hesapladığımız alanı silerek yeni bir girdi alıyoruz. Sonunda giriş yeni bir satırla sonlandırılır ve yeni satırın 255
bulunduğu bir nokta bırakarak döngü çıkar ,----------]-
. Bu, kasette gezinmek için kullanacağımız ikinci yer tutucu karakterdir. Senaryomuzun bu noktasında kasetimiz tam olarak şudur:
[ 0 1 32 255 6 7 2 3 >255< 0 0 ... ]
Hesaplama
Bunun işleyiş şekli, 255
yer tutucularımız arasındaki rakamların listesinin her döngüde bir kez küçüleceğidir. İçinde yalnızca 1 basamak kaldıysa, bittik ve derhal durmalıyız (Bu noktada, bu listedeki her basamağın zaten çıktı olduğunu, bu nedenle tekrar basmak için endişelenmek zorunda kalmayacağımıza dikkat edin).
Biz şimdi ilk gitmek için bu hile kullanmak 255
yer tutucu: <+[-<+]-
. Bu etkin bir şekilde soldaki bandı arar ve 255
aradaki hiçbir şeyi değiştirmez. İşaretçiyi hareket ettirdiğimize göre, çıkış koşulumuzu kontrol edebiliriz: listede sadece bir rakam varsa, sağdaki hücre iki boşluk tutacaktır 255
. Böylece, bunu kontrol edip bir döngü başlatırız:>>+[-<<
Döngüdeki ilk adım, yeni bir satır çıktısı almaktır. Böylece ilk hücreye geçiyoruz (tampon hücremiz), ona 10 ekleyip çıktısını alıyoruz. Bir sonraki adım, tüm baştaki boşluk karakterlerinin çıktısını almaktır. Bunları çıkardıktan sonra, öncü alanların sayısı için sayımızı artırırız. Bu adımlar aşağıdakilerle gerçekleştirilir:
-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>
Bizi bu durumda bırakan:
[ 0 2 32 255 >6< 7 2 3 255 0 0 0 0 0 0 ]
Bir sonraki adımımız, ikinci yer tutucuyu geçtikten sonra listedeki ilk değeri kopyalamaktır 255
:
[[->+]->>+<<<+[-<+]->]
Bunu esasen yer tutucularımız arasında ileri geri 255
zıplayarak bizi burada bırakarak yapıyoruz :
[ 0 2 32 255 >0< 7 2 3 255 0 6 0 0 ... ]
Şimdi listenin geri kalanını yineleyerek, vurduğumuzda durduran bir döngü başlatıyoruz 255
:>+[-<
Bu noktada, hemen solumuzdaki hane her zaman 0'dır. Yani, onları sevdiğimiz için, 255
oradaki bir yer tutucuyu açıyoruz , böylece listedeki yerimize dönebiliyoruz. Bir sonraki adım, listedeki ikinci sırayı ikinci sırayı geçen ilk sırayı taşıdığımız yerlere taşımaktır 255
. Bu adımlar aşağıdakilerle gerçekleştirilir:
->
[[->+]->+>>+<<<<+[-<+]->]
Bizi burada bırakmak: [ 0 2 32 255 255 >0< 2 3 255 7 6 7 0 ]
Şimdi, hem 6
ve 7
hesaplama oluşabilir bir konuma taşınmıştır. İki kopyaya ihtiyacımız var, 7
çünkü listedeki bir sonraki sayının da ihtiyacı olacak. Hizmetten 7
hemen sonra 255
bu amaca hizmet ederken, diğeri 7
hesaplama tarafından tüketilecektir.
İlk önce, iki basamağı ekleriz:
<+>->+[->+]->>
[->+<]>
Bizi burada bırakarak:
[ 0 2 32 255 0 255 2 3 255 7 0 >13< 0 ]
Bir sonraki adım kombinasyonu en karmaşık olanıdır. İşaret ettiğimiz sayının 10'dan büyük olup olmadığını görmemiz gerekir, öyleyse çıkarırız 10
. Gerçekte yaptığımız şey, ondan 10 çıkarmamız ve çıkarmanın 0
herhangi bir noktasına çarpıp çarpmadığına bakmaktır. Olursa 10
, sonra ekleriz . Bunun sonunda, modulo 10 toplamına sahip olmalıyız.
Prepare a 10 to the right
+>++++++++++
Leave yet another 255 for a loop condition later
>>-<<
If the number is greater than 10 end up one space to the left
else one space to the right
[-<-[>>]<]<->
Check if the previous 255 is two spaces to the right and if it is
add 10 back to our sum--we've subtracted too much
>>+[-<<<+>>>[-<->]<+++++++++>>>+]
Bu noktada hedefi başardık. Modulo 10 toplamı bizde! Ayrıca, sayının 10'dan büyük olup olmaması da burada sona erer:
[ 0 2 32 255 0 255 2 3 255 7 0 3 0 0 >0< ]
Bir sonraki hedefimiz bu yeni toplamı çıkarmak, bir boşlukla takip etmek ve tekrar listemize enjekte etmek. Bunları daha önce 255
atlama-toplama ve toplamımıza ekleme tekniklerimizle yapıyoruz 48
, bu yüzden onu ayrıntılı olarak anlatmayacağım .
++++++++[-<++++<++++++>>]
<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]
>.>.
Ve biz buradayız: Yeni enjekte edildikten sonra [ 0 2 32 255 3 255 2 3 255 7 0 0 51 >32< ]
ek bir 255
yer tutucuyu nasıl yerleştirdiğimize dikkat edin, 3
böylece listede yerimizi kaybetmeyelim. Bu noktada, toplamımızı ve alanını çıkardık, bu yüzden bu döngünün bir sonraki yinelemesinin işe yarayacağı bir duruma temizlememiz ve geri dönmemiz gerekir. Hücrelerimizi temizlememiz , bir kez sağa doğru hareket etmemiz 51
ve başlayabilmemiz için liste yer tutucuya gitmemiz gerekir.32
7
[-]<[-]<<<[->+<]<<+[-<+]
Şimdi, biz buradayız: [ 0 2 32 255 3 >0< 2 3 255 0 7 0 ... ]
Bu tam olarak bir sonraki yinelememiz için olmak istediğimiz yer. Yani 255'i kontrol et ve devam et! ( >+]
)
Döngüden ayrıldığımızda, önceki listenin toplamından oluşan yepyeni bir listeye sahip olacağız. İlk defa, şuna benzer:
[ 0 2 32 255 3 9 5 0 >0< ]
Şimdi tüm bu işlemi yeni listemizde tekrarlamak istiyoruz, bu yüzden 255
sola doğru aşağıya atlayıp baştan başlıyoruz! Ile biraz temizlik yapmamız >>[-]<<
ve sonra da yer tutucumuzu düşürmemiz gerekiyor <-
. Ondan sonra, biz girdikten sonra tam olarak aynı yerdeyiz, bu yüzden aynı kontrolleri yaparak kurtulabiliriz:, <+[-<+]->>+
ve patlama! Tam döngümüzü aldık! Elimizde ihtiyaç kapanış ayracı olduğunu ve sona erdiğinde bitti yüzden, zaten çıkış herşeyi ettik: ]
.