Adegan salju animasi ASCII

22

Tulis program terpendek untuk mengubah setiap karya seni ASCII menjadi adegan salju animasi yang mulai terbentuk dari salju yang turun ( contoh JavaScript non-golf terakhir diperbarui 2011-12-19).

Spesifikasi input : Program Anda harus menerima kombinasi spasi, tanda bintang, dan baris baru yang berubah-ubah. Input akan berisi paling banyak 23 baris dan 80 karakter per baris. Tidak akan ada baris kosong, namun baris mungkin hanya terdiri dari spasi putih. Satu baris baru yang tertinggal akan dimasukkan dan harus diabaikan.

Keluaran : Keluaran karakter ASCII (spasi, tanda bintang) dan kode kontrol (carriage return, linefeeds, ANSI escape code, dll.) Untuk konsol teks atau emulator terminal sistem operasi Anda sampai pengguna secara manual menghentikan program. Anda dapat menganggap jendela terminal adalah 80x24 karakter jika sistem operasi Anda mengizinkan pengaturan itu.

Aturan :

  • Animasi harus halus dan cepat (lebih disukai 15 fps).
  • Kepadatan salju harus antara 5% dan 15%.
  • Tidak lebih dari satu layar salju dapat menggulir per detik. (Itu berarti tidak lebih dari 24 baris salju baru dapat ditambahkan dalam periode waktu satu detik.)
  • Salju tidak boleh menampilkan pola yang jelas saat memasuki bagian atas layar; itu harus terlihat acak.
  • Program harus mengisi semua baris layar dengan salju secepat mungkin saat dimulai; pengisian awal baris individual layar tidak harus jelas bagi pemirsa.
  • Sudut kiri bawah seni input ASCII harus di sudut kiri bawah layar (Gambar 1 untuk klarifikasi lebih lanjut).
  • Area di dalam atau di bawah seni ASCII tidak boleh diisi secara permanen dengan tanda bintang. Namun, tanda bintang mungkin (tetapi tidak diharuskan) menggulir melalui area ini.
  • Salju tidak boleh menumpuk di bagian bawah layar atau di atas salju yang ada kecuali seperti yang ditunjukkan pada input.
  • Ruang yang lebih rendah harus diisi sebelum yang atas, karena mengisi ruang dalam urutan yang berlawanan membuat animasi pohon Natal terlihat sangat berbeda dari output kode asli saya. (ditambahkan 2011-12-20)

Selamat berlibur!

Gambar 1: area berlabel layar 80x24

---------------------------New snow added on this line--------------------------
                                                                             |
                                                                             |
----------------------------------------------------------+                  |
                                                    ****  |                  |
    Snow MUST fall  Snow MAY fall ---------------->  **** |                  |
    through this    through these          ****      **** |  Snow MUST fall  |
    area.           areas of a              ****     **** |  through this    |
                    completed   \--------->  ****     ****|  area.           |
        ASCII art   scene.    \     ***        ****   ****|                  |
          area         \       \   *******      ****  ****|                  |
                        \       \    ********     ***  ***|  (ALL CAPS terms |
      (located in        \       \-->   *********  ***    |  have standard   |
       lower left         \     *******     ******  MAY   |     RFC 2119     |
       corner of           \    *************  **   fall  |    meanings.)    |
       screen)              \        ***********    here  |                  |
                         *** +--->          ****  ***     |                  |
                         *** | ****************   ***     |                  |
  | Snow MUST fall       *** | ****************   ***     |                  |
  | through this         *** +--->                ***     |                  |
  | area.                *** | ****************   ***     |                  |
--+---------------------+*** +--->                ***+----+------------------+--
  |   Snow MUST NOT     |****************************|      Snow MUST NOT    |
  V  accumulate here.   |****************************|     accumulate here.  V

Contoh input

Banner Golf Kode

 ******   *******  ********  ********     ******    *******  **       ******** 
**    ** **     ** **     ** **          **    **  **     ** **       **       
**       **     ** **     ** **          **        **     ** **       **       
**       **     ** **     ** ******      **   **** **     ** **       ******   
**       **     ** **     ** **          **    **  **     ** **       **       
**    ** **     ** **     ** **          **    **  **     ** **       **       
 ******   *******  ********  ********     ******    *******  ******** **       

