Steampunk: animación de Clacker

11

En la muy subestimada novela de Steampunk, The Difference Engine , el equivalente de las salas de cine presentaba una imagen en movimiento pixelada que se mostraba con mosaicos que se podía voltear mecánicamente. El motor de control para orquestar el movimiento de estas fichas era una gran máquina ruidosa controlada por una baraja de cartas perforadas.

Su tarea es emular dicho motor y mostrar una animación pixelada como se especifica en un archivo de entrada. La entrada consta de líneas en un formato de ancho fijo, pero puede suponer lo que sea conveniente para una indicación de final de línea. El formato es:

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)

La entrada está secuenciada explícitamente (si alguna vez dejas caer tu baraja en el suelo, me lo agradecerás por esta parte). Eso significa que el programa debe realizar un tipo estable de las líneas de entrada utilizando el campo de secuencia como una clave de clasificación. Las líneas con el mismo número de secuencia deben mantener su orden relativo original. (Debería funcionar con una ordenación inestable, si agrega el número de línea real a la clave). Un campo de secuencia en blanco debe interpretarse como más bajo que cualquier número (secuencia de clasificación ascii).

Una sola línea de enunciado solo puede afectar una sola coordenada y, pero puede especificar un rango contiguo de valores x. El valor x final puede dejarse en blanco o puede ser idéntico al valor inicial para afectar un solo píxel.

El código de operación es un dígito hexadecimal que especifica el Código de función binaria universal que se usa como rasterop. El argumento es 0 o 1. La operación ráster realizada es

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

Entonces, el valor original del píxel ingresa como X en la tabla UBF, y el valor del argumento de la declaración ingresa como Y. El resultado de esta función es el nuevo valor del píxel. Y esta operación se realiza en cada par x, y de xx, YY a XX, YY especificado en la declaración. El rango especificado por xx y XX incluye ambos puntos finales. Entonces

0000 0 010F1

debe establecer los píxeles 0,1,2,3,4,5,6,7,8,9,10 en la fila 0.

Las dimensiones de salida ( m x n ) deben ser de 20 x 20 como mínimo, pero pueden ser mayores si se desea. Pero el grano debería mostrar, ¿sabes? Se supone que está pixelado . Tanto la salida gráfica como la de arte ASCII son aceptables.

Si, por ejemplo, quisiéramos hacer una imagen de una figura pixelada:

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

   ###
   # #
   # #

Si lo dibujamos con una operación de cambio de bits, como XOR, se puede dibujar y borrar independientemente de si la pantalla es negra o blanca.

    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

Duplicar esta secuencia hará que la figura aparezca y desaparezca.

NMM no es Mickey Mouse

Una animación más grande se puede componer fuera de orden, especificando diferentes "disparos" en el campo de secuencia.

   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

Productor:

negro / blanco vs blanco / negro

Este es el por lo que el programa más corto (por conteo de bytes) gana. Bonificación (-50) si el motor hace ruidos de clickity-clack.

luser droog
fuente
3
Normalmente uno solicita aclaraciones publicando en el sandbox. ¿Estás tratando de cerrar la caja de arena?
John Dvorak
55
Para mí personalmente, los sandboxes son un callejón sin salida. Soy demasiado bueno postergando para terminarlos. Aquí, vivo, no puedo ignorar el fuego debajo de mi trasero.
luser droog
1
¿Cómo funciona el conector booleano? ¿Solo une líneas con el mismo número de secuencia? Si están mezclados, ¿hay alguna forma de precedencia del operador? ¿Tiene algún caso de prueba que se base en conectores booleanos? ¿Por qué el caso de prueba que publicaste no tiene ningún número de secuencia? ¿El xcoord final siempre es inclusivo?
Peter Taylor
55
Aquí hay algunos ruidos clickety clack . ¿Recibo un bono? ;-)
Digital Trauma
1
Para el sonido, ¿estás pensando en algo como flipboards de la estación de tren? Por ejemplo, placa solari en la estación de tren gare du nord en parís o pantalla de solapa dividida - circuito de controlador de bricolaje . ¿O estás pensando en sonidos de relé más mecánicos?
Scott Leadley

Respuestas:

3

Mathematica, 306 281 bytes

Esto espera que la cadena de entrada se almacene en 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}]]]

Y aquí con un poco de espacio en blanco:

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

Esto se hizo bastante largo. Este desafío contenía muchos detalles complicados, y especialmente el análisis de entrada requiere mucho código en Mathematica (casi la mitad, 137 bytes, solo analiza la entrada). Terminé cambiando el idioma dos veces antes de instalarme en Mathematica (pensé que podría ahorrar en el análisis de entrada usando Ruby, pero luego me di cuenta de que el resultado necesita ser animado , así que volví a Mathematica).

Martin Ender
fuente
2

Ejemplo de PostScript sin golf

Este es un programa de estilo "prólogo de protocolo", por lo que los datos siguen inmediatamente en el mismo archivo fuente. Los archivos GIF animados se pueden producir con ImageMagick de convertutilidad (usos 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
fuente
La información del cuadro delimitador se descubrió mediante la ejecución gs -sDEVICE=bbox clack.ps.
luser droog