La escalera del diablo es una función de tipo fractal relacionada con el conjunto de Cantor.
Su tarea es replicar esta funky función, ¡en el arte ASCII!
Entrada
Un solo entero n >= 0
, que indica el tamaño de la salida. La entrada puede darse a través de STDIN, argumento de función o argumento de línea de comandos.
Salida
La versión de arte ASCII de la escalera del Diablo en tamaño n
, ya sea devuelta como una cadena o impresa en STDOUT. Los espacios finales al final de cada fila están bien, pero los espacios iniciales no. Opcionalmente, puede imprimir una nueva línea final.
Para el tamaño 0
, la salida es solo:
x
(Si lo desea, puede usar cualquier otro carácter ASCII imprimible que no sea espacio, en lugar de x
).
Para el tamaño n > 0
, nosotros:
- Tome la salida del tamaño
n-1
y estire cada fila por un factor de tres - Riffle entre filas de
x
s individuales - Desplace las filas hacia la derecha para que haya exactamente una
x
en cada columna, y la posición de la primerax
sea mínima mientras disminuye con las filas.
Por ejemplo, la salida para n = 1
es:
x
xxx
x
Para obtener la salida n = 2
, estiramos cada fila por un factor de tres:
xxx
xxxxxxxxx
xxx
Riffle entre filas de solteros x
:
x
xxx
x
xxxxxxxxx
x
xxx
x
Desplazar hacia la derecha:
x
xxx
x
xxxxxxxxx
x
xxx
x
Como otro ejemplo, aquí está n = 3
.
Puntuación
Este es el código de golf, por lo que gana la solución en la menor cantidad de bytes.
(,],~3^#@~.)@]
lugar de(1,[:,1,"0~3*])
guardar 1 byte. Y si está bien con!
como salida char enu:32+
lugar de' #'{~
guardar otro.#\
en lugar dei.@#
y superas APL! :)n-1
no paran
.Hexagonía , 217 bytes.
Esto fue inmensamente divertido. Gracias por publicar este desafío.
Divulgación completa: el idioma (Hexagony) no existía en el momento en que se publicó este desafío. Sin embargo, no lo inventé, y el lenguaje no fue diseñado para este desafío (o cualquier otro desafío específico).
Presentado hexagonalmente:
El programa en realidad no usa las
#
instrucciones, así que usé ese carácter para mostrar qué celdas están realmente sin usar.¿Cómo funciona este programa? Eso depende. ¿Quieres la versión corta o la larga?
Explicación breve
Para ilustrar lo que quiero decir con "línea" y "segmento" en la siguiente explicación, considere esta disección del resultado previsto:
Con eso explicado, el programa corresponde al siguiente pseudocódigo:
Larga explicación
Consulte este diagrama de ruta de código codificado por color.
La ejecución comienza en la esquina superior izquierda. La secuencia de instrucciones
){2'"''3''"2}?)
se ejecuta (más algunas cancelaciones redundantes, como"{
etc.) siguiendo una ruta bastante complicada. Comenzamos con el puntero de instrucción # 0, resaltado en carmesí. A mitad de camino, cambiamos al # 1, comenzando en la esquina superior derecha y pintados en verde bosque. Cuando IP # 2 comienza en azul aciano (centro derecha), el diseño de la memoria es el siguiente:A lo largo de todo el programa, los bordes etiquetados como 2a y 2b siempre tendrán el valor
2
(los usamos para calcular 2ⁿ⁺¹ y para dividir entre 2, respectivamente) y el borde etiquetado como 3 siempre será3
(lo usamos para calcular 3ⁱ).Llegamos a los negocios cuando entramos en nuestro primer bucle, resaltado en azul aciano. Este bucle ejecuta las instrucciones
(}*{=&}{=
para calcular el valor 2ⁿ⁺¹. Cuando sale el bucle, se toma el camino marrón de la silla de montar, que nos lleva al Puntero de instrucción n. ° 3. Esta IP simplemente se mueve a lo largo del borde inferior hacia el oeste en amarillo dorado y pronto pasa el control a la IP # 4.La ruta fucsia indica cómo IP # 4, comenzando en la parte inferior izquierda, avanza rápidamente a la línea de disminución , establece ch en
32
(el carácter de espacio) y seg en (el nuevo valor de) la línea . Es debido al decremento temprano que en realidad comenzamos con 2ⁿ⁺¹ − 1 y eventualmente experimentamos una última iteración con el valor 0. Luego ingresamos al primer bucle anidado .Dirigimos nuestra atención al índigo ramificado, donde, después de una breve disminución de seg , vemos que ch se actualiza a
x
solo si seg ahora es cero. Luego, n se establece en línea - seg para determinar el número real del segmento en el que estamos. Inmediatamente entramos en otro bucle, esta vez en el color justo del tomate.Aquí, calculamos cuántas veces se puede dividir n (el número de segmento actual) por 2. Mientras el módulo nos dé cero, incrementaremos i y dividiremos n por 2. Cuando estemos satisfechos, n ya no es divisible. , nos ramificamos en el gris pizarra, que contiene dos bucles: primero eleva 3 a la potencia del i que calculamos, y luego genera ch muchas veces. Observe que el primero de estos bucles contiene un
[
instrucción, que cambia el control a IP # 3, el que solo estaba dando pequeños pasos a lo largo del borde inferior anteriormente. El cuerpo del bucle (multiplicando por 3 y decrementando) es ejecutado por un solitario IP # 3, encarcelado en un ciclo interminable de color verde oliva oscuro a lo largo del borde inferior del código. Del mismo modo, el segundo de estos bucles de color gris pizarra contiene una]
instrucción que activa IP # 5 para generar ch y decrementar, que se muestra aquí en rojo indio oscuro. En ambos casos, los punteros de instrucción atrapados en la servidumbre ejecutan obedientemente una iteración a la vez y ceden el control de nuevo a IP # 4, solo para esperar el momento en que se solicite su servicio una vez más. El gris pizarra, mientras tanto, se une a sus hermanos fucsia e índigo.Como seg inevitablemente llega a cero, el bucle índigo sale al camino verde del césped, que simplemente genera el carácter de nueva línea y se fusiona rápidamente con el fucsia para continuar el bucle de línea . Más allá de la iteración final del bucle de línea, se encuentra el corto camino sabon ebon de la finalización final del programa.
fuente
Pitón 2, 78
Comenzando con la lista
L=[1]
, la duplicamos e insertamos la siguiente potencia de 3 en el medio, lo que resulta en[1, 3, 1]
. Esto se repite variasn
veces para darnos las longitudes de fila para la escalera del Diablo. Luego imprimimos cada fila rellenada con espacios.fuente
APL, 38
Ejemplo:
Explicación:
fuente
GNU sed, 142
No es la respuesta más corta, ¡pero es sed !:
Debido a que esto es sed (sin aritmética nativa), me estoy tomando libertades con la regla "Un solo entero n> = 0, que indica el tamaño de la salida" . En este caso, el entero de entrada debe ser una cadena de
1
s, cuya longitud es n. Creo que esto "indica" el tamaño de la salida, a pesar de que no es un equivalente numérico directo a n. Por lo tanto, para n = 2, la cadena de entrada será11
:Esto parece completarse con una complejidad de tiempo exponencial de O (c n ), donde c es aproximadamente 17. n = 8 me tomó aproximadamente 45 minutos.
Alternativamente, si se requiere que n se ingrese numéricamente exactamente, entonces podemos hacer esto:
sed, 274 bytes
Salida:
fuente
Pitón 2, 81
Versión del programa (88)
El número de x en la
n
fila indexada 1 es 3 a la potencia de (el índice del primer bit establecidon
, comenzando desde lsb).fuente
Pitón 2, 74
Un enfoque recursivo. El tamaño- $ n $ escalera del diablo se divide en tres partes
n-1
, cuya longitud es3**n - 2**n
x
', de longitud3**n
n-1
, cuya longitud es3**n - 2**n
Tenga en cuenta que la longitud total de las tres partes es
3*(3**n) - 2*(2**n)
o3**(n+1) - 2**(n+1)
, lo que confirma la inducción.La variable opcional
s
almacena el desplazamiento de las partes actuales que estamos imprimiendo. Primero recurrimos a la rama izquierda con un desplazamiento más grande, luego imprimimos la línea central, luego hacemos la rama derecha en el desplazamiento actual.fuente
CJam,
363533 bytesAquí hay otro enfoque de CJam (no he mirado el código del Optimizador, así que no sé si en realidad es muy diferente):
Esto se usa
0
para la curva. Alternativamente, (usando el truco de grc)que usos
x
.Pruébalo aquí.
Explicación
La idea básica es formar primero una matriz con las filas, como
Y luego para ir a través de esta lista, anteponiendo la cantidad correcta de espacios.
La otra versión funciona de manera similar, pero crea una variedad de longitudes, como
Y luego convierte eso en cadenas de
x
s en el mapa final.fuente
Dyalog APL, 34 caracteres
Usando el enfoque de grc. Dibuja la escalera con caracteres
⌹
(dominó) y toma datos de stdin. Esta solución asume⎕IO←0
.⎕
- tomar entrada de stdin.⌽⍳1+⎕
- la secuencia de los números de⎕
abajo a 0. (por ejemplo3 2 1 0
)3*⌽⍳1+⎕
- tres al poder de eso (por ejemplo27 9 3 1
)(⊢,,)/3*⌽⍳1+⎕
- el resultado anterior doblado desde la derecha por la función tácita⊢,,
que es igual a la dfn{⍵,⍺,⍵}
produciendo las longitudes de escalón de la escalera del diablo según el enfoque de grc.{⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕
las longitudes de paso convertidas en pasos.(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕
que la auto-clasificada, como en mi solución J . Tenga en cuenta que⊖
ya voltea el resultado correctamente.' ⌹'[(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕]
los números reemplazados por espacios en blanco y dominó.fuente
Rubí, 99
Una respuesta diferente a la otra, inspirada en la respuesta de FUZxxl
FUZxxl señala que los números de x corresponden al número de factores de 2 del índice. por ejemplo para n = 2 tenemos la siguiente factorización:
Utilizo una forma bastante más directa de extraer estos poderes de 2:
i=m&-m
que produce la secuencia,1 2 1 4 1 2 1
etc. Esto funciona de la siguiente manera:m-1
es lo mismo quem
en sus bits más significativos, pero el bit menos significativo de 1 se convierte en cero, y todos los ceros a la derecha se convierten en 1.Para poder Y esto con el original, necesitamos voltear los bits. Hay varias formas de hacer esto. Una forma es restarlo de
-1
.La fórmula general es entonces
m& (-1 -(m-1))
que se simplifica am&(-m)
Ejemplo:
Aquí está el código: las nuevas líneas se cuentan, las sangrías son innecesarias y, por lo tanto, no se cuentan, como mi otra respuesta. Es un poco más largo que mi otra respuesta debido a la torpe conversión de la base 2:
1 2 1 4 1 2 1 etc
a la base 3:1 3 1 9 1 3 1 etc
(¿hay alguna manera de evitar esoMath::
?)fuente
Rubí,
14099Mi segundo código Ruby, y mi primer uso no trivial del lenguaje. Las sugerencias son bienvenidas. El recuento de bytes excluye los espacios iniciales para las sangrías, pero incluye nuevas líneas (parece que la mayoría de las nuevas líneas no se pueden eliminar a menos que se reemplacen por un espacio al menos).
La entrada es por llamada de función. La salida es una matriz de cadenas, que Ruby volca convenientemente en stdout como una lista separada por una nueva línea con una sola
puts
.El algoritmo es simplemente
new iteration
=previous iteration
+extra row of n**3 x's
+previous iteration
. Sin embargo, hayuna grancantidad de código solo para obtener los espacios iniciales en la salida correcta.Editar: Ruby, 97
Esto utiliza el enfoque similar pero diferente de construir una tabla numérica de todos los números de x requeridos en la matriz
a
de la manera descrita anteriormente, pero luego construir una tabla de cadenas después. La tabla de cadenas se construye hacia atrás en una matrizc
utilizando elunshift
método con un nombre bastante extraño para anteponer a la matriz existente.Actualmente este enfoque se ve mejor, pero solo por 2 bytes :-)
fuente
for m in(0..n-1)do ... end
conn.times{|m|...}
.n.times
y ciertamente lo recordaré. ¡También elimina unend
! Sin embargo, en esta ocasión me preguntaba sifor m in (1..n)
podría ser mejor, para evitar el(m+1)
. ¿Hay una forma más corta de escribir eso?for
es largo principalmente porque está obligado a usarloend
(puede reemplazarlodo
con una nueva línea o con;
). Para1..n
que puedas usar1.upto(n){|m|...}
. Me gusta el aspecto de(1..n).each{|i|...}
pero es un poco más largo que el usoupto
. Y tenga en cuenta que iterar llamandoeach
oupto
no solo es más corto, también se considera Ruby más idiomático.1.upto(n)
lo es! Con eso y algunos paréntesis innecesarios eliminados, ya estoy por debajo de 120. Creo que por debajo de 100 es posible, publicaré el código revisado más tarde.Haskell, 99 caracteres
La función es
d
:fuente
q
y haciendoq x=x
en el caso de la lista vacía. Además, parece que los paréntesisiterate...[1]
son innecesarios.PHP - 137 bytes
Estoy usando aquí el mismo truco que grc . Aquí está la versión sin golf:
fuente
3**$i
-> se siente como PHP 5.6. Deberías especificarlo. Esto es incompatible con casi todas las instalaciones de PHP. Para ahorrarle unos pocos bytes, debe comenzar con$r=str_repeat;
y donde puede tener esa función, puede reemplazar con$r
, ahorrando 2 bytes. Además,$r('x',$v)
puede ser$r(x,$v)
y funcionará bien (tenga en cuenta que ya he reemplazado el nombre de la función con la variable). Además, creo que++$i<=$n
se puede reescribir como$n>++$i
guardar otro 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;}
(en lugar de tener esa nueva línea fea, he agregado la secuencia de escape\r
dentro de una cadena entre comillas dobles, con la variable$o
dentro de ella. Por lo tanto,"\r$o"
tiene el mismo conteo de bytes que el''.$o
, con nueva línea omitida en la última y produce el mismo resultado.while
tiene que ser$n>$i++
para que esta reducción funcione correctamente.$r=str_repeat
truco. Solo he estado pensando$r='str_repeat';
, lo que no estaba guardando ningún byte. La constante indefinida es un buen truco también, bien hecho;). Una nueva línea es un byte más pequeña que la escritura\n
, así que la he guardado, pero he usado comillas dobles para evitar una concatenación$0
. Gracias de nuevo !3 ** $i
esto, diría que tiene una sintaxis terrible. Puede abordar esa corrección. Solo digo sobre esto y no[1]
porque proviene de PHP5.4, que es bastante 'viejo'. Hace 1 año, le pediría que especifique eso. Hoy, le pido que simplemente especifique (en una línea muy corta) que especifica esto. Hablando sobre el código, todavía tiene el++$i<=$n
que se puede reemplazar$n>$i++
. Tuve que convertir todo su código en PHP5.3 para probarlo. Lo cual fue doloroso. Pero veo que comiste 7 bytes hasta ahora.C, 165
Aquí está el mismo código desempaquetado y ligeramente limpiado:
Esto se basa en la misma idea que la solución de FUZxxl al problema, de usar una forma explícita en lugar de implícita para las filas. La declaración de j lo establece en 2 ^ (n + 1), y el primer ciclo while calcula k = 3 ^ (n + 1); entonces l = 3 ^ (n + 1) -2 ^ (n + 1) es el ancho total de la escalera (esto no es demasiado difícil de probar). Luego pasamos por todos los números r del 1 al 2 ^ (n + 1) -1; para cada uno, si es divisible por (exactamente) 2 ^ n, entonces planeamos imprimir s = 3 ^ n 'X's. l se ajusta para garantizar que comencemos desde el lugar correcto: escribimos l espacios y s 'X's, luego una nueva línea.
fuente
(*p)()=putchar;
al principio para llamarputchar
comop
. Creo que debería funcionar.CJam,
46 43 41 39 3635 bytesACTUALIZAR usando un enfoque diferente ahora.
Viejo enfoque:
Bastante ingenuo y largo, pero algo para comenzar.
Agregaré una explicación una vez que lo juegue.
Pruébalo en línea aquí
fuente
Java,
271269 bytesUtiliza el método de grc.
Sangrado:
Cualquier sugerencia es bienvenida.
2 bytes gracias a mbomb007
fuente
b.size()>0
lugar de!b.isEmpty()
guardar 2 bytes.Perl, 62
Primero calcula el resultado iterativamente sin los espacios iniciales. Luego los agrega antes de cada línea de acuerdo con el número de
x
caracteres en el resto de la cadena.fuente
JavaScript (ES6) 104
106 118Editar Se eliminó la función recursiva, la lista de '*' para cada línea se obtiene de forma iterativa, jugando con bits y potencias de 3 (como en muchas otras respuestas)
Dentro del bucle, una cadena multilínea se construye de abajo hacia arriba, manteniendo un recuento continuo de espacios iniciales para agregar en cada línea
Primer intento eliminado
La función R recursiva crea una matriz con el número de '*' para cada línea. Por ejemplo, R (2) es
[1, 3, 1, 9, 1, 3, 1]
Esta matriz se escanea para construir una cadena de varias líneas de abajo hacia arriba, manteniendo un recuento continuo de espacios iniciales para agregar en cada línea
Prueba en la consola Firefox / FireBug
Salida
fuente
R - 111 caracteres
Implementación directa, construyendo la matriz de forma iterativa y destruyéndola lentamente.
Uso:
fuente
n
argumento de la línea de comandon=scan()
.x
su uso como cursor, ni lo necesitaif(n)
. Además, los saltos de línea cuentan como un personaje, creo.x
. Sinif(n)
embargo, no estoy seguro . Agregué esa parte para tratar el cason=0
. Elif(n)
entonces regresaF
y, por lo tanto, devuelve un solox
. Si lo elimino,n=0
da resultados no deseados. Nuevo aquí, así que no sabía sobre saltos de línea. Incluido ahora!a=0
e inicia el ciclo enx in 0:n
, también funciona para n = 0. Entonces puedes omitir elif(n)
.