Badai Matius dan Petir

27

Tantangan

Terinspirasi oleh tantangan ini dan Badai Matius yang jahat , kami akan menghasilkan beberapa baut kilat secara dinamis.

n = 15:

   \
   /\
  /  \
 /   /
/\  /\
 /  \ \
/   / /\
   /\ \
  / /  \
 /\ \  /\
  /  \ \
 /\  /  
   \
    \
    /\

Memasukkan

Integer Positif nmenentukan kedalaman putaran petir.

Aturan dan Kendala

  • /dan \harus digunakan
  • Peluang untuk mengarahkan arah petir adalah sebagai berikut:
    • 25% Membagi menjadi 2 jalur
    • 25% Path mencapai jalan buntu
    • 25% Ke Kiri
    • 25% Benar
    • Ada beberapa pengecualian terkait tumpang tindih dan jalan buntu di bawah:
  • Kode tidak boleh deterministik, baut petir baru harus dihasilkan secara acak setiap waktu
  • Baut tidak boleh tumpang tindih: misalnya jika sudah ada baut di sebelah kiri baut saat ini, baut saat ini harus berakhir atau ke kanan, tetapi tidak ke kiri atau terbelah (kemungkinan masih berlaku, dalam hal ini menjadi 50% ujung / 50% benar)
  • Jika tidak ada jalur perpecahan lain yang tersedia, jalur tersebut tidak boleh berakhir: misalnya di awal ketika hanya ada 1 jalur, jalur tersebut tidak boleh berakhir sampai terbelah, juga berlaku ketika ada beberapa jalur tetapi semua kecuali satu jalur mati , (probabilitas menjadi 33% split / 33% kiri / 33% kanan) tujuan Anda adalah mencapai bagian bawah
  • Spasi putih dapat ditambahkan di sebelah kiri (semua yang Anda perlukan hanya tinggi-1)
  • Namun Anda ingin membuat baut terserah Anda, Anda bisa pergi dari bawah ke atas, dari kiri ke kanan, dll. Selama semua aturan di atas terpenuhi

Contoh lain

n = 10

 \
 /
 \
 /\
  /\
 / /
/\ \
 / /\
 \   \
 /

Badai Matthew rupanya menembakkan baut merah ke langit, yang disebut sprite

Tetap aman dan bersenang-senang bermain golf! Silakan bermain golf secara bertanggung jawab hanya ketika Anda berada di tempat yang aman !!

Zukaberg
sumber
7
Stay safe and have fun golfing!Mungkin juga menentukan bahwa jika EAS menyerang, tinggalkan segalanya dan ikuti perintah! Kode golf bukan prioritas Anda dalam situasi seperti itu.
Erik the Outgolfer
17
@EriktheGolfer, kamu bukan pegolf sejati.
Biru
4
Saya tidak percaya bahwa "Jalur paling tengah seharusnya menjadi jalan yang mencapai" adalah konsisten dengan sisa deskripsi generasi acak. Misalnya, secara acak memungkinkan baut asli untuk terbelah dua dan kemudian untuk dua baut tengah berakhir; bagaimana kemungkinan ini bisa ditimpa sambil tetap mempertahankan probabilitas yang ditunjukkan?
Greg Martin
Juga, apa yang terjadi jika (misalnya) dua langkah pertama sama-sama terbagi? Kemudian dua baut tengah saling bersentuhan, yang tampaknya bermasalah tetapi juga tidak dikesampingkan oleh kasus-kasus khusus.
Greg Martin
@GregMartin Poin bagus di bagian paling tengah, awalnya saya berharap untuk menghasilkan baut yang seimbang, tapi sekarang saya berpikir tentang hal itu bahkan tanpa kendala sekitar 50% dari waktu itu harus berakhir di suatu tempat di tengah, kedalaman 15 hanya akan memiliki peluang 1-2% di mana sebagian besar jalur kanan atau kiri mendarat. Saya akan menghapus aturan itu. Dan untuk bagian 2 langkah pemisahan, satu-satunya hal yang harus dicegah adalah bahwa tidak ada 2 jalur yang harus diikuti 2 jalur: \/pada titik mana pun.
Zukaberg

Jawaban:

6

Perl, 92 90 89 84 byte

Termasuk +1 untuk -n

Beri ketinggian pada STDIN:

perl -M5.010 bolt.pl <<< 15

bolt.pl:

#!/usr/bin/perl -n
map{$_=$;until$;=$_,s/.6|3.?/53|16*rand/eg,/3|6/>/36/;say y|3615|\\/ |r}(1x$_.6)x$_

Penjelasan

Jika Anda memanggil offset dari titik awal 0 (titik ada di sudut kotak karakter), maka pada baris berikutnya Anda dapat pergi ke kiri atau kanan (atau tidak) dan dapat berakhir dengan titik pada offset -1,1. Baris berikutnya memberikan -2,0,2kemungkinan offset dll. Mereka semua berbeda 2. Jika Anda kemudian memanggil karakter ke kiri bawah titik genap dan karakter ke kanan bawah ganjil, Anda dapat memperluas untuk menetapkan genap atau ganjil untuk setiap posisi karakter pada baris sedemikian rupa sehingga genap dan ganjil bergantian (sebenarnya seluruh bidang ubin dalam pola kotak-kotak). Posisi genap dapat memiliki /atau , posisi aneh dapat memiliki \atau .

