ASCII-animierte Schneeszene


22

Schreiben Sie das kürzeste Programm, um aus jedem ASCII-Kunstwerk eine animierte Schneeszene zu machen, die sich aus dem fallenden Schnee zu formen beginnt ( JavaScript-Beispiel ohne Golfspiel, zuletzt aktualisiert am 19.12.2011).

Eingabespezifikation : Ihr Programm muss beliebige Kombinationen von Leerzeichen, Sternchen und Zeilenumbrüchen akzeptieren. Die Eingabe enthält höchstens 23 Zeilen und 80 Zeichen pro Zeile. Es werden keine Leerzeilen angezeigt, die Zeilen dürfen jedoch nur aus Leerzeichen bestehen. Eine einzelne nachgestellte Zeile wird eingefügt und muss ignoriert werden.

Ausgabe : Geben Sie ASCII-Zeichen (Leerzeichen, Sternchen) und Steuercodes (Zeilenumbrüche, Zeilenvorschübe, ANSI-Escape-Codes usw.) für die Textkonsole oder den Terminal-Emulator Ihres Betriebssystems aus, bis der Benutzer das Programm manuell beendet. Sie können davon ausgehen, dass das Terminalfenster 80 x 24 Zeichen umfasst, wenn Ihr Betriebssystem diese Einstellung zulässt.

Regeln :

  • Die Animation muss flüssig und schnell sein (15 fps bevorzugt).
  • Die Schneedichte muss zwischen 5% und 15% liegen.
  • Es darf nicht mehr als ein Schneebildschirm pro Sekunde angezeigt werden. (Das bedeutet, dass in einem Zeitraum von einer Sekunde nicht mehr als 24 Zeilen Neuschnee hinzugefügt werden dürfen.)
  • Der Schnee darf kein offensichtliches Muster aufweisen, wenn er oben auf dem Bildschirm eintritt. es muss zufällig aussehen.
  • Das Programm muss alle Zeilen des Bildschirms so schnell wie möglich mit Schnee füllen, wenn es startet. Das anfängliche Füllen der einzelnen Zeilen des Bildschirms darf für den Betrachter nicht offensichtlich sein.
  • Die untere linke Ecke der ASCII-Eingabekunst muss sich in der unteren linken Ecke des Bildschirms befinden (Abbildung 1 zur weiteren Verdeutlichung).
  • Der Bereich innerhalb oder unter der ASCII-Grafik darf nicht dauerhaft mit Sternchen ausgefüllt sein. Sternchen können (müssen aber nicht) durch diesen Bereich scrollen.
  • Schnee darf sich nicht am unteren Bildschirmrand oder auf vorhandenem Schnee ansammeln, außer wie in der Eingabe angegeben.
  • Die unteren Felder müssen vor den oberen ausgefüllt werden, da das Ausfüllen der Felder in umgekehrter Reihenfolge dazu führt, dass die Weihnachtsbaumanimation sich stark von der Ausgabe meines ursprünglichen Codes unterscheidet. (hinzugefügt am 20.12.2011)

Schöne Ferien!

Abbildung 1: Beschriftete Bereiche eines 80x24-Bildschirms

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

Beispieleingaben

Code Golf Banner

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

Stapelüberlauf-Logo

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

Weihnachtsbäume

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

1
Der dritte Weihnachtsbaum ist kaputt.
Bobby

Schöne Herausforderung! Ich denke, die Regeln sollten zur leichteren Bezugnahme aufgezählt werden, und ich verstehe die dritte und sechste Regel nicht ...
hallvabo

@hallvabo Ich habe diese beiden Regeln geklärt, indem ich eine beschriftete Zahl hinzugefügt habe.
PleaseStand

Bitte um Klarstellung: Ist der Zeilenumbruch in der maximalen Zeilenlänge von 80 Zeichen enthalten , oder sind es maximal 80 Zeichen plus Zeilenumbruch? (Ich nahm das letztere an, aber einige Einreichungen schienen das erstere angenommen zu haben.)
Ilmari Karonen

@IlmariKaronen Letzteres.
Bitte stehen

Antworten:


5

Perl, 196/239 Zeichen

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}

Diese Lösung unterscheidet sich von Ihrem JS-Beispiel darin, dass das Muster von oben nach unten und nicht von unten nach oben gefüllt wird. Ich gehe jedoch davon aus, dass dies in Ordnung ist, da Sie in den Regeln nichts dazu gesagt haben.

