A Escadaria do Diabo é uma função semelhante ao fractal relacionada ao conjunto Cantor.
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-1
e estique cada linha por um fator de três - Riffle entre linhas de
x
s - Desloque as linhas para a direita para que exista exatamente uma
x
em cada coluna, e a posição da primeirax
seja 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.
(,],~3^#@~.)@]
vez de(1,[:,1,"0~3*])
economizar 1 byte. E se você estiver de acordo com!
o char de saída emu:32+
vez de' #'{~
salvar outro.#\
em vez dei.@#
e você ultrapassa o APL! :)n-1
não paran
.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).
Dispostas hexagonalmente:
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:
Com isso explicado, o programa corresponde ao seguinte pseudocódigo:
Explicação longa
Consulte este diagrama de caminho de código com código de cores.
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: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
x
apenas 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.
fonte
Python 2, 78
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áriasn
vezes para nos dar o comprimento da linha da escada do diabo. Em seguida, imprimimos cada linha preenchida com espaços.fonte
APL, 38
Exemplo:
Explicação:
fonte
GNU sed, 142
Não é a resposta mais curta, mas é sed !:
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
1
s, 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
: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
Resultado:
fonte
Python 2, 81
Versão do programa (88)
O número de x na
n
1ª linha indexada é 3 à potência de (o índice do primeiro bit definidon
, iniciando no lsb).fonte
Python 2, 74
Uma abordagem recursiva. A escada do tamanho de $ n $ diabo é dividida em três partes
n-1
, cujo comprimento é3**n - 2**n
x
', de comprimento3**n
n-1
, cujo comprimento é3**n - 2**n
Observe que o comprimento total das três partes é
3*(3**n) - 2*(2**n)
ou3**(n+1) - 2**(n+1)
, o que confirma a indução.A variável opcional
s
armazena 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.fonte
CJam,
363533 bytesAqui está outra abordagem CJam (eu não olhei para o código do Optimizer, então não sei se é realmente muito diferente):
Isso usa
0
para a curva. Alternativamente, (usando o truque do grc)qual usa
x
.Teste aqui.
Explicação
A idéia básica é primeiro formar uma matriz com as linhas, como
E então, percorrer esta lista, acrescentando a quantidade certa de espaços.
A outra versão funciona da mesma forma, mas cria uma variedade de comprimentos, como
E depois transforma isso em sequências de
x
s no mapa final.fonte
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
.⎕
- pegue a entrada de stdin.⌽⍳1+⎕
- a sequência dos números de⎕
baixo a 0. (por exemplo3 2 1 0
)3*⌽⍳1+⎕
- três ao poder disso (por exemplo27 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ó.fonte
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:
Eu uso uma maneira bastante mais direta de extrair esses poderes de 2: o
i=m&-m
que produz a sequência1 2 1 4 1 2 1
etc. Isso funciona da seguinte maneira:m-1
é o mesmo quem
nos 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:
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 etc
para a base 3:1 3 1 9 1 3 1 etc
(existe uma maneira de evitar issoMath::
?)fonte
Ruby,
14099Meu 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, existeuma quantidaderazoável de código apenas para obter os espaços iniciais na saída correta.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
a
da 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 matrizc
usando ounshift
método de nome bastante estranho para preceder a matriz existente.Atualmente, essa abordagem está melhor - mas apenas por 2 bytes :-)
fonte
for m in(0..n-1)do ... end
porn.times{|m|...}
.n.times
e certamente lembrarei disso. Elimina umend
também! No entanto, nesta ocasião, eu queria saber sefor m in (1..n)
poderia ser melhor, para evitar o(m+1)
. Existe uma maneira mais curta de escrever isso?for
é longo, principalmente porque você é forçado a usarend
(você pode substituirdo
por uma nova linha ou por;
). Para1..n
você poder usar1.upto(n){|m|...}
. Eu gosto da aparência,(1..n).each{|i|...}
mas é um pouco mais longa do que usarupto
. E observe que iterando chamandoeach
ouupto
não é apenas mais curto, também é considerado Ruby mais idiomático.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.Haskell, 99 caracteres
A função é
d
:fonte
q
e fazendoq x=x
no caso de lista vazio. Além disso, parece que os parênteses ao redoriterate...[1]
são desnecessários.PHP - 137 bytes
Estou usando aqui o mesmo truque do grc . Aqui está a versão não destruída:
fonte
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<=$n
pode ser reescrito,$n>++$i
economizando mais um byte.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\r
dentro de uma string entre aspas, com a variável$o
. Dentro dela Assim"\r$o"
tem o mesmo byte-count como''.$o
um, com nova linha omitido na última e produz o mesmo resultado.while
deve ser$n>$i++
que essa redução funcione corretamente.$r=str_repeat
truque. 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 !3 ** $i
disso, 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<=$n
que 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.C, 165
Aqui está o mesmo código descompactado e ligeiramente limpo:
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.
fonte
(*p)()=putchar;
no início a chamadaputchar
comop
. Eu acho que isso deve resultar.CJam,
46 43 41 39 3635 bytesATUALIZE agora usando uma abordagem diferente.
Abordagem antiga:
Bastante ingênuo e longo, mas algo para começar.
Adicionará uma explicação assim que eu jogar.
Experimente online aqui
fonte
Java,
271269 bytesUsa o método do grc.
Recuado:
Todas as sugestões são bem-vindas.
2 bytes graças a mbomb007
fonte
b.size()>0
vez de!b.isEmpty()
, economizando 2 bytes.Perl, 62
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
x
caracteres no restante da string.fonte
JavaScript (ES6) 104
106 118Editar 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
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
Teste no console Firefox / FireBug
Resultado
fonte
R - 111 caracteres
Implementação direta, construindo a matriz iterativamente e destruindo-a lentamente.
Uso:
fonte
n
argumento da linha de comandon=scan()
.x
usá-lo como cursor, nem precisaif(n)
. Além disso, as quebras de linha contam como um personagem, eu acho.x
. Não tenho certeza sobreif(n)
no entanto. Eu adicionei essa parte para lidar com o cason=0
. Oif(n)
então retornaF
e, portanto, retorna um únicox
. Se eu removê-lo,n=0
obtém resultados indesejados. Novo aqui, então não sabia sobre quebras de linha. Incluído agora!a=0
e iniciar o loopx in 0:n
, também funcionará para n = 0. Então você pode omitir oif(n)
.