BrainF ** k, 396 391 byte
>+>>++++[-<++++++++>]->,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-<+[-<+]->>+[-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>[[->+]->>+<<<+[-<+]->]>+[-<->[[->+]->+>>+<<<<+[-<+]->]<+>->+[->+]->>[->+<]>+>++++++++++>>-<<[-<-[>>]<]<->>>+[-<<<+>>>[-<->]<+++++++++>>>+]++++++++[-<++++<++++++>>]<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]>.>.[-]<[-]<<<[->+<]<<+[-<+]>+]>>[-]<<<-<+[-<+]->>+]
Saya tidak bisa menahan diri dari godaan untuk melakukan hal ini. Paling tidak segitiga itu sisi-runcing ke bawah.
Input masuk sebagai string karakter numerik diikuti oleh satu baris baru.
Output akan berisi ruang trailing tunggal di setiap baris.
Contoh:
$ 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
Penjelasan
Karena agak sulit untuk menjelaskan kode dari perspektif fungsional, kita dapat melihatnya dari perspektif keadaan rekaman pada berbagai waktu. Gagasan inti di sini adalah bahwa segitiga yang kita hasilkan diinisialisasi sebagai array (untuk BF, bagaimanapun) yang padat yang menyusut dalam ukuran sebesar 1 setiap iterasi dari sebuah loop. Pikiran penting lainnya adalah bahwa kita menggunakan 255
untuk menunjukkan "pengganti" yang dapat kita cari di rekaman itu.
Inisialisasi
Ini adalah langkah termudah. Pada awal program, kami menjalankan yang berikut:
>+>>++++[-<++++++++>]->
Ini memaksa kaset ke dalam kondisi berikut (di mana >N<
menunjukkan lokasi pointer pada tape)
[ 0 1 32 255 >0< 0 0 ...]
Angka pertama di sini adalah lokasi "buffer". Kami tidak akan menggunakannya dalam jangka panjang, tetapi berguna untuk membuat operasi lebih sederhana dan untuk menyalin data.
Angka kedua adalah jumlah spasi yang akan kami hasilkan di awal setiap baris, dimulai setelah baris pertama. Baris pertama tidak akan memiliki ruang utama.
Angka ketiga adalah karakter spasi yang kita hasilkan.
Angka keempat adalah placeholder 255, sehingga kita bisa kembali ke posisi ini dengan relatif mudah.
Memasukkan
Dari posisi ini, kita akan membaca semua karakter. Pada akhir langkah ini, kami berharap berada dalam situasi berikut:
[ 0 1 32 255 a b c d e f ... >255< 0 0 ... ]
Di mana a b c d e f ...
menunjukkan string karakter numerik yang dimasukkan (bukan baris baru).
Kami mencapai ini dengan yang berikut:
,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-
Ada beberapa nuansa untuk ini. Pertama-tama, kita akan menampilkan setiap karakter saat kita mendapatkannya, dan kemudian mengeluarkan spasi setelahnya. Kedua, kami tidak ingin menyalin nilai ASCII ke rekaman, kami ingin menyalin angka numerik yang sebenarnya. Ketiga, kami ingin berhenti ketika kami mencapai baris baru dan meninggalkan diri kami di tempat yang baik pada saat itu.
Katakan input kita 6723
. Kemudian, setelah membaca yang pertama 6
, rekaman kami terlihat seperti ini:
[ 0 1 32 255 >54< 0 0 ...]
Kami memeriksa bahwa nilai ini tidak sama dengan 10
(baris ASCII) dengan ,----------[++++++++++
. Kami kemudian mencetak nilai dan melanjutkan dengan mengurangi secara bersamaan 48 dari nilai input dan menambahkan 32 ke nilai di sebelahnya ( >>++++++++[-<++++<------>>]<
), meninggalkan kami di sini:
[ 0 1 32 255 6 >32< 0 ...]
Perhatikan bahwa selama proses ini kita dapat mengasumsikan bahwa semua digit di sebelah kanan input kami adalah 0 - ini berarti bahwa kami tidak dalam bahaya merusak keadaan sebelumnya jika kami menggunakan nilai di sebelah kanan untuk menghitung 6 * 8
dan 4 * 8
.
Sekarang kita menampilkan karakter spasi yang baru saja kita buat, dan menerima input baru, menghapus ruang yang kita hitung di sana. Akhirnya, input akan dihentikan oleh baris baru dan loop akan keluar, meninggalkan tempat di 255
mana baris baru seharusnya ( ,----------]-
). Ini adalah karakter placeholder kedua yang akan kita gunakan untuk menavigasi rekaman itu. Pada titik ini dalam skenario kami, rekaman kami persis seperti ini:
[ 0 1 32 255 6 7 2 3 >255< 0 0 ... ]
Perhitungan
Cara kerjanya adalah daftar digit antara 255
placeholder kami akan menyusut satu per iterasi dari loop. Ketika hanya memiliki 1 digit yang tersisa di dalamnya, kita sudah selesai dan harus segera berhenti (Perhatikan bahwa, pada titik ini, setiap digit dalam daftar itu sudah menjadi keluaran, jadi kita tidak perlu khawatir tentang mengeluarkannya lagi).
Kami sekarang menggunakan trik ini untuk menavigasi dengan yang pertama 255
placeholder: <+[-<+]-
. Ini secara efektif mencari rekaman di sebelah kiri untuk 255
, tidak mengubah apa pun di antaranya. Sekarang kita telah memindahkan pointer, kita dapat memeriksa kondisi keluar kita: jika hanya ada satu digit dalam daftar, maka sel dua spasi di sebelah kanan akan tahan 255
. Dengan demikian, kami memeriksa hal itu dan memulai perulangan:>>+[-<<
Langkah pertama di loop kami adalah untuk menghasilkan baris baru. Jadi kami pindah ke sel pertama (sel buffer kami), tambahkan 10 ke sana dan hasilkan. Langkah selanjutnya adalah menampilkan semua karakter ruang terkemuka. Setelah mengeluarkannya, kami menambah jumlah kami untuk sejumlah ruang utama. Langkah-langkah ini dilakukan dengan yang berikut:
-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>
Yang membuat kita dalam keadaan ini:
[ 0 2 32 255 >6< 7 2 3 255 0 0 0 0 0 0 ]
Langkah kami selanjutnya adalah menyalin nilai pertama dalam daftar, melewati placeholder kedua 255
:
[[->+]->>+<<<+[-<+]->]
Kami pada dasarnya melakukan ini dengan melompat-lompat di antara placeholder kami 255
, meninggalkan kami di sini:
[ 0 2 32 255 >0< 7 2 3 255 0 6 0 0 ... ]
Kami sekarang memulai perulangan, mengulangi seluruh daftar, berhenti ketika kami menekan 255
:>+[-<
Pada titik ini, angka di sebelah kiri langsung kita selalu 0. Jadi, karena kita mencintai mereka, kita memasukkan tempat penampung 255
di sana sehingga kita dapat kembali ke tempat kita dalam daftar. Langkah selanjutnya adalah memindahkan tempat kedua dalam daftar ke lokasi di sekitar tempat kami memindahkan tempat pertama, melewati tempat penampung kedua 255
. Langkah-langkah ini dilakukan dengan yang berikut:
->
[[->+]->+>>+<<<<+[-<+]->]
Meninggalkan kami di sini: [ 0 2 32 255 255 >0< 2 3 255 7 6 7 0 ]
Sekarang, baik 6
dan 7
telah dipindahkan ke lokasi di mana perhitungan dapat terjadi. Kami memerlukan dua salinan 7
karena nomor berikutnya dalam daftar akan memerlukannya juga. The 7
segera setelah 255
melayani tujuan ini, sedangkan yang lain 7
akan dikonsumsi oleh perhitungan.
Pertama, kami menambahkan dua digit:
<+>->+[->+]->>
[->+<]>
Meninggalkan kami di sini:
[ 0 2 32 255 0 255 2 3 255 7 0 >13< 0 ]
Kombinasi langkah-langkah selanjutnya adalah yang paling rumit. Kita perlu melihat apakah angka yang kita tunjuk lebih besar dari 10, dan jika ya, kita kurangi 10
. Pada kenyataannya, apa yang kita lakukan adalah kita mengurangi 10 dari itu dan melihat apakah itu mencapai 0
titik apa pun dalam pengurangan itu. Jika ya, kami tambahkan 10
lagi nanti. Pada akhir ini, kita harus memiliki jumlah modulo 10.
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
>>+[-<<<+>>>[-<->]<+++++++++>>>+]
Pada titik ini, kami telah mencapai tujuan. Kami memiliki jumlah modulo 10! Juga, apakah jumlahnya lebih besar dari 10, kita akan berakhir di sini:
[ 0 2 32 255 0 255 2 3 255 7 0 3 0 0 >0< ]
Tujuan kami berikutnya adalah untuk mengeluarkan jumlah baru ini, mengikutinya dengan spasi, dan menyuntikkannya kembali ke daftar kami. Kami melakukan ini semua dengan teknik sebelumnya kami - 255
melompat dan menambah 48
jumlah kami, jadi saya tidak akan membahasnya secara rinci.
++++++++[-<++++<++++++>>]
<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]
>.>.
Dan kami di sini: [ 0 2 32 255 3 255 2 3 255 7 0 0 51 >32< ]
Perhatikan bagaimana kami menempatkan 255
placeholder tambahan setelah kami yang baru disuntikkan 3
sehingga kami tidak kehilangan tempat dalam daftar. Pada titik ini, kami memiliki output jumlah dan ruangnya, jadi kami perlu membersihkan dan kembali ke keadaan di mana iterasi berikutnya dari loop ini akan berfungsi. Kita perlu membersihkan sel 51
dan kita 32
, memindahkan yang 7
satu ke kanan, dan menavigasi ke placeholder daftar kita sehingga kita bisa memulai dari awal.
[-]<[-]<<<[->+<]<<+[-<+]
Sekarang, kita di sini: [ 0 2 32 255 3 >0< 2 3 255 0 7 0 ... ]
Di mana tepatnya kita ingin berada untuk iterasi berikutnya. Jadi periksa 255 dan lanjutkan! ( >+]
)
Ketika kita diturunkan dari loop, kita akan memiliki daftar baru - terdiri dari jumlah dari daftar sebelumnya. Pertama kali, akan terlihat seperti ini:
[ 0 2 32 255 3 9 5 0 >0< ]
Sekarang kami ingin mengulangi seluruh proses itu di daftar baru kami, jadi kami 255
turunkan ke kiri dan mulai dari awal lagi! Kita perlu melakukan sedikit pembersihan dengan >>[-]<<
, dan kemudian menjatuhkan placeholder kita <-
. Setelah itu, kami berada di tempat yang persis sama dengan yang kami cari, sehingga kami bisa lolos dengan melakukan pemeriksaan yang sama:, <+[-<+]->>+
dan boom! Kami punya loop penuh kami! Semua yang kita butuhkan adalah penutupan braket, dan ketika itu berakhir kita sudah sudah keluaran segalanya, jadi kita sudah selesai: ]
.