Steampunk: animation Clacker

11

Dans le roman Steampunk très sous-estimé The Difference Engine , l'équivalent des salles de cinéma a fourni une image animée pixellisée affichée par des carreaux qui pouvaient être retournés mécaniquement. Le moteur de contrôle pour orchestrer le mouvement de ces tuiles était une grande machine bruyante contrôlée par un jeu de cartes perforées.

Votre tâche consiste à émuler un tel moteur et à afficher une animation pixelisée comme spécifié par un fichier d'entrée. L'entrée se compose de lignes dans un format à largeur fixe, mais vous pouvez supposer tout ce qui convient pour une indication de fin de ligne. Le format est:

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)

L'entrée est explicitement séquencée (si jamais vous déposez votre jeu de cartes sur le sol, vous me remercierez pour cette partie). Cela signifie que le programme doit effectuer un tri stable des lignes d'entrée en utilisant le champ de séquence comme clé de tri. Les lignes avec le même numéro de séquence doivent conserver leur ordre relatif d'origine. (Il devrait fonctionner avec un tri instable, si vous ajoutez le numéro de ligne réel à la clé.) Un champ de séquence vide doit être interprété comme inférieur à n'importe quel nombre (séquence de classement ascii).

Une seule ligne d'instruction ne peut affecter qu'une seule coordonnée y, mais peut spécifier une plage contiguë de valeurs x. La valeur x finale peut être laissée en blanc ou peut être identique à la valeur initiale afin d'affecter un seul pixel.

L'opcode est un chiffre hexadécimal qui spécifie le code de fonction binaire universel qui est utilisé comme rasterop. L'argument est 0 ou 1. L'opération de raster effectuée est

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

Ainsi, la valeur d'origine du pixel entre comme X dans la table UBF et la valeur d'argument de l'instruction entre comme Y. Le résultat de cette fonction est la nouvelle valeur du pixel. Et cette opération est effectuée sur chaque paire x, y de xx, YY à XX, YY spécifiée dans l'instruction. La plage spécifiée par xx et XX comprend les deux points d'extrémité. Donc

0000 0 010F1

doit définir les pixels 0,1,2,3,4,5,6,7,8,9,10 sur la ligne 0.

Les dimensions de sortie ( m x n ) doivent être de 20 x 20 au minimum, mais peuvent être plus grandes si vous le souhaitez. Mais le grain devrait apparaître, vous savez? Il est censé être pixélisé . Les sorties graphiques et ASCII sont acceptables.

Si par exemple, nous voulions faire une image d'une figure pixélisée:

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

   ###
   # #
   # #

Si nous le dessinons avec une opération de retournement, comme XOR, elle peut être dessinée et effacée, que l'écran soit noir ou blanc.

    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

Dupliquer cette séquence fera apparaître et disparaître la figure.

NMM n'est pas Mickey Mouse

Une animation plus grande peut être composée dans le désordre, en spécifiant différents "plans" dans le champ de séquence.

   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

Produire:

noir / blanc vs blanc / noir

C'est le donc le programme le plus court (par nombre d'octets) gagne. Bonus (-50) si le moteur fait des bruits de cliquetis.

luser droog
la source
3
Normalement, on demande des éclaircissements en publiant dans le bac à sable. Essayez-vous de fermer le bac à sable?
John Dvorak
5
Pour moi personnellement, les bacs à sable sont une impasse. Je suis trop bon pour tergiverser pour les finir. Ici, en direct, je ne peux ignorer le feu sous mes fesses.
luser droog
1
Comment fonctionne le connecteur booléen? Rejoint-il uniquement les lignes avec le même numéro de séquence? S'ils sont mélangés, existe-t-il une certaine forme de priorité des opérateurs? Avez-vous des cas de test qui reposent sur des connecteurs booléens? Pourquoi le scénario de test que vous avez publié n'a-t-il pas de numéro de séquence? La xcoordonnée finale est-elle toujours inclusive?
Peter Taylor
5
Voici quelques bruits de cliquetis . Ai-je droit à un bonus? ;-)
Digital Trauma
1
Pour le son, pensez-vous à quelque chose comme des flipboards de gare? Exemple: planche solari à la gare du nord à paris ou Split-flap Display - Circuit de pilotage DIY . Ou pensez-vous plus de sons de relais mécaniques?
Scott Leadley

Réponses:

3

Mathematica, 306 281 octets

Cela attend que la chaîne d'entrée soit stockée dans une variable 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}]]]

Et ici avec un espace:

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

Ça a été sacrément long. Ce défi contenait de nombreux détails délicats, et en particulier l'analyse en entrée prend beaucoup de code dans Mathematica (près de la moitié, 137 octets, analysent simplement l'entrée). J'ai fini par changer de langue deux fois avant de m'installer sur Mathematica (je pensais pouvoir économiser sur l'analyse des entrées en utilisant Ruby, mais j'ai réalisé que le résultat devait être animé , alors je suis retourné à Mathematica).

Martin Ender
la source
2

Exemple Postscript non golfé

Il s'agit d'un programme de style "protocole-prologue", donc les données suivent immédiatement dans le même fichier source. Fichiers GIF animés peuvent être produits avec de ImageMagick convertutilitaire (utilisations de 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
la source
Les informations de la boîte englobante ont été découvertes en exécutant gs -sDEVICE=bbox clack.ps.
luser droog