Steampunk: Clacker-Animation

11

In dem stark unterschätzten Steampunk-Roman The Difference Engine lieferte das Äquivalent von Kinohäusern ein pixeliges Bewegtbild, das von Kacheln angezeigt wurde, die mechanisch umgedreht werden konnten. Die Steuerungsmaschine zum Orchestrieren der Bewegung dieser Kacheln war eine große, laute Maschine, die von einem Kartenspiel gesteuert wurde.

Ihre Aufgabe ist es, eine solche Engine zu emulieren und eine pixelige Animation anzuzeigen, wie in einer Eingabedatei angegeben. Die Eingabe besteht aus Zeilen in einem Format mit fester Breite. Sie können jedoch davon ausgehen, was für eine Anzeige am Zeilenende zweckmäßig ist. Das Format ist:

SSSSYYxxXXOA
SSSS: 4 digit sequence no. may be padded by blanks or all blank
    YY: the y coordinate affected by this line (descending, top is 0, bottom is m-1)
      xx: the starting x coordinate
        XX: the ending x coordinate
          O: hexadecimal opcode
           A: argument (0 or 1)

Die Eingabe erfolgt explizit (wenn Sie jemals Ihr Kartenspiel auf den Boden fallen lassen, werden Sie mir für diesen Teil danken). Das heißt, das Programm muss eine stabile Sortierung der Eingabezeilen durchführen, wobei das Sequenzfeld als Sortierschlüssel verwendet wird. Zeilen mit derselben Sequenznummer müssen ihre ursprüngliche relative Reihenfolge beibehalten. (Es sollte mit einer instabilen Sortierung funktionieren, wenn Sie die tatsächliche Zeilennummer an die Taste anhängen.) Ein leeres Sequenzfeld sollte als niedriger als eine beliebige Zahl interpretiert werden (ASCII-Kollatierungssequenz).

Eine einzelne Anweisungszeile kann nur eine einzelne y-Koordinate beeinflussen, kann jedoch einen zusammenhängenden Bereich von x-Werten angeben. Der Endwert x kann leer bleiben oder mit dem Anfangswert identisch sein, um ein einzelnes Pixel zu beeinflussen.

Der Opcode ist eine hexadezimale Ziffer, die den universellen Binärfunktionscode angibt, der als Rasterop verwendet wird. Das Argument ist 0 oder 1. Die durchgeführte Rasteroperation ist

pixel = pixel OP argument          infix expression
         --or-- 
        OP(pixel, argument)        function call expression

Der ursprüngliche Wert des Pixels wird also als X in die UBF-Tabelle eingegeben, und der Argumentwert aus der Anweisung wird als Y eingegeben. Das Ergebnis dieser Funktion ist der neue Wert des Pixels. Und diese Operation wird für jedes x, y-Paar von xx, YY bis XX, YY ausgeführt, das in der Anweisung angegeben ist. Der durch xx und XX angegebene Bereich umfasst beide Endpunkte. So

0000 0 010F1

sollte die Pixel 0,1,2,3,4,5,6,7,8,9,10 in Zeile 0 setzen.

Die Ausgangsabmessungen ( m x n ) sollten mindestens 20 x 20 betragen, können jedoch bei Bedarf größer sein. Aber das Korn sollte sich zeigen, weißt du? Es soll pixelig sein . Sowohl grafische als auch ASCII-artige Ausgaben sind akzeptabel.

Wenn wir zum Beispiel ein Bild von einer pixeligen Figur machen wollten:

  #   #
   ###
   ##
   ####
    #
#### ####
   # #

   ###
   # #
   # #

Wenn wir ihn mit einem Bit-Flipping-Vorgang wie XOR zeichnen, kann er gezeichnet und gelöscht werden, unabhängig davon, ob der Bildschirm schwarz oder weiß ist.

    00020261
     0 6 661
     1 3 561
     2 3 461
     3 3 661
     4 4 461
     5 0 361
     5 5 861
     6 3 361
     6 5 561
     8 3 561
     9 3 361
     9 5 561
    10 3 361
    10 5 561

Durch Duplizieren dieser Sequenz wird die Figur ein- und ausgeblendet.

NMM ist nicht Mickey Mouse

