Steampunk: animação Clacker


11

No romance subestimado de Steampunk, The Difference Engine , o equivalente a casas de cinema produzia uma imagem em movimento pixelizada exibida por ladrilhos que poderiam ser invertidos mecanicamente. O mecanismo de controle para orquestrar o movimento desses ladrilhos era uma grande máquina barulhenta controlada por um baralho de cartas perfuradas.

Sua tarefa é emular esse mecanismo e exibir uma animação pixelizada, conforme especificado por um arquivo de entrada. A entrada consiste em linhas em um formato de largura fixa, mas você pode assumir o que for conveniente para uma indicação de final de linha. O formato é:

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)

A entrada é explicitamente sequenciada (se você deixar seu baralho de cartas no chão, vai me agradecer por essa parte). Isso significa que o programa deve executar uma classificação estável das linhas de entrada usando o campo de sequência como uma chave de classificação. As linhas com o mesmo número de sequência devem manter sua ordem relativa original. (Ele deve funcionar com uma classificação instável, se você anexar o número da linha real à chave.) Um campo de sequência em branco deve ser interpretado como menor que qualquer número (sequência de intercalação ascii).

Uma única linha de instrução pode afetar apenas uma única coordenada y, mas pode especificar um intervalo contíguo de valores x. O valor final x pode ser deixado em branco ou pode ser idêntico ao valor inicial para afetar um único pixel.

O opcode é um dígito hexadecimal que especifica o código da função binária universal que é usado como um rasterop. O argumento é 0 ou 1. A operação de varredura executada é

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

Portanto, o valor original do pixel entra como X na tabela UBF e o valor do argumento da instrução entra como Y. O resultado dessa função é o novo valor do pixel. E esta operação é executada em cada par x, y de xx, YY a XX, YY especificado na instrução. O intervalo especificado por xx e XX inclui os dois pontos finais. assim

0000 0 010F1

deve definir os pixels 0,1,2,3,4,5,6,7,8,9,10 na linha 0.

As dimensões de saída ( m x n ) devem ser de 20 x 20 no mínimo, mas podem ser maiores, se desejado. Mas o grão deve aparecer, sabe? É para ser pixelizada . A saída gráfica e a arte ASCII são aceitáveis.

Se, por exemplo, quisemos criar uma imagem de uma figura pixelizada:

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

   ###
   # #
   # #

Se o desenharmos com um op inofensivo, como o XOR, ele poderá ser desenhado e apagado, independentemente de a tela ser preta ou branca.

    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 sequência fará com que a figura apareça e desapareça.

NMM não é Mickey Mouse

Uma animação maior pode ser composta fora de ordem, especificando diferentes "capturas" no campo de sequência.

   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

Produção:

preto / branco vs branco / preto

Este é o pelo que o programa mais curto (por contagem de bytes) vence. Bônus (-50) se o mecanismo emitir ruídos de cliques.


3
Normalmente, solicitamos esclarecimentos postando na sandbox. Você está tentando desligar a caixa de areia?
John Dvorak

5
Para mim, pessoalmente, as caixas de areia são um beco sem saída. Sou muito bom em procrastinar para terminar. Aqui, viva, não posso ignorar o fogo debaixo da minha bunda.
Luser droog

1
Como o conector booleano funciona? Une apenas linhas com o mesmo número de sequência? Se eles são misturados, existe alguma forma de precedência do operador? Você tem algum caso de teste que depende de conectores booleanos? Por que o caso de teste que você postou não possui nenhum número de sequência? O final xcoord é sempre inclusivo?
22413 Peter Taylor

5
Aqui estão alguns ruídos de cliques . Eu recebo um bônus? ;-)
Trauma digital

1
Para o som, você está pensando em algo como flipboard da estação de trem? Por exemplo, solari board na estação de trem gare du nord em paris ou Split-flap Display - circuito de driver DIY . Ou você está pensando em sons de relé mais mecânicos?
Scott Leadley

Respostas:


3

Mathematica, 306 281 bytes

Isso espera que a string de entrada seja armazenada na variável 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}]]]

E aqui com algum espaço em branco:

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

Isso ficou muito longo. Esse desafio continha muitos detalhes complicados e, especialmente, a análise de entrada exige muito código no Mathematica (quase metade dele, 137 bytes, está apenas analisando a entrada). Acabei alternando o idioma duas vezes antes de optar pelo Mathematica (achei que poderia economizar na análise de entrada usando Ruby, mas depois percebi que o resultado precisava ser animado , então voltei ao Mathematica).


2

Exemplo de PostScript Ungolfed

Este é um "protocolo de prólogo" programa de estilo, para que os dados imediatamente a seguir, no mesmo arquivo de origem. Arquivos GIF animados podem ser produzidos com o ImageMagick convertutilidade (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

As informações da caixa delimitadora foram descobertas executando gs -sDEVICE=bbox clack.ps.
Luser droog
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.