Buat Salju!

18

Tugas Anda: menghasilkan kepingan salju Koch ke kedalaman n. Anda tidak perlu membuat kepingan salju Koch lengkap, hanya satu sisi dari segitiga awal. Wikipedia di Koch flakes: https://en.wikipedia.org/wiki/Koch_snowflake .

Aturan:

  • Program harus menghasilkan satu sisi kepingan salju Koch hingga ke kedalaman n.
  • Keluaran harus ASCII.
  • Anda dapat menghasilkan seluruh kepingan salju; ini tidak wajib.
  • Aturan standar untuk input / output dan celah dan hal-hal berlaku.
  • Spasi tidak masalah, selama semua karakter berada di tempat yang tepat relatif satu sama lain.
  • Kode terpendek menang!

Kasus uji:

n = 0:

__

n = 1:

__/\__

n = 2:

      __/\__
      \    /
__/\__/    \__/\__

n = 3:

                        __/\__
                        \    /
                  __/\__/    \__/\__
                  \                /
                  /_              _\
                    \            /
      __/\__      __/            \__      __/\__
      \    /      \                /      \    /
__/\__/    \__/\__/                \__/\__/    \__/\__

Saya harap ini masuk akal. Perhatikan bahwa dalam setiap kasus uji, fraktal dapat dibagi menjadi tiga bagian dengan panjang yang sama. Perhatikan juga bahwa lebar setiap kepingan salju tiga kali lebih lebar dari kepingan salju generasi sebelumnya.

Kamerad SparklePony
sumber
FYI, disepakati bahwa ini bukan korban penipuan dari ini .
Kamerad SparklePony
Saya tidak berpikir Anda telah mendefinisikan dengan tepat apa representasi ASCII yang tepat dari kurva nth Koch.
orlp
Saya tidak yakin proporsinya masuk akal. Non-dupe digunakan __/\__dengan dua garis bawah, yang membuat setiap iterasi secara konsisten 3 kali lebih besar dari yang sebelumnya. Menggunakan hanya satu garis bawah nampaknya memberikan kontradiksi yang mulai menjadi sangat canggung dalam n = 3. Misalnya bagian luar memiliki lebar 12 sedangkan bagian tengah hanya memiliki lebar 10, sebagai akibat dari /_dan _\ yang terlalu sempit. Dan bahkan sebelum itu Anda telah _memperluas dua kali lebar /dan \ .
Ørjan Johansen
Saya pikir /_dan _\ adalah satu-satunya bagian yang benar-benar fatal - garis bawah harus dilalui, karena mereka harus berada pada posisi yang sama dengan /dan \ . Setelah selesai, hal-hal dapat diperluas 3 kali dari n = 1 dan seterusnya (tetapi n = 0 tidak cocok.)
Ørjan Johansen
Sayangnya, tidak, bagian tengah masih memiliki lebar yang tidak cocok dengan bagian luarnya, terbukti dengan n = 3 memiliki lebar 52 daripada 54 = 2 * 3 ^ 3. Coba salah satunya . Saya menyertakan versi terbalik dengan bagian-bagian hanya muncul dari n = 4 atau n = 5 - mereka berbeda dari yang ke atas di mana garis bawah dijatuhkan.
Ørjan Johansen

Jawaban:

10

Haskell , 308 300 299 byte

Suntingan:

  • -4 byte: Mengubah zipWith(+)ke zipWith(-)dan menyesuaikan pengkodean dan offset menyingkirkan setiap tanda negasi.
  • -1 byte: Selanjutnya, mengubah pengkodean memungkinkan beberapa nama variabel #untuk dihapus dengan menggunakan r=reversealih-alih pencocokan pola langsung.
  • -2 byte: Menggunakan operator alih-alih huruf untuk zipWith(-).
  • -1 byte: Mendefinisikan o=[0,0]untuk mempersingkat konstanta daftar.
  • -1 byte: Menggabungkan dua cabang ?.