Logo Stack Overflow

                                                    ****
                                                     ****
                                           ****      ****
                                            ****     ****
                                             ****     ****
                                    ***        ****   ****
                                   *******      ****  ****
                                     ********     ***  ***
                                        *********  ***
                                *******     ******
                                *************  **
                                     ***********
                         ***                ****  ***
                         ***   ****************   ***
                         ***   ****************   ***
                         ***                      ***
                         ***   ****************   ***
                         ***                      ***
                         ****************************
                         ****************************

Pohon Natal

                                        *
                                       ***                           *
                *                     *****                         ***
               ***                   *******           *           *****
              *****                 *********         ***            *
                *                  ***********       *****
                       *          *************     *******
        *             ***        ***************       *               *
       ***           *****      *****************                     ***
      *****         *******    *******************                   *****
     *******           *      *********************                 *******
    *********                           *                          *********
        *                                                              *
Mohon berdiri
sumber
1
Pohon natal ketiga rusak.
Bobby
Tantangan yang bagus! Saya pikir aturan harus disebutkan untuk referensi yang lebih mudah, dan saya tidak mengerti aturan ketiga dan keenam ...
hallvabo
@hallvabo Saya telah mengklarifikasi kedua aturan tersebut, yang terakhir dengan menambahkan angka berlabel.
PleaseStand
Permintaan klarifikasi: apakah baris baru termasuk dalam panjang garis maksimum 80-char, atau maks 80 karakter plus baris baru? (Saya mengasumsikan yang terakhir, tetapi beberapa pengajuan tampaknya telah mengasumsikan yang pertama.)
Ilmari Karonen
@IlmariKaronen Yang terakhir.
PleaseStand

Jawaban:

5

Perl, 196/239 karakter

chomp(@p=(@f=($"x80)x24,<>)[-24..-1]);{@s=(join("",map rand>.1?$":"*",1..80),@s);if(@s>23){$t=$f[$_],print$_?$/:"\e[H",($f[$_]|=$s[$_]&$p[$_])|($s[$_]&=~$t^$f[$_])for 0..23;select"","","",.1}redo}

Solusi ini berbeda dari contoh JS Anda bahwa polanya diisi dari atas ke bawah dan bukan dari bawah ke atas, tetapi saya berasumsi tidak apa-apa karena Anda tidak mengatakan apa-apa tentang hal itu dalam aturan.

Pengurangan 1-char sepele dapat diperoleh dengan mengganti \edengan karakter ESC literal, tetapi itu membuat kode lebih sulit untuk dibaca dan diedit.


Update: Saya melakukan berhasil datang dengan versi yang mengisi pola dari bawah ke atas, dan tidak memungkinkan salju jatuh melalui bagian diisi dari pola, seperti pada contoh implementasi JS, pada biaya 43 chars ekstra:

chomp(@p=(@q=@f=($"x80)x24,<>)[-24..-1]);{@s=(join("",map rand>.1?$":"*",1..80),@s);if(@s>23){my$q;$q[-1-$_]=($q|=$p[-$_]&~$f[-$_])for@a=0..23;print$_?$/:"\e[H",($f[$_]|=$s[$_]&$p[$_]&~$q[$_])|($s[$_]&=~$f[$_])for@a;select"","","",.1}redo}

Mengganti ($s[$_]&=~$f[$_])dengan hanya $s[$_]akan menghemat 11 karakter dengan membiarkan salju yang jatuh melewati bagian-bagian pola yang terisi (yang cocok dengan spek, tetapi bukan contoh implementasi).


Oke, karena saya tampaknya masih memimpin balapan setelah seminggu, saya kira saya harus menjelaskan bagaimana solusi saya bekerja untuk mendorong lebih banyak kompetisi. (Catatan: Penjelasan ini untuk versi pengisian top-down char-196. Saya dapat mengubahnya untuk menyertakan versi lain nanti.)

Pertama-tama, satu trik besar yang menjadi dasar solusi saya adalah bahwa, karena cara kode karakter ASCII diatur, 1-bit dalam kode ASCII untuk suatu ruang kebetulan merupakan subset dari mereka yang ada dalam kode untuk suatu asterisk.

Dengan demikian, ungkapan berikut ini benar: " " & "*" eq " "dan " " | "*" eq "*". Inilah yang memungkinkan saya menggunakan operasi string bitwise untuk menggabungkan bagian statis dan bergerak dari adegan tanpa harus mengulang karakter individu.

Jadi, dengan itu, mari kita bahas kodenya. Ini versi de-golf-nya:

