Desenhar a escadaria do diabo


46

A Escadaria do Diabo é uma função semelhante ao fractal relacionada ao conjunto Cantor.

insira a descrição da imagem aqui

Sua tarefa é replicar essa função descolada - na arte ASCII!

Entrada

Um único inteiro n >= 0, indicando o tamanho da saída. A entrada pode ser fornecida via STDIN, argumento de função ou argumento de linha de comando.

Resultado

A versão em arte ASCII da escada do Diabo em tamanho n, retornou como uma corda ou impressa em STDOUT. Os espaços à direita no final de cada linha são válidos, mas os espaços à esquerda não. Opcionalmente, você pode imprimir uma única nova linha à direita.

Para tamanho 0, a saída é apenas:

x

(Se desejar, você pode usar qualquer outro caractere ASCII imprimível que não seja o espaço, no lugar de x.)

Para o tamanho n > 0, nós:

  • Pegue a saída de tamanho n-1e estique cada linha por um fator de três
  • Riffle entre linhas de xs
  • Desloque as linhas para a direita para que exista exatamente uma xem cada coluna, e a posição da primeira xseja mínima enquanto diminui com as linhas

Por exemplo, a saída para n = 1é:

    x
 xxx
x

Para obter a saída n = 2, esticamos cada linha por um fator de três:

            xxx
   xxxxxxxxx
xxx

Riffle entre linhas de single x:

x
            xxx
x
   xxxxxxxxx
x
xxx
x

Deslocar para a direita:

                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

Como outro exemplo, aqui está n = 3.

Pontuação

Isso é código-golfe, então a solução com o menor número de bytes vence.

Respostas:


7

Pyth, 30

jb_u+G+*leGd*HNu+N+^3hTNUQ]1]k

Este é um programa que recebe informações do STDIN e usa o método do grc para encontrar o conjunto Cantor. Usa o caractere "para exibir a curva.

Experimente online aqui.

Explicação:

Vou explicar o código em duas partes, primeiro, a geração do conjunto cantor:

u+N+^3hTNUQ]1
u        UQ]1         : reduce( ... , over range(input), starting with [1])
 +N                   : lambda N,T: N + ...
   +^3hTN             : 3 ** (T+1) + N   (int + list in pyth is interpreted as [int] + list)

E a formatação de saída:

jb_u+G+*leGd*HN    ]k
jb_                    : "\n".join(reversed(...)
   u               ]k  : reduce(lambda G,H: ... , over cantor set, starting with [""])
    +G+*leGd           : G + len(G[-1]) * " " + ...
            *HN        : H * '"'

Observe que no pyth N = '"' por padrão.


32

J ( 73 68 58 41 39 38 35 34 caracteres)

Depois de pensar sobre o problema por algum tempo, encontrei uma maneira totalmente diferente de gerar o padrão da Escadaria do Diabo. A resposta antiga, incluindo sua explicação, foi removida. Você pode examinar as revisões desta resposta para descobrir como foi.

Esta resposta retorna uma série de espaços em branco e objectos cortantes, representando a escada do diabo.

