Haskell , 166 154 byte
(-12 byte terima kasih kepada Laikoni, (pemahaman zip dan daftar alih-alih zipWith dan lambda, cara yang lebih baik untuk menghasilkan baris pertama))
i#n|let k!p=p:(k+1)![m*l*r+(m*(l*r-l-r)+1)*0^mod k(2^(n-i))|(l,m,r)<-zip3(1:p)p$tail p++[1]];x=1<$[2..2^n]=mapM(putStrLn.map("M "!!))$take(2^n)$1!(x++0:x)
Cobalah online!
Penjelasan:
Fungsi ini i#nmenggambar ASCII-Triangle dengan ketinggian 2^nsetelah ilangkah-langkah iterasi.
Pengkodean yang digunakan secara internal mengkodekan posisi kosong 1dan posisi penuh sebagai 0. Oleh karena itu, baris pertama dari segitiga dikodekan sebagai[1,1,1..0..1,1,1] dengan 2^n-1orang-orang di kedua sisi nol. Untuk membangun daftar ini, kita mulai dengan daftar x=1<$[2..2^n], yaitu daftar [2..2^n]dengan semua yang dipetakan 1. Kemudian, kami membangun daftar lengkap sebagaix++0:x
Operator k!p(penjelasan terperinci di bawah), diberi indeks garis kdan yang sesuai pmenghasilkan daftar garis tak terhingga yang mengikuti p. Kami memohonnya dengan 1dan garis awal yang dijelaskan di atas untuk mendapatkan seluruh segitiga, dan kemudian hanya mengambil 2^ngaris pertama . Kemudian, kami cukup mencetak setiap baris, mengganti1 dengan spasi dan 0dengan M(dengan mengakses daftar "M "di lokasi 0atau 1).
Operator k!pdidefinisikan sebagai berikut:
k!p=p:(k+1)![m*l*r+(m*(l*r-l-r)+1)*0^mod k(2^(n-i))|(l,m,r)<-zip3(1:p)p$tail p++[1]]
Pertama, kami menghasilkan tiga versi p: 1:pyang pdengan 1prepended, psendiri dan tail p++[1]yang semuanya kecuali elemen pertama p, dengan yang 1ditambahkan. Kami kemudian zip tiga daftar ini, memberi kami secara efektif semua elemen pdengan tetangga kiri dan kanan mereka, sebagai (l,m,r). Kami menggunakan pemahaman daftar untuk kemudian menghitung nilai yang sesuai di baris baru:
m*l*r+(m*(l*r-l-r)+1)*0^mod k(2^(n-i))
Untuk memahami ungkapan ini, kita perlu menyadari ada dua kasus dasar untuk dipertimbangkan: Entah kita cukup memperluas baris sebelumnya, atau kita berada pada titik di mana titik kosong dalam segitiga dimulai. Dalam kasus pertama, kami memiliki tempat yang penuh jika ada tempat di lingkungan tersebut yang terisi. Ini dapat dihitung sebagaim*l*r ; jika salah satu dari ketiganya adalah nol, maka nilai yang baru adalah nol. Kasus lainnya agak rumit. Di sini, kita pada dasarnya membutuhkan deteksi tepi. Tabel berikut memberikan delapan lingkungan yang memungkinkan dengan nilai yang dihasilkan di baris baru:
000 001 010 011 100 101 110 111
1 1 1 0 1 1 0 1
Rumus sederhana untuk menghasilkan tabel ini adalah 1-m*r*(1-l)-m*l*(1-r)yang disederhanakan m*(2*l*r-l-r)+1. Sekarang kita harus memilih di antara dua kasus ini, di mana kita menggunakan nomor baris k. Jika mod k (2^(n-i)) == 0, kita harus menggunakan case kedua, jika tidak, kita menggunakan case pertama. Karena 0^(mod k(2^n-i))itu istilahnya adalah 0jika kita harus menggunakan kasus pertama dan1 jika kita harus menggunakan case kedua. Hasilnya, kita bisa menggunakan
m*l*r+(m*(l*r-l-r)+1)*0^mod k(2^(n-i))
total - jika kita menggunakan kasus pertama, kita cukup mendapatkan m*l*r, sementara dalam kasus kedua, istilah tambahan ditambahkan, memberikan total keseluruhan m*(2*l*r-l-r)+1.