chomp(@p = (@f = ($" x 80) x 24, <ARGV>)[-24..-1]);
{
    @s = (join('', map((rand > 0.1 ? $" : '*'), 1..80)), @s);
    if (@s > 23) {
        foreach (0 .. 23) {
            $t = $f[$_];
            print( $_ ? $/ : "\e[H" );
            print( ($f[$_] |= $s[$_] & $p[$_]) | ($s[$_] &= ~$t ^ $f[$_]) );
        }
        select '', '', '', 0.1;
    }
    redo;
}

Baris pertama mengatur array @f(untuk "fix") dan @p(untuk "pattern"). @fakan membentuk bagian tetap dari tampilan, dan mulai berisi hanya ruang, sementara @p, yang tidak ditampilkan secara langsung, berisi pola input; saat animasi berlanjut, kami akan menambahkan lebih banyak tanda bintang @fhingga terlihat seperti @p.

Secara khusus, @f = ($" x 80) x 23set @fke 24 string masing-masing 80 spasi. ( $"adalah variabel Perl khusus yang nilai default-nya kebetulan adalah spasi.) Kami kemudian mengambil daftar ini, menambahkan baris input ke dalamnya menggunakan operator readline <>, ambil 24 baris terakhir dari daftar gabungan ini dan tetapkan ke @p: ini adalah cara kompak untuk pad @pdengan garis-garis kosong sehingga muncul pola di mana seharusnya. Akhirnya, kami chompmemasukkan baris input @puntuk menghapus baris baru yang tertinggal agar tidak menyebabkan masalah di lain waktu.

Sekarang, mari kita lihat loop utama. Ternyata itu {...;redo}adalah cara yang lebih singkat untuk menulis infinite loop daripada while(1){...}atau bahkan for(;;){...}, terutama jika kita bisa menghilangkan tanda titik koma sebelumnya redokarena itu segera mengikuti ifblok.

Baris pertama dari loop utama memperkenalkan array @s(untuk "salju", tentu saja), di mana ia menambahkan string 80-karakter acak dari 90% spasi dan tanda bintang 10% pada setiap iterasi. (Untuk menyimpan beberapa karakter, saya tidak pernah benar-benar menghapus garis tambahan dari akhir @sarray, sehingga terus bertambah lama. Akhirnya hal itu akan membuat program terhenti karena array menjadi terlalu panjang untuk masuk dalam memori, tapi itu akan memakan waktu lebih lama daripada kebanyakan orang untuk menonton animasi ini. Menambahkan pop@s;pernyataan sebelum selectakan memperbaikinya dengan biaya tujuh karakter.)

Sisa dari loop utama dibungkus dalam sebuah ifblok, sehingga hanya berjalan setelah @sarray mengandung setidaknya 24 baris. Ini adalah cara sederhana untuk mematuhi spesifikasi, yang mengharuskan seluruh tampilan diisi dengan salju yang turun sejak awal, dan juga menyederhanakan operasi bitwise sedikit.

Selanjutnya muncul satu foreachloop, yang dalam versi golf sebenarnya adalah pernyataan tunggal dengan for 0..23pengubah. Karena konten dari loop tersebut mungkin perlu penjelasan, saya akan membukanya lagi di bawah ini:

foreach (0 .. 23) {
    print $_ ? $/ : "\e[H";     # move cursor top left before first line, else print newline
    $t = $f[$_];                # save the previous fixed snowflakes
    $f[$_] |= $s[$_] & $p[$_];  # snowflakes that hit the pattern become fixed 
    $s[$_] &= ~$t ^ $f[$_];     # ...and are removed from the moving part
    print $f[$_] | $s[$_];      # print both moving and fixed snowflakes ORed together
}

Pertama-tama, $_adalah variabel penghitung loop default di Perl kecuali variabel lain ditentukan. Di sini ia berjalan dari 0 hingga 23, yaitu lebih dari 24 baris dalam bingkai tampilan. $foo[$_]menunjukkan elemen yang diindeks oleh $_dalam array @foo.

Pada baris pertama dari loop de-golf, kami mencetak baris baru (mudah diperoleh dari $/variabel khusus) atau, ketika $_sama dengan 0, string "\e[H", di mana \emenunjukkan karakter ESC. Ini adalah kode kontrol terminal ANSI yang menggerakkan kursor ke sudut kiri atas layar. Secara teknis, kita bisa menghilangkan itu jika kita mengasumsikan ukuran layar tertentu, tetapi saya menyimpannya dalam versi ini karena itu berarti saya tidak perlu mengubah ukuran terminal saya untuk menjalankan animasi.

Di $t = $f[$_]telepon, kami hanya menyimpan nilai saat ini $f[$_]dalam variabel "sementara" (karenanya $t) sebelum berpotensi mengubahnya di baris berikutnya, di mana $s[$_] & $p[$_]memberikan persimpangan (bitwise AND) dari salju yang jatuh dan pola input, dan |=operator OR itu ke jalur output tetap $f[$_].

Pada baris di bawahnya, $t ^ $f[$_]berikan XOR bitwise dari nilai sebelumnya dan saat ini $f[$_], yaitu daftar bit yang kita ubah pada baris sebelumnya, jika ada, dan meniadakan salah satu string input dengan ~meniadakan output. Jadi, yang kita dapatkan adalah bitmask dengan semua bit diatur ke 1 kecuali yang baru saja kita tambahkan $f[$_]pada baris sebelumnya. DAN menggunakan bitmask itu untuk $s[$_]menghapus bit-bit itu darinya; pada dasarnya, ini berarti bahwa ketika kepingan salju yang jatuh mengisi lubang pada pola yang telah ditetapkan, kepingan salju akan dikeluarkan dari susunan salju yang jatuh.

Akhirnya, print $f[$_] | $s[$_](yang dalam versi golf diimplementasikan dengan hanya ORing dua baris sebelumnya bersama-sama) hanya mencetak gabungan (bitwise OR) dari kepingan salju tetap dan bergerak pada baris saat ini.

Satu hal lagi yang perlu dijelaskan adalah di select '', '', '', 0.1bawah lingkaran dalam. Ini hanya cara jelek untuk tidur 0,1 detik dalam Perl; untuk beberapa alasan sejarah yang konyol, sleepperintah Perl standar memiliki resolusi satu detik, dan mengimpor yang lebih baik sleepdari Time::HiResmodul membutuhkan lebih banyak karakter daripada menyalahgunakan 4-argselect .

Ilmari Karonen
sumber
Tampaknya ada sedikit bug: garis ke-24 tidak digunakan, dan garis bawah seni ASCII adalah garis ke-23. Dan itu benar-benar harus mengisi ruang yang lebih rendah sebelum mengisi yang atas, meskipun saya awalnya tidak menentukan itu.
PleaseStand
@ Please Please: Saya mengubah kode untuk menggunakan semua 24 baris (dan kebetulan menyingkirkan say), dengan biaya 2 karakter tambahan. Saya pikir saya tidak bisa mengubah urutan pengisian dengan sangat mudah; implementasi saya agak mendasar terkait dengannya.
Ilmari Karonen
Penjelasan hebat! Saya berharap dapat memutakhirkan entri ini lagi.
Dillon Cower
@PleaseStand: Aku benar-benar tidak berhasil membuat versi mengisi bottom-up, yang sekarang terlihat cukup banyak yang sama seperti contoh JS Anda; ini sedikit lebih panjang dari atas ke bawah, tetapi masih lebih pendek dari entri lainnya sejauh ini.
Ilmari Karonen
3

HTML dan JavaScript, 436 karakter

Tambahkan ke input:

<body onload="for(a=[],b=[],c=document.body.firstChild,e=c[H='innerHTML'].split(N='\n'),f=e.length-1,g=24,h=g-f;f--;)for(X=80;X--;)b[80*(h+f)+X]='*'==e[f][X];for(setInterval(F='for(y=24;y--;)for(x=80;x--;)if(a[w=80*y+x]){d=1;if(b[w])for(d=0,z=y+1;24>z;++z)b[s=80*z+x]&&!a[s]&&(d=1);d&&(a[w]=0,a[w+80]=1)}for(x=80;x--;).1>Math.random(i=0)&&(a[x]=1);for(t=\'\';1920>i;++i)t+=\'* \'[+!a[i]],79==i%80&&(t+=N);c[H]=t',67);g--;)eval(F)"><pre>

Lihat itu berjalan untuk setiap contoh: kode golf , logo Stack Overflow , pohon Natal . Pengguna Internet Explorer perlu menjalankan versi 9 dan mengatur "Mode Dokumen" ke "standar IE9" (menggunakan alat pengembang F12) agar pengiriman ini berfungsi dengan benar.

Mohon berdiri
sumber
1
Semua 3 tampaknya rusak? pasteall.org/pic/show.php?id=66297
CoDEmanX
1

Python, 299 karakter

Ini harus sesuai dengan aturan, dengan asumsi baris baru termasuk dalam batas 80 karakter.

import random,sys,time
C=1920
v=_,x=' *'
a=['']*C
f=lambda n:[random.choice(e*9+x)for e in _*n]
for e in sys.stdin:a+="%-80s"%e
a=a[-C:]
s=f(C)
while 1:
 z=0;t=''
 for e in s:
    t+=v[x<a[z]or e>_]
    if(e>_<a[z])>(x in a[z+80::80]):a[z]='+'
    t+=z%80/79*'\n';z+=1
 print t;s=f(80)+s[:-80];time.sleep(.1)
hallvabo
sumber
Output Anda menjadi kacau jika input memiliki garis yang panjangnya persis 80 karakter (plus baris baru). Saya telah meminta PleaseStand untuk mengklarifikasi apakah itu OK.
Ilmari Karonen
Ini karena saya memasukkan baris baru di akhir setiap garis lebar 80-char. Deskripsi ini ambigu di sini, karena menetapkan bahwa baris baru harus dimasukkan, tetapi juga bahwa orang dapat menganggap terminal adalah 80 karakter lebar (dalam hal ini seseorang dapat menghilangkan baris baru dan tergantung pada pembungkus otomatis).
hallvabo
Saya pikir masalah sebenarnya adalah bahwa Anda tidak menghapus baris baru sebelum melapisi baris input ke 80 karakter, sehingga input 80-karakter-plus-baris pada akhirnya benar-benar menambahkan 81 karakter adan jadi mengacaukan pengindeksan. Saya baru saja mencobanya, dan sepertinya mengganti %edengan %e.rstrip()jalur 6 memperbaiki masalah. (Tentu saja, mungkin ada perbaikan yang lebih pendek; Saya tidak pandai bermain golf Python.)
Ilmari Karonen
Jika Anda ingin mendukung 81 baris char, ubah saja angkanya, dan itu akan baik-baik saja. Selama Anda tetap di bawah 100 karakter per baris, itu tidak akan mengubah jumlah char :-)
hallvabo
Jika saya mengubah kode Anda untuk menggunakan baris 81-char, itu tidak akan berjalan dengan benar pada terminal 80-kolom, sekarang bukan? Anda menghasilkan output 80-kolom dengan baik, hanya saja Anda tidak menerima input 80-kolom dengan benar. Cobalah: buat file input dengan beberapa baris dengan 80 tanda bintang di masing-masing dan lihat apa yang terjadi. Seharusnya tidak sulit: solusi saya menanganinya dengan baik.
Ilmari Karonen
0

Jawa, 625 karakter

import java.io.*;import java.util.*;class s extends TimerTask {int _c,_k;char _i[],_o[];boolean _b[];public s(String f) throws IOException {_i=new char[23*80];_o=new char[80];_b=new boolean [23*80];BufferedReader br = new BufferedReader(new FileReader(f));while (br.read(_i,_c++*80,80)!=-1);} public void run(){_k=--_k<0?_c:_k;for(int i=0;i<80;_b[_k*80+i]=Math.random()>0.9?true:false,i++);for(int m=0;m<_c;m++){for(int n=0;n<80;_o[n]=_b[(_k+m)%_c*80+n]?'*':_i[m*80+n],n++);System.out.println(_o);}}public static void main(String[] a) throws IOException{Timer timer=new Timer();timer.scheduleAtFixedRate(new s(a[0]),0,500);}}

Solusi sederhana di Jawa.

SiZ
sumber
Bagus, tapi saya pikir Anda tidak memenuhi spesifikasi. Secara khusus, Anda menunjukkan seluruh pola dari awal - itu tidak "terbentuk dari salju yang turun" seperti dalam demo sampel. (Memang, ini bisa dijelaskan lebih baik dalam pertanyaan. Anda benar-benar perlu menonton demo untuk memahami apa yang harus dilakukan.) Juga, framerate Anda terlalu lambat, Anda tidak memulai dengan layar yang dipenuhi salju, Anda tampaknya anggaplah format input berbeda dari contoh yang diberikan, dan Anda benar-benar harus mengatur ulang posisi kursor di antara frame (pencetakan "\033[H"harus melakukannya).
Ilmari Karonen