Durch Ersetzen \emit einem wörtlichen ESC-Zeichen kann eine triviale 1- Zeichen -Reduzierung erzielt werden , was jedoch das Lesen und Bearbeiten des Codes erheblich erschwert.


Update: Ich habe es geschafft, eine Version zu entwickeln, die das Muster von unten nach oben ausfüllt und es nicht zulässt, dass Schnee durch die gefüllten Teile des Musters fällt, wie in der JS-Beispielimplementierung, und das kostet 43 zusätzliche Zeichen:

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}

Ersetzen ($s[$_]&=~$f[$_]) mit nur $s[$_]würde 11 Zeichen einsparen, indem fallender Schnee durch die gefüllten Teile des Musters geleitet wird (was der Spezifikation entspricht, aber nicht der Beispielimplementierung).


OK, da ich nach einer Woche immer noch an der Spitze des Rennens zu stehen scheine, sollte ich erklären, wie meine Lösung funktioniert, um mehr Wettbewerb zu fördern. (Hinweis: Diese Erklärung gilt für die Top-Down-Füllversion mit 196 Zeichen. Ich kann sie dahingehend ändern, dass sie später die andere Version enthält.)

Zunächst einmal besteht der große Trick, auf dem meine Lösung basiert, darin, dass aufgrund der Anordnung der ASCII-Zeichencodes die 1-Bits im ASCII-Code für ein Leerzeichen zufällig eine Teilmenge derjenigen im Code für ein sind Sternchen.

Somit sind die folgenden Ausdrücke wahr: " " & "*" eq " "und" " | "*" eq "*" . Auf diese Weise kann ich bitweise Zeichenfolgenoperationen zum Kombinieren der statischen und sich bewegenden Teile der Szene verwenden, ohne einzelne Zeichen durchlaufen zu müssen.

Lassen Sie uns nun den Code durchgehen. Hier ist eine entgolfte Version davon:

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

Die erste Zeile richtet die Arrays @f(für "fixed") und @p(für "pattern") ein. @fbildet den festen Teil der Anzeige und enthält zunächst nur Leerzeichen, während @pdas Eingabemuster nicht direkt angezeigt wird. Mit fortschreitender Animation werden wir immer mehr Sternchen hinzufügen, @fbis es schließlich so aussieht @p.

Insbesondere @f = ($" x 80) x 23setzt @fbis 24 Saiten 80 Räume jeweils. ( $"ist eine spezielle Perl-Variable, deren Standardwert zufällig ein Leerzeichen ist.) Wir nehmen diese Liste, hängen die Eingabezeilen mit dem readline-Operator an <>, nehmen die letzten 24 Zeilen dieser kombinierten Liste und weisen sie zu @p: this is Eine kompakte Möglichkeit, @pleere Linien einzufügen, damit das Muster dort angezeigt wird, wo es sollte. Schließlich müssen wir chompdie Eingabezeilen @peingeben, um alle nachgestellten Zeilen zu entfernen, damit sie später keine Probleme verursachen.

Schauen wir uns nun die Hauptschleife an. Es stellt sich heraus, dass dies {...;redo}ein kürzerer Weg ist, eine Endlosschleife zu schreiben als while(1){...}oder sogar for(;;){...}, besonders wenn wir das Semikolon vorher weglassen müssen, redoweil es unmittelbar auf einen ifBlock folgt .

In der ersten Zeile der Hauptschleife wird das Array @s(natürlich für "snow") eingefügt, dem bei jeder Iteration eine zufällige 80-stellige Zeichenfolge mit 90% Leerzeichen und 10% Sternchen vorangestellt wird. (Um ein paar Zeichen zu sparen, platziere ich eigentlich nie zusätzliche Zeilen am Ende des @sArrays, damit es immer länger wird. Das wird das Programm schließlich zum Stillstand bringen, da das Array zu lang wird, um in den Speicher zu passen, aber das wird viel länger dauern als die meisten Menschen jemals diese Animation aufpassen würde. eine Hinzufügen pop@s;Aussage vor demselect hinzufügen, wird dies auf Kosten von sieben Zeichen behoben.)

