ASCIIアニメーション雪景色


22

ASCIIアートのあらゆる部分を、雪が降ってから形成され始めるアニメーションの雪景色に変える最短のプログラムを作成します(ゴルフ以外のJavaScriptの例は、 2011-12-19に最終更新されました)。

入力仕様:プログラムは、スペース、アスタリスク、および改行の任意の組み合わせを受け入れる必要があります。入力には、最大23行と1行あたり80文字が含まれます。空行はありませんが、行は空白のみで構成されます。単一の末尾の改行が含まれるため、無視する必要があります。

出力:ユーザーが手動でプログラムを終了するまで、オペレーティングシステムのテキストコンソールまたはターミナルエミュレーターのASCII文字(スペース、アスタリスク)および制御コード(キャリッジリターン、ラインフィード、ANSIエスケープコードなど)を出力します。オペレーティングシステムがその設定を許可している場合、ターミナルウィンドウは80x24文字であると想定できます。

ルール

  • アニメーションは滑らかで高速でなければなりません(15 fpsを推奨)。
  • 雪の密度は5〜15%でなければなりません。
  • 1秒間にスクロールできる雪の画面は1つだけです。(つまり、1秒間に24行を超える新しい雪を追加できないことを意味します。)
  • 雪は、画面の上部に入るときに明らかなパターンを表示してはなりません。ランダムに見える必要があります。
  • プログラムは、起動時に画面のすべての行をできるだけ早く雪で満たす必要があります。画面の個々の行の最初の塗りつぶしは、視聴者に明白であってはなりません。
  • 入力ASCIIアートの左下隅は、画面の左下隅になければなりません(さらに明確にするために、図1)。
  • ASCIIアートの内側または下の領域は、恒久的にアスタリスクで埋めてはいけません。ただし、アスタリスクはこの領域をスクロールできます(必須ではありません)。
  • 雪は、入力に示されている場合を除き、画面の下部または既存の雪の上に堆積してはなりません。
  • スペースを逆順にすると、クリスマスツリーのアニメーションが元のコードの出力と非常に異なって見えるため、下のスペースは上のスペースよりも先に埋める必要があります。(2011-12-20を追加)

楽しい休日を!

図1: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

入力例

コードゴルフバナー

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

スタックオーバーフローロゴ

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

クリスマスツリー

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

1
3番目のクリスマスツリーが壊れています。
ボビー

ナイスチャレンジ!...私はルールを簡単に参照するために列挙されるべきだと思う、と私は3番目と6番目のルールを理解していない
hallvabo

@hallvaboラベル付きの図を追加することで、後者の2つのルールを明確にしました。
プリーズスタンド

明確化の要求:改行は80文字の最大行長に含まれていますか、それとも最大80文字改行を加えたものですか?(私は後者を仮定しましたが、いくつかの提出物は前者を仮定したようです。)
Ilmari Karonen

@IlmariKaronen後者。
プリーズスタンド

回答:


5

Perl、196/239文字

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}

このソリューションは、パターンが下から上ではなく上から下に塗りつぶされるという点でJSの例とは異なりますが、ルールでそれについて何も言わなかったので、それは問題ないと思います。

単純な1文字の削減は\e、リテラルのESC文字に置き換えることで実現できますが、コードの読み取りと編集がはるかに難しくなります。


更新:、パターンを下から上に塗りつぶし、追加の43文字のコストで、JS実装の例のように、パターンの塗りつぶされた部分に雪が降らないバージョンを思いついた:

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}

($s[$_]&=~$f[$_])単にに置き換えると、$s[$_]雪がパターンの塗りつぶされた部分を通過するようになり、11文字を節約できます(仕様に一致しますが、実装例には一致しません)。


1週間経ってもまだレースをリードしているようですので、より多くの競争を促進するために私のソリューションがどのように機能するかを説明する必要があると思います。(注:この説明は、196文字のトップダウン充填バージョンに関するものです。後で他のバージョンを含めるように修正する場合があります。)

まず第一に、私の解決策が基づいている1つの大きなトリックは、ASCII文字コードの配置方法のために、スペースのASCIIコードの1ビットがたまたまのコードのそれらのサブセットであるということですアスタリスク。