import Data.List
k n=0?sort(o#(f=<<scanl1(+)(iterate(>>=(:[1,4,1]))[6]!!n)))
x?l@(([_,w],c):r)|x>w='\n':0?l|0<1=([2..w-x]>>" ")++[c|w>x]++w?r
_?_=""
w#((c,l):m)=(l&w,c):r l&(l&w)#m
_#_=[]
f x=zip"_/\\_/\\"([id,r]<*>[0:1:o,[0,1,0,1],o++[1,1]])!!mod x 6<$[1,3..gcd 3x]
(&)=zipWith(-)
r=reverse
o=[0,0]

Cobalah online! (Sedihnya, apa pun yang lebih besar dari n = 3 dibungkus dengan mengerikan dan tidak dapat dibaca, tetapi Anda dapat menyalinnya ke program lain untuk melihatnya.)

Variasi

  • Jika Anda berubah [6]menjadi [6,4,4], Anda mendapatkan kepingan salju keseluruhan. Cobalah online!
  • Jika Anda menghapus ,3..gcd 3x, Anda mendapatkan kurva dalam gaya yang awalnya diberikan pertanyaan ini. Cobalah online!
  • Atau keduanya sekaligus: Cobalah secara online!

Bagaimana itu bekerja

  • kadalah fungsi utama, dibutuhkan Int ndan mengembalikan a String.
  • iterate(>>=(:[1,4,1]))[6]menghasilkan daftar tak terbatas yang mengandung, untuk setiap n, belokan antara garis berurutan dalam iterasi kurva, gaya grafis turtle, sebagai angka yang secara nominal antara 0dan 5. Setiap iterasi hanya yang sebelumnya dengan belokan 1,4,1disisipkan. Satu-satunya alasan sublists memulai dengan 6alih - alih 0adalah untuk membuat gcdtrik dalam fbekerja dengan menghindari f 0.
  • scanl1(+)mengubah belokan menjadi arah "absolut", hingga modulo 6. A 0berarti ke kanan, maka setiap angka yang lebih tinggi adalah 60 derajat berlawanan arah jarum jam dari sebelumnya. (Yah, itu akan menjadi 60 derajat jika ini adalah gambar yang tepat daripada ASCII.)
  • f mengubah arah absolut menjadi daftar (karakter, penyandian offset) pasangan yang menyandikan karakter mana yang akan ditambahkan ke kurva (untuk arah horizontal, ia menghasilkan dua pasangan, jika tidak satu), dan bagaimana posisi relatif berubah.
  • The #iterates Operator melalui daftar sebelumnya (karakter, offset encoding) pasang, menghasilkan sebenarnya (koordinat, karakter) pasang.
  • Prinsip penyandian:
    • Karakter dari _/\nominal mewakili garis yang ditarik dari sudut mulai melalui sel persegi panjang ke sudut akhir yang berbeda.
    • Koordinat sel berbentuk [y,x], atas ke bawah, kiri ke kanan, sehingga mereka mengurutkan dalam urutan yang ingin kita cetak. Kolom berbasis 1. Daftar digunakan sebagai pengganti tupel untuk aritmatika vektor yang lebih pendek (&)=zipWith(-).
    • Sebuah sudut dilambangkan dengan koordinat yang sama [y,x]dengan sel di kiri atas. Ini memastikan bahwa semua offset dari sudut ke sel-sel di sekitarnya tidak negatif, menghindari konstanta negatif.
    • Namun, koordinat sudut dilewatkan secara dinegasi untuk memungkinkan semua operasi vektor menjadi pengurangan, bukan penambahan, yang menghindari semua tanda eksplisit lainnya.
    • Daftar penyandian offset adalah [y1,x1,x2,y2]tempat [y1,x1]offset koordinat dari sudut awal ke sel karakter dan [y2,x2]merupakan offset dari sudut ujung ke sel karakter. Ini berarti:
      • Daftar pengodean untuk arah 3.. 5hanyalah kebalikan dari daftar untuk 0.. 2, yang memungkinkan mereka dihasilkan [id,r]<*>.
      • Semua aritmatika vektor yang diperlukan dapat dilakukan dengan menggunakan (&)=zipWith(-)daftar pengodean atau kebalikannya.
  • Setelah mengurutkan daftar pasangan (koordinat, karakter), mereka diteruskan ke ?, yang menghasilkan final Stringdari mereka.
    • In x?l@(([_,w],c):r) xadalah koordinat x dari karakter sebelumnya yang ditunjukkan pada baris ini, atau 0jika pada awal baris; ladalah seluruh daftar saat ini, wadalah koordinat x dari karakter berikutnya yang akan ditambahkan, cadalah karakter, dan rmerupakan daftar yang tersisa.
    • Pada tahap ini, koordinat y tidak lagi diperlukan. Karena setiap baris berisi karakter, dan karakter pertama setiap baris baik di sebelah kiri akhir yang sebelumnya, awal baris baru terdeteksi dengan memeriksa apakah koordinat x telah menurun.
    • Underscore memiliki nilai ASCII lebih besar dari \dan /, sehingga akan diurutkan terakhir jika tumpang tindih dengan karakter lain di posisi yang sama. Jadi garis bawah yang berlebihan terdeteksi dengan memeriksa bahwa koordinat x telah diulang.
Ørjan Johansen
sumber
Bagus! Saya akan menerima ini jika tidak ada kegiatan lagi untuk pertanyaan ini hari ini.
Kamerad SparklePony