' #'{~1(]|.@=@#~[:,3^q:)2}.@i.@^>:

Aqui está a resposta dividida em duas partes em notação explícita:

f =: 3 : '|. = (, 3 ^ 1 q: y) # y'
g =: 3 : '(f }. i. 2 ^ >: y) { '' #'''

Explicação

A abordagem é um pouco diferente, então observe e se surpreenda.

  1. >: 3 - três incrementados, ou seja,

    4
    
  2. 2 ^ >: 3 - dois à potência de três incrementados, ou seja,

    16
    
  3. i. 2 ^ >: 3- os primeiros 2 ^ >: 3números inteiros, ou seja,

    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    
  4. }. i. 2 ^ 4- os primeiros 2 ^ >: 3números inteiros decapitados, ou seja,

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    

    Vamos chamar essa sequência s; nós entramos fagora.

  5. 1 q: s- os expoentes de 2 na decomposição primária de cada item de s. Em geral, x q: yproduz uma tabela dos expoentes para os primeiros xnúmeros primos na decomposição primária de y. Isso produz:

    0
    1
    0
    2
    0
    1
    0
    3
    0
    1
    0
    2
    0
    1
    0
    
  6. 3 ^ 1 q: s - três à potência desses expoentes, ou seja,

     1
     3
     1
     9
     1
     3
     1
    27
     1
     3
     1
     9
     1
     3
     1
    
  7. , 3 ^ 1 q: s- o deslocamento (isto é, o argumento com sua estrutura colapsado em um vetor) do resultado anterior. Isso é necessário porque q:introduz um eixo final indesejado. Isso gera

     1 3 1 9 1 3 1 27 1 3 1 9 1 3 1
    
  8. (, 3 ^ 1 q: s) # s- cada item sreplicado com a mesma frequência que o item correspondente no resultado anterior, ou seja,

    1 2 2 2 3 4 4 4 4 4 4 4 4 4 5 6 6 6 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 9 10 10 10 11 12 12 12 12 12 12 12 12 12 13 14 14 14 15
    
  9. = (, 3 ^ 1 q: s) # s - a auto-classificação do resultado anterior, isto é, uma matriz em que cada linha representa um dos itens únicos do argumento, cada coluna representa o item correspondente do argumento e cada célula representa se os itens da linha e da coluna são iguais, isso é,

    1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
    
  10. |. = (, 3 ^ 1 q: s) # s - o resultado anterior virou ao longo do eixo vertical.

  11. (|. = (, 3 ^ 1 q: s) # s) { ' #'- os itens do resultado anterior usados ​​como índices na matriz ' #', 0sendo substituídos por  e 1substituídos por #, ou seja,

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

    o resultado que queremos.


Dentro do loop de energia, em (,],~3^#@~.)@]vez de (1,[:,1,"0~3*]) economizar 1 byte. E se você estiver de acordo com !o char de saída em u:32+vez de ' #'{~salvar outro.
Aleatório

#\ em vez de i.@#e você ultrapassa o APL! :)
randomra

Sua segunda solução não funciona porque seria necessário um limite, mas encontrei outra maneira de vencer o APL.
FUZxxl

A nova saída é a escada para o n-1não para n.
Aleatório

@ randomra Ah ... isso é uma merda. Deixe-me ver se é corrigível.
FUZxxl

26

Hexagonia , 217 bytes

Isso foi imensamente divertido. Obrigado por postar este desafio.

Divulgação completa: o idioma (Hexagony) não existia no momento em que este desafio foi lançado. No entanto, eu não o inventei e a linguagem não foi projetada para esse desafio (ou qualquer outro desafio específico).

){_2"_{\"{{""}"{'2//_.\><*\"\/_><[\]/3\'\_;|#__/(\2\'3_'}(#:|{$#{>_\//(#={/;01*&"\\_|[##={|}$_#></)]$_##|){*_.>.(/?#//~-="{}<_"=#/\}.>"%<.{#{x\"<#_/=&{./1#_#>__<_'\/"#|@_|/{=/'|\"".{/>}]#]>(_<\'{\&#|>=&{{(\=/\{*'"]<$_

Dispostas hexagonalmente:

        ) { _ 2 " _ { \ "
       { { " " } " { ' 2 /
      / _ . \ > < * \ " \ /
     _ > < [ \ ] / 3 \ ' \ _
    ; | # _ _ / ( \ 2 \ ' 3 _
   ' } ( # : | { $ # { > _ \ /
  / ( # = { / ; 0 1 * & " \ \ _
 | [ # # = { | } $ _ # > < / ) ]
$ _ # # | ) { * _ . > . ( / ? # /
 / ~ - = " { } < _ " = # / \ } .
  > " % < . { # { x \ " < # _ /
   = & { . / 1 # _ # > _ _ < _
    ' \ / " # | @ _ | / { = /
     ' | \ " " . { / > } ] #
      ] > ( _ < \ ' { \ & #
       | > = & { { ( \ = /
        \ { * ' " ] < $ _

Na verdade, o programa não usa as #instruções, então usei esse caractere para mostrar quais células são genuinamente não utilizadas.

Como é que este programa funciona? Depende. Você quer a versão curta ou a longa?

Breve explicação

Para ilustrar o que quero dizer com "linha" e "segmento" na explicação a seguir, considere esta dissecação da saída pretendida:

segments →
 │   │ │         │ │   │x   lines
─┼───┼─┼─────────┼─┼───┼─     ↓
 │   │ │         │ │xxx│
─┼───┼─┼─────────┼─┼───┘
 │   │ │         │x│
─┼───┼─┼─────────┼─┘
 │   │ │xxxxxxxxx│
─┼───┼─┼─────────┘
 │   │x│
─┼───┼─┘
 │xxx│
─┼───┘
x│

Com isso explicado, o programa corresponde ao seguinte pseudocódigo:

n = get integer from stdin

# Calculate the number of lines we need to output.
line = pow(2, n+1)

while line > 0:
    line = line - 1

    # For all segments except the last, the character to use is spaces.
    ch = ' ' (space, ASCII 32)

    # The number of segments in each line is
    # equal to the line number, counting down.
    seg = line

    while seg > 0:
        seg = seg - 1

        # For the last segment, use x’s.
        if seg = 0:
            ch = 'x' (ASCII 120)

        # Calculate the actual segment number, where the leftmost is 1
        n = line - seg

        # Output the segment
        i = pow(3, number of times n can be divided by 2)
        i times: output ch

    output '\n' (newline, ASCII 10)

end program

Explicação longa

Consulte este diagrama de caminho de código com código de cores.

Caminho de execução

A execução começa no canto superior esquerdo. A sequência de instruções ){2'"''3''"2}?)é executada (mais alguns cancelamentos redundantes, como "{etc.), seguindo um caminho bastante complicado. Começamos com o ponteiro de instrução # 0, destacado em vermelho. No meio, passamos para o número 1, começando no canto superior direito e pintado em verde floresta. Quando o IP 2 inicia em azul centáurea (meio à direita), o layout da memória é o seguinte:

Layout de memória

Durante todo o programa, as arestas rotuladas 2a e 2b sempre terão o valor 2(as usamos para calcular 2ⁿ⁺¹ e dividir por 2, respectivamente) e a aresta rotulada 3 sempre será 3(usamos isso para calcular 3ⁱ).

Chegamos aos negócios quando entramos em nosso primeiro ciclo, destacado em azul centáurea. Este loop executa as instruções (}*{=&}{=para calcular o valor 2ⁿ⁺¹. Quando o loop sai, o caminho de sela marrom é percorrido, o que nos leva ao Ponteiro de Instrução # 3. Esse IP apenas se move ao longo da borda inferior para o oeste em amarelo dourado e logo passa o controle para o IP # 4.

O caminho fúcsia indica como o IP # 4, começando no canto inferior esquerdo, prossegue rapidamente para diminuir a linha , defina ch como 32(o caractere de espaço) e seg como (o novo valor de) linha . É devido ao decréscimo inicial que realmente começamos com 2 start-1 e, finalmente, experimentamos uma última iteração com o valor 0. Em seguida, inserimos o primeiro loop aninhado .

Voltamos nossa atenção para o índigo ramificado, onde, após um breve decréscimo de seg , vemos ch atualizado para xapenas se seg agora for zero. Depois, n é definido como line - seg para determinar o número real do segmento em que estamos. Imediatamente entramos em outro loop, desta vez na cor clara do tomate.

Aqui, calculamos quantas vezes n (o número do segmento atual) pode ser dividido por 2. Enquanto o módulo nos der zero, incrementamos ie dividimos n por 2. Quando estivermos satisfeitos, n não será mais assim divisível , ramificamos para o cinza ardósia, que contém dois loops: primeiro, aumenta 3 à potência do i calculada e, em seguida, gera ch isso muitas vezes. Observe que o primeiro desses loops contém um[instrução, que alterna o controle para o IP nº 3 - aquele que estava apenas dando pequenos passos ao longo da borda inferior anteriormente. O corpo do loop (multiplicando por 3 e decrementando) é executado por um IP solitário nº 3, preso em um ciclo interminável de verde azeitona escuro ao longo da borda inferior do código. Da mesma forma, o segundo desses loops em cinza ardósia contém uma ]instrução que ativa o IP # 5 para gerar ch e decrement, mostrados aqui em vermelho indiano escuro. Nos dois casos, os Indicadores de Instrução presos em servidão obedientemente executam uma iteração de cada vez e devolvem o controle ao IP # 4, apenas para aguardar o momento em que seu serviço seja chamado novamente. Enquanto isso, o cinza ardósia se une a seus irmãos fúcsia e índigo.

Como seg inevitavelmente chega a zero, o loop índigo sai para o caminho verde do gramado, que apenas gera o caractere de nova linha e imediatamente se funde novamente no fúcsia para continuar o loop de linha . Além da iteração final do loop de linha, encontra-se o caminho de ébano curto possível de finalizar o programa.


8
Agora, isso é simplesmente insanidade antiquada.
FUZxxl 28/09/2015

21

Python 2, 78

L=[1]
i=3
exec"L+=[i]+L;i*=3;"*input()
while L:x=L.pop();print' '*sum(L)+'x'*x

Começando com a lista L=[1], duplicamos e inserimos a próxima potência de 3 no meio, resultando em [1, 3, 1]. Isso é repetido várias nvezes para nos dar o comprimento da linha da escada do diabo. Em seguida, imprimimos cada linha preenchida com espaços.


20

APL, 38

⊖↑'x'/⍨¨D,⍨¨0,¯1↓-+\D←{1,⍨∊1,⍪3×⍵}⍣⎕,1

Exemplo:

      ⊖↑'x'/⍨¨D,⍨¨0,¯1↓-+\D←{1,⍨∊1,⍪3×⍵}⍣⎕,1
⎕:
      2
                  x
               xxx 
              x    
     xxxxxxxxx     
    x              
 xxx               
x   

Explicação:

⊖↑'x'/⍨¨D,⍨¨0,¯1↓-+\D←{1,⍨∊1,⍪3×⍵}⍣⎕,1

                                     ⎕       ⍝ read a number from the keyboard
                       {           }⍣ ,1      ⍝ apply this function N times to [1]
                               3×⍵           ⍝ multiply each value by 3
                           ∊1,⍪               ⍝ add an 1 in front of each value
                        1,⍨                  ⍝ add an 1 to the end
                     D←                      ⍝ store values in D (lengths of rows)
                   +\                        ⍝ get running sum of D
                  -                          ⍝ negate (negative values on / give spaces)
             0,¯1↓                           ⍝ remove last item and add a 0 to the beginning
                                             ⍝ (each row needs offset of total length of preceding rows)   
         D,⍨¨                                ⍝ join each offset with each row length
   'x'/⍨¨                                    ⍝ get the right number of x-es and spaces for each row
 ↑                                           ⍝ make a matrix out of the rows
⊖                                            ⍝ mirror horizontally 

Essa é uma boa solução.
FUZxxl

20
Eu amo que a explicação do código pareça uma Escada do Diabo.
18715 Alex A.

Encontrei uma solução APL ainda mais curta.
FUZxxl

14

GNU sed, 142

Não é a resposta mais curta, mas é sed !:

s/$/:/
:l
s/x/xxx/g
s/:/:x:/g
tb
:b
s/^1//
tl
s/:x/X/g
s/^/:/
:m
s/.*:([Xx]+)Xx*:$/&\1:/
tm
:n
s/([ :])[Xx](x*Xx*)/\1 \2/g
tn
s/:/\n/g
s/X/x/g

Como isso é sed (sem aritmética nativa), estou assumindo liberdades com a regra "Um único número inteiro n> = 0, indicando o tamanho da saída" . Nesse caso, o número inteiro de entrada deve ser uma sequência de 1s, cujo comprimento é n. Eu acho que isso está "indicando" o tamanho da saída, mesmo que não seja um equivalente numérico direto a n. Assim, para n = 2, a sequência de entrada será 11:

$ echo 11 | sed -rf devils-staircase.sed

                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

$ 

Isso parece completo com a complexidade de tempo exponencial de O (c n ), onde c é de cerca de 17. n = 8 levou cerca de 45 minutos para mim.


Como alternativa, se for necessário que n seja digitado exatamente numericamente, podemos fazer o seguinte:

sed, 274 bytes

s/[0-9]/<&/g
s/9/8Z/g
s/8/7Z/g
s/7/6Z/g
s/6/5Z/g
s/5/4Z/g
s/4/3Z/g
s/3/2Z/g
s/2/1Z/g
s/1/Z/g
s/0//g
:t
s/Z</<ZZZZZZZZZZ/g
tt
s/<//g
s/$/:/
:l
s/x/xxx/g
s/:/:x:/g
tb
:b
s/^Z//
tl
s/:x/X/g
s/^/:/
:m
s/.*:([Xx]+)Xx*:$/&\1:/
tm
:n
s/([ :])[Xx](x*Xx*)/\1 \2/g
tn
s/:/\n/g
s/X/x/g

Resultado:

$ echo 2 | sed -rf devils-staircase.sed

                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

$ 

7
Isso é muito legal.
FUZxxl

8

Python 2, 81

def f(n,i=1,s=0):
 if i<2<<n:q=3**len(bin(i&-i))/27;f(n,i+1,s+q);print' '*s+'x'*q

Versão do programa (88)

def f(n,s=0):
 if n:q=3**len(bin(n&-n))/27;f(n-1,s+q);print' '*s+'x'*q
f((2<<input())-1)

O número de x na n1ª linha indexada é 3 à potência de (o índice do primeiro bit definido n, iniciando no lsb).


8

Python 2, 74

def f(n,s=0):
 if~n:B=3**n;A=s+B-2**n;f(n-1,A+B);print' '*A+'x'*B;f(n-1,s)

Uma abordagem recursiva. A escada do tamanho de $ n $ diabo é dividida em três partes

  • O ramo recursivo esquerdo, uma escada de tamanho n-1, cujo comprimento é3**n - 2**n
  • A linha central de x', de comprimento3**n
  • O ramo recursivo direito, uma escada de tamanho n-1, cujo comprimento é3**n - 2**n

Observe que o comprimento total das três partes é 3*(3**n) - 2*(2**n)ou 3**(n+1) - 2**(n+1), o que confirma a indução.

A variável opcional sarmazena o deslocamento das peças atuais que estamos imprimindo. Primeiro recuamos para o ramo esquerdo com deslocamento maior, depois imprimimos a linha central e, em seguida, fazemos o ramo direito no deslocamento atual.


6

CJam, 36 35 33 bytes

Aqui está outra abordagem CJam (eu não olhei para o código do Optimizer, então não sei se é realmente muito diferente):

L0sl~{{3*0s}%0s\+}*{1$,S*\+}%W%N*

Isso usa 0para a curva. Alternativamente, (usando o truque do grc)

LLl~){3\#a1$++}/{1$,S*\'x*+}%W%N*

qual usa x.

Teste aqui.

Explicação

A idéia básica é primeiro formar uma matriz com as linhas, como

["0" "000" "0" "000000000" "0" "000" "0"]

E então, percorrer esta lista, acrescentando a quantidade certa de espaços.

L0sl~{{3*0s}%0s\+}*{1$,S*\+}%W%N*
L                                 "Push an empty string for later.";
 0s                               "Push the array containing '0. This is the base case.";
   l~                             "Read and evaluate input.";
     {           }*               "Repeat the block that many times.";
      {    }%                     "Map this block onto the array.";
       3*                         "Triple the current string.";
         0s                       "Push a new zero string.";
             0s\+                 "Prepend another zero string.";
                   {       }%     "Map this block onto the result.";
                    1$            "Copy the last line.";
                      ,S*         "Get its length and make a string with that many spaces.";
                         \+       "Prepend the spaces to the current row.";
                             W%   "Reverse the rows.";
                               N* "Join them with newlines.";

A outra versão funciona da mesma forma, mas cria uma variedade de comprimentos, como

[1 3 1 9 1 3 1]

E depois transforma isso em sequências de xs no mapa final.


6

Dyalog APL, 34 caracteres

Usando a abordagem do grc. Desenha a escada com caracteres (dominó) e recebe a entrada de stdin. Esta solução assume ⎕IO←0.

' ⌹'[(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕]
  • - pegue a entrada de stdin.
  • ⌽⍳1+⎕- a sequência dos números de baixo a 0. (por exemplo 3 2 1 0)
  • 3*⌽⍳1+⎕- três ao poder disso (por exemplo 27 9 3 1)
  • (⊢,,)/3*⌽⍳1+⎕- o resultado anterior dobrado da direita pela função tácita, ⊢,,que é igual ao dfn, {⍵,⍺,⍵}produzindo os comprimentos dos degraus da escada do diabo de acordo com a abordagem do grc.
  • {⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕ os comprimentos das etapas convertidos em etapas.
  • (∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕que a auto-classificada, como na minha solução J . Observe que já vira o resultado corretamente.
  • ' ⌹'[(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕] os números substituídos por espaços em branco e dominó.

4

Ruby, 99

Uma resposta diferente da minha outra, inspirada na resposta de FUZxxl

FUZxxl observa que os números de x correspondem ao número de fatores de 2 do índice. por exemplo para n = 2, temos a seguinte fatoração:

1 =1
2 =1 * 2
3 =3
4 =1 * 2 * 2
5 =5
6 =3 * 2
7 =7

Eu uso uma maneira bastante mais direta de extrair esses poderes de 2: o i=m&-mque produz a sequência 1 2 1 4 1 2 1etc. Isso funciona da seguinte maneira:

m-1é o mesmo que mnos bits mais significativos, mas o bit 1 menos significativo se torna zero e todos os zeros à direita se tornam 1s.

Para poder E com o original, precisamos inverter os bits. Existem várias maneiras de fazer isso. Uma maneira é subtraí-lo -1.

A fórmula geral é então m& (-1 -(m-1)) que simplifica am&(-m)

Exemplo:

          100   01100100
100-1=     99   01100011
-1-99=   -100   10011100
100&-100=   4   00000100

Aqui está o código: novas linhas são contadas, os recuos são desnecessários e, portanto, não são contados, como minha outra resposta. É um pouco mais longo do que minha outra resposta devido à conversão desajeitada da base 2: 1 2 1 4 1 2 1 etcpara a base 3: 1 3 1 9 1 3 1 etc(existe uma maneira de evitar isso Math::?)

def s(n)
  a=[]
  t=0
  1.upto(2*2**n-1){|m|i=3**Math::log(m&-m,2)
    a.unshift" "*t+"x"*i 
    t+=i}
  puts a
end

3

Ruby, 140 99

Meu segundo código Ruby, e meu primeiro uso não trivial da linguagem. Sugestões são bem-vindas. A contagem de bytes exclui espaços iniciais para recuos, mas inclui novas linhas (parece que a maioria das novas linhas não pode ser excluída, a menos que sejam substituídas por um espaço, pelo menos).

A entrada é por chamada de função. A saída é uma matriz de strings, que o ruby ​​despeja convenientemente no stdout como uma lista separada por nova linha com uma única puts.

O algoritmo é simplesmente new iteration= previous iteration+ extra row of n**3 x's+ previous iteration. No entanto, existe uma quantidade razoável de código apenas para obter os espaços iniciais na saída correta.

def s(n)
  a=["x"]
  1.upto(n){|m|t=" "*a[0].length
    a=a.map{|i|t+" "*3**m+i}+[t+"x"*3**m]+a}
  puts a
end

Edição: Ruby, 97

Isso usa a abordagem semelhante, porém diferente, de criar uma tabela numérica com todos os números de x exigidos na matriz ada maneira descrita acima, mas depois construir uma tabela de seqüências de caracteres posteriormente. A tabela de seqüências de caracteres é construída de trás para a frente na matriz cusando o unshiftmétodo de nome bastante estranho para preceder a matriz existente.

Atualmente, essa abordagem está melhor - mas apenas por 2 bytes :-)

def s(n)
  a=c=[]
  (n+1).times{|m|a=a+[3**m]+a}
  t=0
  a.each{|i|c.unshift" "*t+"x"*i
    t+=i}
  puts c
end

1
Você pode substituir for m in(0..n-1)do ... endpor n.times{|m|...}.
Omar

@ Omar Obrigado, vou tentar isso amanhã. Você não acreditaria em quanto esforço foi necessário para executar isso, devido aos constantes erros de sintaxe. Eu não sabia como acessar a variável de iteração n.timese certamente lembrarei disso. Elimina um endtambém! No entanto, nesta ocasião, eu queria saber se for m in (1..n)poderia ser melhor, para evitar o (m+1). Existe uma maneira mais curta de escrever isso?
Level River St

1
foré longo, principalmente porque você é forçado a usar end(você pode substituir dopor uma nova linha ou por ;). Para 1..nvocê poder usar 1.upto(n){|m|...}. Eu gosto da aparência, (1..n).each{|i|...}mas é um pouco mais longa do que usar upto. E observe que iterando chamando eachou uptonão é apenas mais curto, também é considerado Ruby mais idiomático.
Omar

@Obrigado novamente, 1.upto(n)é! Com isso e alguns suportes desnecessários, já estou com 120. Acho que abaixo de 100 é possível, publicarei o código revisado mais tarde.
Level River St

3

Haskell, 99 caracteres

d=q.((iterate((1:).(>>=(:[1]).(*3)))[1])!!)
q[]=[];q(a:r)=sum r&' '++a&'x'++'\n':q r
(&)=replicate

A função é d:

λ: putStr $ d 3
                                                                x
                                                             xxx
                                                            x
                                                   xxxxxxxxx
                                                  x
                                               xxx
                                              x
                   xxxxxxxxxxxxxxxxxxxxxxxxxxx
                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

Todos esses parênteses! Não há realmente nenhuma maneira de se locomover com menos?
FUZxxl

Você pode perder um byte trocando as equações por qe fazendo q x=xno caso de lista vazio. Além disso, parece que os parênteses ao redor iterate...[1]são desnecessários.
Zgarb

3

PHP - 137 bytes

function f($n){for($a=[];$i<=$n;array_push($a,3**$i++,...$a))$r=str_repeat;foreach($a as$v){$o=$r(' ',$s).$r(x,$v)."
$o";$s+=$v;}echo$o;}

Estou usando aqui o mesmo truque do grc . Aqui está a versão não destruída:

function staircase($n)
{
    $lengthsList = [];
    for ($i = 0; $i <= $n; ++$i) {
        array_push($lengthsList, 3 ** $i, ...$lengthsList);
    }

    $output = '';
    $cumulatedLength = 0;
    foreach ($lengthsList as $length)
    {
        $output = str_repeat(' ', $cumulatedLength) . str_repeat('x', $length) . "\n" . $output;
        $cumulatedLength += $length;
    }

    echo $output;
}

3**$i-> parece com o PHP 5.6. Você deve especificá-lo. Isso é incompatível com quase todas as instalações do PHP. Para economizar alguns bytes, você deve começar com $r=str_repeat;e onde tiver essa função, substituir por $r, economizando 2 bytes. Além disso, $r('x',$v)pode ser $r(x,$v)e funcionará bem (observe que eu já substituí o nome da função pela variável). Além disso, acredito que isso ++$i<=$npode ser reescrito, $n>++$ieconomizando mais um byte.
Ismael Miguel

Aqui é a sua função, com um pouco de truque legal: function f($n){$r=str_repeat;$a=[1];while($n>++$i)$a=array_merge($a,[3**$i],$a);foreach($a as$v){$o=$r(' ',$s).$r(x,$v)."\r$o";$s+=$v;}echo$o;}(em vez de ter que nova linha feio, eu adicionei a seqüência de escape \rdentro de uma string entre aspas, com a variável $o. Dentro dela Assim "\r$o"tem o mesmo byte-count como ''.$oum, com nova linha omitido na última e produz o mesmo resultado.
Ismael Miguel

Na verdade, a condição do whiledeve ser $n>$i++que essa redução funcione corretamente.
Ismael Miguel

@IsmaelMiguel O PHP 5.6 é a última versão do PHP, não preciso dizer mais nada. Não é minha culpa se quase todo mundo estiver usando uma versão antiga e se a maioria estiver usando uma versão obsoleta. Obrigado pelo $r=str_repeattruque. Eu estive pensando apenas sobre o $r='str_repeat';que não estava salvando nenhum byte. A constante indefinida também é um bom truque, bem feito;). Uma nova linha é um byte menor que a escrita \n, então eu a mantive, mas usei aspas duplas para evitar uma concatenação $0. Obrigado novamente !
Blackhole

Ficaria bem em você. Se eu não soubesse 3 ** $idisso, diria que você tem uma sintaxe terrível. Você pode resolver essa correção. Estou dizendo apenas sobre este e não o [1]porque veio do PHP5.4, que é bastante "antigo". Há um ano, peço que você especifique isso. Hoje, peço que você simplesmente especifique (em uma linha muito curta) que especifique isso. Falando sobre o código, você ainda tem o ++$i<=$nque pode ser substituído $n>$i++. Eu tive que converter todo o seu código em PHP5.3 para testá-lo. O que foi doloroso. Mas vejo que você comeu 7 bytes até agora.
Ismael Miguel

3

C, 165

#define W while
f(n){int i=n+1,j=1<<i,k=1,l,r,s,t;W(i--)k*=3;l=k-j;W(--j){r=j,s=1;W(!(r%2))r/=2,s*=3;l-=s;t=l;W(t--)putchar(32);W(++t<s)putchar(88);putchar('\n');}}

Aqui está o mesmo código descompactado e ligeiramente limpo:

int f(int n) {
    int i=n+1, j=1<<i, k=1;
    while (i--) k*=3;
    int l=k-j;
    while (--j) {
        int r=j,s=1;
        while (!(r%2))
            r/=2, s*=3;
        l-=s;
        int t=l;
        while (t--) putchar(' ');
        while (++t<s) putchar('X');
        putchar('\n');
    }
}

Isso se baseia na mesma idéia que a solução da FUZxxl para o problema, de usar um formulário explícito, e não implícito, para as linhas. A declaração de j define-a como 2 ^ (n + 1), e o primeiro loop while calcula k = 3 ^ (n + 1); então l = 3 ^ (n + 1) -2 ^ (n + 1) é a largura total da escada (não é tão difícil de provar). Passamos então por todos os números r de 1 a 2 ^ (n + 1) -1; para cada um, se é divisível por (exatamente) 2 ^ n, planejamos imprimir s = 3 ^ n 'X' s. l é ajustado para garantir que comecemos do ponto certo: escrevemos l espaços e s 'X's, depois uma nova linha.


defina W para; while e omita int para salvar alguns caracteres.
FUZxxl

também t = l- = s para economizar.
FUZxxl

@FUZxxl Tentei os dois, mas enquanto C ainda permite tipos implícitos em funções, ele não estava permitindo declarações de variáveis, mesmo com os sinalizadores 'clássicos' (pelo menos no GCC). E eu tentei #define W; while e não pareceu se importar com isso, embora eu possa ter escorregado na definição.
Steven Stadnicki

hm ... acho que você só pode omitir o tipo em uma variável global. Não traz muito para você. Você pode tentar adicionar (*p)()=putchar;no início a chamada putcharcomo p. Eu acho que isso deve resultar.
FUZxxl

2

CJam, 46 43 41 39 36 35 bytes

L0ri),(a*+_W%(;+{3\#'x*+_,S*}%$1>N*

ATUALIZE agora usando uma abordagem diferente.


Abordagem antiga:

]ri){3f*_,)"x"a*\]z:+}*_s,f{1$,U+:U-S*\N}

Bastante ingênuo e longo, mas algo para começar.

Adicionará uma explicação assim que eu jogar.

Experimente online aqui


Parece precisar de algum trabalho. Não funcionou corretamente para n = 4, 5, 17. Exibidas seqüências de rifles formatadas à esquerda de x na parte superior. Com n = 17, despejou o código na tela e encheu o fundo com x.
DavidC

1
@DavidCarraher Para 4, 5, acho que é apenas a quebra de linha. Se você copiar a saída para um editor de texto sem quebra de linha, tudo ficará bem para mim.
Sp3000

Está bem. Eu sei ver.
DavidC

2

Java, 271 269 ​​bytes

Usa o método do grc.

import java.util.*;String a(int a){List<Integer>b=new ArrayList<>();int c=-1,d=1;for(;c++<a;b.add(d),b.addAll(b),b.remove(b.size()-1),d*=3);String f="";for(;b.size()>0;f+="\n"){d=b.remove(b.size()-1);for(int g:b)for(c=0;c<g;c++)f+=' ';for(c=0;c<d;c++)f+='x';}return f;}

Recuado:

import java.util.*;
String a(int a){
    List<Integer>b=new ArrayList<>();
    int c=-1,d=1;
    for(;c++<a;b.add(d),b.addAll(b),b.remove(b.size()-1),d*=3);
    String f="";
    for(;b.size()>0;f+="\n"){
        d=b.remove(b.size()-1);
        for(int g:b)
            for(c=0;c<g;c++)
                f+=' ';
        for(c=0;c<d;c++)
            f+='x';
    }
    return f;
}

Todas as sugestões são bem-vindas.

2 bytes graças a mbomb007


Você pode usar em b.size()>0vez de !b.isEmpty(), economizando 2 bytes.
Mbomb007

1

Perl, 62

#!perl -p
eval's/x+/$&$&$&
x/g,s/\d*/x
/;'x++$_;s/x+/$"x$'=~y!x!!.$&/ge

Primeiro calcula o resultado iterativamente sem os espaços à esquerda. Em seguida, adicione-os antes de cada linha, de acordo com o número de xcaracteres no restante da string.


1

JavaScript (ES6) 104 106 118

Editar Removida a função recursiva, a lista de '*' para cada linha é obtido de forma iterativa, brincando com pedaços e poderes de 3 (como em muitas outras respostas)
Dentro do loop, uma string de múltiplas linhas é buuilt de até inferior, mantendo uma contagem de espaços à esquerda para adicionar em cada linha

F=n=>{
  for(i=a=s='';++i<2<<n;a=s+'*'.repeat(t)+'\n'+a,s+=' '.repeat(t))
    for(t=u=1;~i&u;u*=2)t*=3;
  return a
}

Primeira tentativa removida

A função R recursiva cria uma matriz com o número de '*' para cada linha. Por exemplo, R (2) é [1, 3, 1, 9, 1, 3, 1]
Esta matriz é varrida para criar uma cadeia de linhas múltiplas de baixo para cima, mantendo uma contagem contínua de espaços à esquerda para adicionar em cada linha

F=n=>
(R=n=>[1].concat(...n?R(n-1).map(n=>[n*3,1]):[]))(n)
.map(n=>a=' '.repeat(s,s-=-n)+'*'.repeat(n)+'\n'+a,a=s='')
&&a 

Teste no console Firefox / FireBug

F(3)

Resultado

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

1

R - 111 caracteres

Implementação direta, construindo a matriz iterativamente e destruindo-a lentamente.

n=scan()
a=1
if(n)for(x in 1:n)a=c(a,3^x,a)
for(A in a){cat(rep(' ',sum(a)-A),rep('x',A),'\n',sep='');a=a[-1]}

Uso:

> source('devil.r')
1: 2
2: 
Read 1 item
                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

Bom ponto, modifiquei meu código para que ele leva o nargumento da linha de comando
koekenbakker

1
Você economiza 8 bytes lendo STDIN. n=scan().
19415 Alex A.

Você não precisa declarar xusá-lo como cursor, nem precisa if(n). Além disso, as quebras de linha contam como um personagem, eu acho.
19415 freekvd

Obrigado, você está certo x. Não tenho certeza sobre if(n)no entanto. Eu adicionei essa parte para lidar com o caso n=0. O if(n)então retorna Fe, portanto, retorna um único x. Se eu removê-lo, n=0obtém resultados indesejados. Novo aqui, então não sabia sobre quebras de linha. Incluído agora!
22415 koekenbakker

Se você definir a=0e iniciar o loop x in 0:n, também funcionará para n = 0. Então você pode omitir o if(n).
22415 freekvd
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.