したがって、次の式が真である:" " & "*" eq " "及び" " | "*" eq "*"。これにより、ビット単位の文字列操作を使用して、個々の文字をループすることなくシーンの静的部分と移動部分を結合できます。

それで、それが邪魔にならないように、コードを見ていきましょう。これは、ゴルフを解体したバージョンです。

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;
}

最初の行は、配列@f(「固定」用)および@p(「パターン」用)を設定します。 @fは、ディスプレイの固定部分を形成し、スペースのみを含むものから始まりますが、@p直接表示されないには、入力パターンが含まれます。アニメーションが進むにつれて、@f最終的にはのようになるまで、アスタリスクをさらに追加していきます@p

具体的には、それぞれ80スペースの24文字列に@f = ($" x 80) x 23設定@fします。($"デフォルト値がたまたまスペースである特別なPerl変数です。)次に、このリストを取得し、readline演算子を使用して入力行を追加し、<>この結合リストの最後の24行を取得して割り当てます@p@pパターンが必要な場所に表示されるように空白行を埋め込むコンパクトな方法。最後にchomp、入力行@pて後続の改行を削除し、後で問題が発生しないようにします。

それでは、メインループを見てみましょう。これは、特にセミコロンを直後に続けるため、前にセミコロンを省略することができる場合、または{...;redo}よりも無限ループを記述する短い方法ですwhile(1){...}for(;;){...}redoifのブロックを。

メインループの最初の行は、配列を導入し@s(もちろん「雪」の場合)、反復ごとに90%のスペースと10%のアスタリスクのランダムな80文字の文字列を付加します。(いくつかの文字を節約するために、実際に@s配列の最後から余分な行をポップすることはありませんので、ますます長くなります。最終的には、配列がメモリに収まりきらないためにプログラムが停止しますが、ほとんどの人がこのアニメーションを見るよりもはるかに時間がかかります。7文字のコストでそれを修正するpop@s;前にステートメントを追加しselectます。)

メインループの残りの部分はifブロックでラップされているため、一度だけ実行されます@s配列に少なくとも24行が含まれます。これは仕様に準拠するための簡単な方法です。この方法では、最初から雪が降ってディスプレイ全体を埋める必要があり、ビット単位の操作も少し簡略化されます。

次に、foreachループがあります。これは、ゴルフバージョンでは、実際にはfor 0..23修飾子を持つ単一のステートメントです。ループの内容にはおそらく説明が必要なので、以下でもう少し詳しく説明します。

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
}

まず第一に、$_別の変数が指定されない限り、Perlのデフォルトのループカウンター変数です。ここでは、0から23まで、つまり、表示フレームの24行にわたって実行されます。 $foo[$_]は、$_配列内のでインデックス付けされた要素を示します@foo

デgolfedループの最初の行に、我々は、改行(便宜から得られるいずれかの印刷$/特殊変数)または、$_0に等しく、ストリング"\e[H"\eESC文字を意味します。これは、カーソルを画面の左上隅に移動するANSI端末制御コードです。技術的には、特定の画面サイズを想定している場合は省略できますが、アニメーションを実行するために端末のサイズを変更する必要がないため、このバージョンでそれを保持しました。

上の$t = $f[$_]行は、我々だけの現在の値を保存$f[$_](したがって、「一時的な」変数には$t)前に潜在的に次の行、それを変更する$s[$_] & $p[$_]雪と入力パターンの交点(ビット単位のAND)を与えると、|=オペレータの論理和それを固定出力行に$f[$_]

その下の行$t ^ $f[$_]で、の以前の値と現在の値のビット単位のXOR $f[$_]、つまり前の行で変更したビットのリストがあれば、その入力文字列のいずれかを~否定すると出力が否定されます。したがって、取得するのは、前の行で追加したビットを除き、すべてのビットが1に設定されたビットマスク$f[$_]です。そのビットマスクをANDすると、$s[$_]それらのビットが削除されます。つまり、落下するスノーフレークが固定パターンの穴を埋めると、落下する雪の配列から削除されます。