Der Rest der Hauptschleife wird in einen ifBlock eingeschlossen, sodass er nur ausgeführt wird, wenn das @sArray mindestens 24 Zeilen enthält. Dies ist eine einfache Möglichkeit, die Spezifikation einzuhalten, die es erfordert, dass das gesamte Display von Anfang an mit fallendem Schnee gefüllt ist, und vereinfacht auch die bitweisen Operationen ein wenig.

Als nächstes folgt eine foreachSchleife, die in der Golfversion eigentlich eine einzelne Anweisung mit einem for 0..23Modifikator ist. Da der Inhalt der Schleife wahrscheinlich eine Erklärung benötigt, werde ich ihn weiter unten etwas entpacken:

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
}

Zunächst $_ist dies die Standardvariable für den Schleifenzähler in Perl, sofern keine andere Variable angegeben ist. Hier läuft es von 0 bis 23, also über die 24 Zeilen im Displayrahmen. $foo[$_]bezeichnet das Element, das $_im Array durch indiziert ist @foo.

In der ersten Zeile der entgolften Schleife drucken wir entweder eine neue Zeile (zweckmäßigerweise aus der $/speziellen Variablen) oder, wenn $_gleich 0, die Zeichenfolge "\e[H", wobei \eein ESC-Zeichen bezeichnet wird. Dies ist ein ANSI-Terminal-Steuercode , mit dem der Cursor in die linke obere Ecke des Bildschirms bewegt wird. Technisch könnten wir das weglassen, wenn wir eine bestimmte Bildschirmgröße annehmen würden, aber ich habe es in dieser Version beibehalten, da dies bedeutet, dass ich die Größe meines Terminals nicht ändern muss, um die Animation auszuführen.

In der $t = $f[$_]Zeile speichern wir nur den aktuellen Wert von $f[$_]in einer "temporären" Variablen (daher $t), bevor wir ihn möglicherweise in der nächsten Zeile ändern, wo $s[$_] & $p[$_]der Schnittpunkt (bitweises UND) des fallenden Schnees und des Eingabemusters sowie die |=Operator-ODERs angegeben werden das in die feste Ausgangsleitung $f[$_].

In der Zeile darunter wird $t ^ $f[$_]das bitweise XOR des vorherigen und des aktuellen Werts von angegeben $f[$_], dh eine Liste der in der vorherigen Zeile geänderten Bits, falls vorhanden, und das Negieren einer der Eingabezeichenfolgen mit ~negiert die Ausgabe. Wir erhalten also eine Bitmaske, bei der alle Bits auf 1 gesetzt sind, mit Ausnahme derjenigen, die wir gerade in $f[$_]der vorherigen Zeile hinzugefügt haben . Durch UND-Verknüpfung dieser Bitmaske werden $s[$_]diese Bits entfernt. Tatsächlich bedeutet dies, dass eine fallende Schneeflocke, wenn sie ein Loch im festen Muster ausfüllt, aus dem Fallschnee-Array entfernt wird.

Schließlich wird print $f[$_] | $s[$_](was in der Golfversion durch einfaches ODER-Verknüpfen der beiden vorherigen Zeilen implementiert wird) nur die Vereinigung (bitweises ODER) der festen und sich bewegenden Schneeflocken in der aktuellen Zeile gedruckt.

Eine weitere zu erklärende Sache ist die select '', '', '', 0.1unterhalb der inneren Schleife. Dies ist nur eine mühsame Methode, um in Perl 0,1 Sekunden zu schlafen. Aus irgendeinem dummen historischen Grund hat der Standard-Perl- sleepBefehl eine Auflösung von einer Sekunde, und das Importieren eines besseren sleepaus dem Time::HiResModul erfordert mehr Zeichen als der Missbrauch von 4-Argumentenselect .


Es scheint einen kleinen Fehler zu geben: Die 24. Zeile wird nicht verwendet, und die unterste Zeile der ASCII-Grafik ist die 23. Zeile. Und es sollte wirklich untere Räume füllen, bevor es obere füllt, obwohl ich das ursprünglich nicht spezifiziert habe.
PleaseStand

@PleaseStand: Ich habe den Code so geändert, dass alle 24 Zeilen verwendet werden (und habe im Übrigen die entfernt say), und zwar zum Preis von 2 zusätzlichen Zeichen. Ich glaube jedoch nicht, dass ich die Füllreihenfolge leicht ändern kann. meine umsetzung ist eher grundlegend daran gebunden.
Ilmari Karonen