Eine größere Animation kann außerhalb der Reihenfolge erstellt werden, indem im Sequenzfeld verschiedene "Aufnahmen" angegeben werden.

   100 016F0
   101 016F0
   102 016F0
   103 016F0
   104 016F0
   105 016F0
   106 016F0
   107 016F0
   108 016F0
   109 016F0
   110 016F0
   111 016F0
   112 016F0
   113 016F0
   114 016F0
   115 016F0
   200020261
   2 0 6 661
   2 1 3 561
   2 2 3 461
   2 3 3 661
   2 4 4 461
   2 5 0 361
   2 5 5 861
   2 6 3 361
   2 6 5 561
   2 8 3 561
   2 9 3 361
   2 9 5 561
   210 3 361
   210 5 561
    00020261
     0 6 661
     1 3 561
     2 3 461
     3 3 661
     4 4 461
     5 0 361
     5 5 861
     6 3 361
     6 5 561
     8 3 561
     9 3 361
     9 5 561
    10 3 361
    10 5 561
   300020261
   3 0 6 661
   3 1 3 561
   3 2 3 461
   3 3 3 661
   3 4 4 461
   3 5 0 361
   3 5 5 861
   3 6 3 361
   3 6 5 561
   3 8 3 561
   3 9 3 361
   3 9 5 561
   310 3 361
   310 5 561
    00020261
     0 6 661
     1 3 561
     2 3 461
     3 3 661
     4 4 461
     5 0 361
     5 5 861
     6 3 361
     6 5 561
     8 3 561
     9 3 361
     9 5 561
    10 3 361
    10 5 561

Produzieren:

schwarz / weiß gegen weiß / schwarz

Dies ist so dass das kürzeste Programm (nach Byte-Anzahl) gewinnt. Bonus (-50), wenn der Motor Klickgeräusche macht.

luser droog
quelle
3
Normalerweise bittet man um Klärung, indem man in die Sandbox schreibt. Versuchen Sie, den Sandkasten herunterzufahren?
John Dvorak
5
Für mich persönlich sind die Sandkästen eine Sackgasse. Ich kann zu gut zögern, um sie zu erledigen. Hier, live, kann ich das Feuer unter meinem Hintern nicht ignorieren.
Luser Droog
1
Wie funktioniert der Boolesche Konnektor? Verbindet es nur Zeilen mit derselben Sequenznummer? Wenn sie gemischt sind, gibt es irgendeine Form von Operator-Vorrang? Haben Sie Testfälle, die auf Booleschen Konnektoren basieren? Warum hat der von Ihnen veröffentlichte Testfall keine Sequenznummern? Ist die xEndkoordinate immer inklusive?
Peter Taylor
5
Hier sind einige klickende Klackgeräusche . Bekomme ich einen Bonus? ;-)
Digitales Trauma
1
Denken Sie für Sound so etwas wie Flipboards am Bahnhof? ZB Solari Board am Bahnhof Gare du Nord in Paris oder Split-Flap Display - DIY-Treiberschaltung . Oder denken Sie an mehr mechanische Relaissounds?
Scott Leadley

Antworten:

3

Mathematica, 306 281 Bytes

Dies erwartet, dass die Eingabezeichenfolge in einer Variablen gespeichert wird i