最後に、print $f[$_] | $s[$_](ゴルフバージョンでは、前の2行をORするだけで実装されます)現在の行の固定された雪片と動いている雪片の和集合(ビット単位のOR)を出力します。

もう1つ説明する必要があるのselect '', '', '', 0.1は、内側のループの下です。これは、Perlで0.1秒スリープするための単なる手間のかかる方法です。馬鹿げた歴史的な理由から、標準のPerl sleepコマンドには1秒の解像度がありsleepTime::HiResモジュールからより良いものをインポートするには4-argをselect乱用するよりも多くの文字が必要です。


わずかなバグがあるようです。24行目は使用されておらず、ASCIIアートの一番下の行は23行目です。もともとそれを指定しませんでしたが、実際には、上のスペースを埋める前に下のスペースを埋めるべきです。
プリーズスタンド

@PleaseStand:コードを変更して、24行すべてを使用するようにしました(そして、偶然にを削除しましたsay)が、2文字余分にかかりました。ただし、注文を非常に簡単に変更できるとは思いません。私の実装はかなり基本的にそれに関連付けられています。
イルマリカロネン

素晴らしい説明!このエントリに再び投票できるといいのですが。
ディロン・コーワー

@PleaseStand:私は実際にはなかった、今はかなりあなたのJSの例と同じように見えるボトムアップ充填バージョンを作るために管理します。トップダウンのものよりも少し長いですが、今のところ他のエントリよりも短いです。
イルマリカロネン

3

HTMLおよびJavaScript、436文字

入力の前に追加します。

<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>

各例で実行してください:コードゴルフスタックオーバーフローロゴクリスマスツリー。Internet Explorerユーザーは、この送信を正しく機能させるために、バージョン9を実行し、「ドキュメントモード」を「IE9標準」に設定する必要があります(F12開発者ツールを使用)。


1
3つすべてが壊れているようですか?pasteall.org/pic/show.php?id=66297
CoDEmanX

1

Python、299文字

これは、改行が80文字の制限に含まれると仮定して、ルールに準拠する必要があります。

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)

入力に正確に80文字(および改行)の長さの行がある場合、出力はねじれます。PleaseStandに、問題ないかどうかを明確にするように依頼しました。
イルマリカロネン

これは、各80文字幅の行の最後に改行を含めるためです。ここでは、改行を含める必要があることを指定しているため、説明はあいまいですが、端末の幅が80文字であると想定する場合もあります(この場合、改行を省略して自動ラッピングに依存します)。
hallvabo

実際の問題は、入力行を80文字にパディングする前に改行を削除しないことだと思います。そのため、80文字プラス改行入力では実際に81文字が追加aされ、インデックス作成が台無しになります。試したところ、6行目で置き換える%e%e.rstrip()問題が解決したようです。(もちろん、もっと短い修正があるかもしれません。私はPythonゴルフが得意ではありません。)
イルマリカロネン

81文字の行をサポートしたい場合は、数字を変更するだけで問題ありません。1行あたり100文字未満である限り、
文字数

81文字の行を使用するようにコードを変更すると、80列の端末で正しく実行されなくなります。80カラムの出力をうまく生成していますが、80カラムの入力を正しく受け入れていないだけです。試してみてください:各行に80個のアスタリスクが付いた2、3行の入力ファイルを作成し、何が起こるかを確認してください。それはそれほど難しくないはずです。私のソリューションはそれをうまく処理します。
イルマリカロネン

0

Java、625文字

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);}}

Javaのシンプルなソリューション。


いいですが、仕様に準拠しているとは思いません。特に、最初からパターン全体を表示します。サンプルデモのように、「雪からの形成」ではありません。(確かに、これは質問でよりよく説明できます。デモを見て、それが何をすべきかを理解する必要があります。)また、フレームレートが遅すぎるため、雪に覆われた画面から始めないでください。与えられた例とは異なる入力形式を想定しているので、フレーム間のカーソル位置を本当にリセットする"\033[H"必要があります(印刷する必要があります)。
イルマリカロネン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.