Karakter tepat sebelum /berada dalam posisi yang aneh sehingga bisa baik \atau , namun \/dilarang sehingga hanya dimungkinkan. Demikian pula karakter setelah a \ harus menjadi (dengan asumsi baris diisi dengan cukup ruang ke kiri dan kanan sehingga batas-batas baris tidak ada masalah). Jadi petir berlanjut pada baris berikutnya selalu tepat di bawah a \atau di bawah a /. Dalam kedua kasus titik yang lebih rendah di tengah dan baris berikutnya dapat memiliki salah satu dari , /, \atau /\langsung di bawah bagian atas 2 karakter. Jadi untuk menghasilkan baris berikutnya saya cukup mengganti saja \atau/oleh salah satu dari 4 ekspansi ini dengan probabilitas yang sama (Anda juga bisa secara independen mengganti karakter pertama dengan atau /dan karakter kedua dengan atau \). Dalam perl Anda bisa melakukan ini dengan sesuatu seperti:

s#\\ | /#("  "," \\","/ ","/\\")[rand 4]#eg

Jika baris yang dihasilkan namun mengandung \/(dilarang bergabung) atau tidak ada /atau \sama sekali (baut mati dan tidak mencapai bagian bawah) hasilnya tidak valid. Dalam hal ini saya membuang seluruh baris dan coba lagi. Kelanjutan yang valid selalu ada dan jika Anda mencoba cukup sering akan ditemukan (mis. Semuanya mati kecuali untuk 1 aliran). Ini adalah distribusi probabilitas yang sedikit berbeda dari algoritma anti-overlap yang disarankan, tapi saya pikir ini sebenarnya lebih baik karena tidak memiliki bias arah. Validitas dapat diuji menggunakan cara golf

m#\\|/#>m#\\/#

Masalahnya di sini adalah bahwa substitusi acak begitu looooong dan semua \lolos ini juga memakan byte. Jadi saya memutuskan untuk membuat baris saya menggunakan string angka dan mengganti digit yang sesuai , /dan \sebelum mencetak. Penggantian acak dasar adalah

53|16*rand

yang memberikan salah satu 53, 55, 61atau 63dengan probabilitas yang sama. Saya kemudian menafsirkan 5dan 1sebagai , 3sebagai \dan 6sebagai /. Itu menjelaskan cetak baris:

say y|3615|\\/ |r

Dalam kompetisi golf yang serius sekarang saya akan mulai mengeksplorasi formula sulap alternatif secara sistematis, tetapi ini seharusnya cukup bagus (dalam 3 byte optimal)

Sisa komponen program:

1x$_.6

Ini menginisialisasi $_(lihat peta berikutnya) ke ruang ketinggian diikuti oleh a /. Ini adalah baris tak terlihat di atas yang pertama dicetak dan memastikan bidang cukup lebar sehingga baut tidak pernah kehabisan ruang di sebelah kiri

map{ ... ; say ...}(1x$_.6)x$_

Saya akan memproses kali ini tinggi string awal yang sama mencetak baris baru setiap kali

$_=$;until$;=$_,...

Simpan baris saat ini di $;. Jika penggantian ternyata pengembalian tidak valid $_dari$;

s/.6|3.?/53|16*rand/eg

Lakukan penggantian yang sebenarnya. Saya tidak perlu memeriksa apa yang sebelum /atau sesudah \karena itu harus spasi. Ini nyaman karena ruang dapat diwakili oleh salah satu 1atau 5. Karena saya hanya mengisi string ke kiri setelah spasi \masih bisa absen, jadi buat karakter itu opsional

/3|6/>/36/

Periksa apakah baris baru itu valid

Ton Hospel
sumber
+1 Rapi! Anda harus memasukkan tester online ini perl -M5.010 main.pl <<< 25, saya sudah mendapatkan beberapa output bagus!
Zukaberg
Pikiran menjelaskan sedikit cara kerjanya? Saya terlalu senang menghasilkan mereka haha, jujur ​​saya tidak mengantisipasi hasil yang baik.
Zukaberg
Sayangnya, Anda perlu menambahkan 3 byte untuk-n , karena ruang dan garis hitung juga. Aturan yang sama adalah untuk argumen baris perintah. Lihat "Doa Khusus", poin-kedua: Saya menghitung itu sebagai perbedaan dalam jumlah karakter dengan permintaan setara terpendek tanpa mereka.
Erik the Outgolfer
1
@EriktheGolfer Tidak, +1 OK karena program ini berfungsi dengan baik dari menggunakan commandline -nEyang hanya 1 karakter lebih dari -E(lihat artikel yang Anda referensi. Ini juga menghilangkan kebutuhan untuk -M5.010) Saya selalu menyajikan kode saya sebagai file karena lebih nyaman, tapi saya selalu menghitung opsi seperti ini: Jika bisa dijalankan dari commandline saya tidak menghitung spasi dan tanda hubung. Jika harus berada dalam sebuah file (misalnya karena menggunakan do$0) saya lakukan menghitung ruang dan dasbor
Ton Hospel
@TonHospel Oh, saya tidak tahu Anda pernah menggunakan -E. Jika demikian, Anda baik-baik saja.
Erik the Outgolfer
0

JavaScript (ES6), 154 byte

f=(n,r=[],s=" ".repeat(n)+"/",t=s.replace(/ \/|\\ |\\$/g,_=>"  /  \\/\\".substr(Math.random()*8&6,2)))=>n?/^ +$|\\\//.test(t)?f(n,r,s):f(n-1,[...r,t],t):r
<input type="number" min=1 oninput=o.textContent=f(this.value).join`\n`><pre id=o>

Saya berjuang dengan implementasinya sampai saya melihat jawaban @ TonHospel, yang pada saat itu baru saja berubah menjadi port. Output sampel:

         /\
        / /\
       /\   \
        /\   \
         /\  /
          / /\
         / / /\
            / /\
            \   \
             \
Neil
sumber