ListAnimate[ArrayPlot/@FoldList[({n,y,x,X,o,a}=#2;MapAt[IntegerDigits[o,2,4][[-1-FromDigits[{#,a},2]]]&,#,{y+1,x+1;;X+1}])&,Array[0&,{20,20}],ToExpression/@MapAt["16^^"<>#&,StringTrim/@SortBy[i~StringSplit~"\n"~StringCases~RegularExpression@"^....|..(?!.?$)|.",{#[[1]]&}],{;;,5}]]]

Und hier mit einigen Leerzeichen:

ListAnimate[ArrayPlot /@ FoldList[(
     {n, y, x, X, o, a} = #2;
     MapAt[
      IntegerDigits[o, 2, 4][[-1 - FromDigits[{#, a}, 2]]] &,
      #,
      {y + 1, x + 1 ;; X + 1}
      ]
     ) &,
   Array[0 &, {20, 20}],
   ToExpression /@ 
    MapAt["16^^" <> # &, 
     StringTrim /@ 
      SortBy[i~StringSplit~"\n"~StringCases~
        RegularExpression@"^....|..(?!.?$)|.", {#[[1]] &}], {;; , 5}]
   ]]

Das wurde verdammt lang. Diese Herausforderung enthielt viele fummelige Details, und insbesondere das Parsen von Eingaben erfordert in Mathematica viel Code (fast die Hälfte davon, 137 Bytes, analysiert nur die Eingabe). Am Ende habe ich die Sprache zweimal gewechselt, bevor ich mich für Mathematica entschieden habe (ich dachte, ich könnte mit Ruby das Parsen der Eingaben sparen, aber dann wurde mir klar, dass das Ergebnis animiert werden muss , also ging ich zurück zu Mathematica).

Martin Ender
quelle
2

Ungolfed Postscript Beispiel

Dies ist ein Programm im "Protokoll-Prolog" -Stil, sodass die Daten unmittelbar in derselben Quelldatei folgen. Animierte GIF-Dateien können mit dem convertDienstprogramm von ImageMagick erstellt werden (verwendet Ghostscript) : convert clack.ps clack.gif.

%%BoundingBox: 0 0 321 321

/t { token pop exch pop } def
/min { 2 copy gt { exch } if pop } def
/max { 2 copy lt { exch } if pop } def

/m [ 20 { 20 string }repeat ] def
/draw { change {
        m {} forall 20 20 8 [ .0625 0 0 .0625 0 0 ] {} image showpage
    } if } def

%insertion sort from https://groups.google.com/d/topic/comp.lang.postscript/5nDEslzC-vg/discussion
% array greater_function insertionsort array
/insertionsort
{ 1 1 3 index length 1 sub
    { 2 index 1 index get exch % v, j
        { dup 0 eq {exit} if
            3 index 1 index 1 sub get 2 index 4 index exec
            {3 index 1 index 2 copy 1 sub get put 1 sub}
            {exit} ifelse
        } loop
        exch 3 index 3 1 roll put
    } for
    pop
} def

/process {
    x X min 1 x X max { % change? x
        m y get exch  % row-str x_i
        2 copy get  % r x r_x 
        dup         % r x r_x r_x
        0 eq { 0 }{ 1 } ifelse  % r x r_x b(x)
        2 mul a add f exch neg bitshift 1 and   % r x r_x f(x,a)
        0 eq { 0 }{ 255 } ifelse  % r x r_x c(f)
        exch 1 index % r x c(f) r_x c(f)
        ne { /change true def } if
        put
    } for
    draw
} def

{ [ {
     currentfile 15 string
         dup 2 13 getinterval exch 3 1 roll
         readline not{pop pop exit}if
    pop
    [ exch
     /b exch dup 0 1 getinterval exch
     /n exch dup 1 1 getinterval exch
     /seq exch dup 2 4 getinterval exch
     /y exch dup 6 2 getinterval t exch
     /x exch dup 8 2 getinterval t exch
     /X exch dup 10 2 getinterval dup (  ) ne { t exch }{pop 2 index exch} ifelse
     /f exch dup 12 get (16#?) dup 3 4 3 roll put t exch
     /a exch 13 get 48 sub
     /change false def
    >>
}loop ]
dup { /seq get exch /seq get exch gt } insertionsort
true exch
{ begin
    b(A)eq{
        { process } if
    }{
        b(O)eq{
            not { process } if
        }{
            pop
            process
        }ifelse
    }ifelse
    change
    end
} forall
    draw
} exec
   100 016F0
   101 016F0
   102 016F0
   103 016F0
   104 016F0
   105 016F0
   106 016F0
   107 016F0
   108 016F0
   109 016F0
   110 016F0
   111 016F0
   112 016F0
   113 016F0
   114 016F0
   115 016F0
   200020261
   2 0 6 661
   2 1 3 561
   2 2 3 461
   2 3 3 661
   2 4 4 461
   2 5 0 361
   2 5 5 861
   2 6 3 361
   2 6 5 561
   2 8 3 561
   2 9 3 361
   2 9 5 561
   210 3 361
   210 5 561
    00020261
     0 6 661
     1 3 561
     2 3 461
     3 3 661
     4 4 461
     5 0 361
     5 5 861
     6 3 361
     6 5 561
     8 3 561
     9 3 361
     9 5 561
    10 3 361
    10 5 561
   300020261
   3 0 6 661
   3 1 3 561
   3 2 3 461
   3 3 3 661
   3 4 4 461
   3 5 0 361
   3 5 5 861
   3 6 3 361
   3 6 5 561
   3 8 3 561
   3 9 3 361
   3 9 5 561
   310 3 361
   310 5 561
    00020261
     0 6 661
     1 3 561
     2 3 461
     3 3 661
     4 4 461
     5 0 361
     5 5 861
     6 3 361
     6 5 561
     8 3 561
     9 3 361
     9 5 561
    10 3 361
    10 5 561
0000 0 515F1
0000 1 11501
0000 1 115F1
luser droog
quelle
Die Bounding-Box-Informationen wurden durch Ausführen ermittelt gs -sDEVICE=bbox clack.ps.
Luser Droog