Tolle Erklärung! Ich wünschte, ich könnte diesen Eintrag noch einmal hochstimmen.
Dillon Cower

@PleaseStand: Ich eigentlich habe gelingt , eine Bottom-up - Füllung Version zu machen, die jetzt so ziemlich das gleiche wie Ihr JS Beispiel aussieht; Es ist etwas länger als das von oben nach unten, aber immer noch kürzer als die anderen Einträge.
Ilmari Karonen

3

HTML und JavaScript, 436 Zeichen

Stellen Sie es der Eingabe voran:

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

Sehen Sie, wie es für jedes Beispiel ausgeführt wird: Codegolf , Stack Overflow-Logo , Weihnachtsbäume . Internet Explorer-Benutzer müssen Version 9 ausführen und den "Dokumentmodus" auf "IE9-Standards" setzen (mithilfe der F12-Entwicklertools), damit diese Übermittlung ordnungsgemäß funktioniert.


1
Alle 3 scheinen kaputt zu sein? pasteall.org/pic/show.php?id=66297
CoDEmanX

1

Python, 299 Zeichen

Dies sollte den Regeln entsprechen, vorausgesetzt, der Zeilenumbruch ist im 80-Zeichen-Limit enthalten.

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)

Ihre Ausgabe wird nervös, wenn die Eingabe Zeilen enthält, die genau 80 Zeichen (plus Zeilenvorschub) lang sind. Ich habe PleaseStand gebeten zu klären, ob das in Ordnung ist.
Ilmari Karonen

Dies liegt daran, dass ich am Ende jeder 80 Zeichen breiten Zeile einen Zeilenumbruch anhänge. Die Beschreibung ist hier nicht eindeutig, da sie angibt, dass Zeilenumbrüche enthalten sein müssen, aber auch, dass das Terminal eine Breite von 80 Zeichen haben kann (in diesem Fall können Zeilenumbrüche weggelassen und ein automatischer Zeilenumbruch verwendet werden).
Hallvabo

Ich denke, das eigentliche Problem ist, dass Sie die Zeilenumbrüche nicht entfernen, bevor Sie die Eingabezeilen mit 80 Zeichen auffüllen, sodass eine Eingabe mit 80 Zeichen plus Zeilenumbrüchen tatsächlich 81 Zeichen anfügt aund so die Indizierung durcheinander bringt . Ich habe es gerade ausprobiert und es sieht so aus, als ob das Ersetzen %edurch %e.rstrip()Zeile 6 das Problem behebt. (Natürlich kann es auch einen kürzeren Fix geben; ich bin kein guter Python-Golfer.)
Ilmari Karonen

Wenn Sie 81 Zeichen unterstützen möchten, ändern Sie einfach die Zahlen, und es funktioniert einwandfrei. Solange Sie unter 100 Zeichen pro Zeile bleiben, ändert sich die
Zeichenanzahl

Wenn ich Ihren Code so ändere, dass er 81-Zeichen-Zeilen verwendet, wird er auf einem Terminal mit 80 Spalten nicht korrekt ausgeführt. Sie produzieren eine Ausgabe mit 80 Spalten, es ist nur so, dass Sie eine Eingabe mit 80 Spalten nicht korrekt akzeptieren . Probieren Sie es aus: Erstellen Sie eine Eingabedatei mit ein paar Zeilen mit jeweils 80 Sternchen und sehen Sie, was passiert. Es sollte nicht so schwer sein: Meine Lösung kommt damit zurecht.
Ilmari Karonen

0

Java, 625 Zeichen

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

Eine einfache Lösung in Java.


Nett, aber ich glaube nicht, dass Sie die Spezifikation einhalten. Insbesondere zeigen Sie das gesamte Muster von Anfang an - es entsteht nicht "aus dem fallenden Schnee" wie in der Beispieldemo. (Zugegeben, dies könnte in der Frage besser erklärt werden. Sie müssen sich die Demo unbedingt ansehen, um zu verstehen, was sie tun soll.) Außerdem ist Ihre Bildrate zu langsam Nehmen Sie ein Eingabeformat an, das sich von den angegebenen Beispielen unterscheidet, und Sie sollten die Cursorposition zwischen den Frames wirklich zurücksetzen (dies "\033[H"sollte beim Drucken geschehen).
Ilmari Karonen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.