Introducción
Si no está familiarizado con Hexagony , es un lenguaje esotérico creado por Martin Büttner. La cuestión es que este lenguaje acepta múltiples formas para el programa. Los siguientes programas son todos equivalentes:
abcdefg
y
a b
c d e
f g
Básicamente, el código se ha enrollado en un hexágono regular. Pero tenga en cuenta que agregar un nuevo comando al código, que abcdefgh
sería el resultado en el siguiente programa:
a b c
d e f g
h . . . .
. . . .
. . .
Como puede ver, el primer paso es enrollar el código en un hexágono, y luego el hexágono se completa con no-ops ( .
) hasta el siguiente número hexagonal centrado .
Su tarea es simple, cuando se le asigna una cadena (el código fuente), genera el código fuente completo del hexágono.
Las normas
- Puede proporcionar un programa o una función.
- Se permite el espacio en blanco inicial, pero solo cuando el hexágono no se deforma
- Se permite el espacio en blanco al final.
- Tenga en cuenta que los espacios en blanco en el programa se ignoran . Entonces
a b c
es igual aabc
- Solo
32 - 126
se utilizan los caracteres ASCII imprimibles ( ), por lo que soloSpace
se ignora el carácter normal . - Suponga que la longitud de la cadena es mayor que 0.
- Este es el código de golf , por lo que gana el envío con la menor cantidad de bytes.
Casos de prueba
Input: ?({{&2'2':{):!/)'*/
Output:
? ( {
{ & 2 '
2 ' : { )
: ! / )
' * /
Input: H;e;l;d;*;r;o;Wl;;o;*433;@.>;23<\4;*/
Output:
H ; e ;
l ; d ; *
; r ; o ; W
l ; ; o ; * 4
3 3 ; @ . >
; 2 3 < \
4 ; * /
Input: .?'.) .@@/'/ .!.> +=(<.!)} ( $>( <%
Output:
. ? ' .
) . @ @ /
' / . ! . >
+ = ( < . ! )
} ( $ > ( <
% . . . .
. . . .
abc`defg
que en realidad se convertiría en pastebin.com/ZrdJmHiR`
caracteres)".Respuestas:
Pyth,
575450494846Banco de pruebas
Imprime un espacio inicial en cada línea.
Esta versión requiere una prueba de que 10 ^ n> = 3n (n - 1) + 1 para todo n> = 1 . Gracias a ANerdI y ErickWong por proporcionar pruebas.
Siguiendo estas desigualdades: 10 ^ n> (1 + 3) ^ n = 1 + 3n + 9n (n - 1) + ...> 3n (n - 1) + 1 se puede ver fácilmente que esto es correcto para n> = 2 . Examinar el caso n = 1 es bastante trivial, dando 10> 1 .
Alternativamente, tomar las derivadas de estas ecuaciones dos veces muestra que 10 ^ n tiene una segunda derivada mayor para todos n> = 1 , que luego se puede conectar en cascada a las primeras derivadas, y finalmente a las ecuaciones originales.
Explicación
fuente
Hexagonía , 271 bytes.
Te presento el primer 3% de un autointerpretador de Hexagony ...
Pruébalo en línea! También puede ejecutarlo en sí mismo, pero tardará entre 5 y 10 segundos.
En principio, esto podría encajar en la longitud lateral 9 (para una puntuación de 217 o menos), porque esto usa solo 201 comandos, y la versión no escrita que escribí primero (en la longitud lateral 30) solo necesitaba 178 comandos. Sin embargo, estoy bastante seguro de que tomaría una eternidad hacer que todo encajara, así que no estoy seguro de si realmente lo intentaré.
También debería ser posible jugar golf un poco en tamaño 10 evitando el uso de las últimas una o dos filas, de modo que se puedan omitir las operaciones no finales, pero eso requeriría una reescritura sustancial, como una de las primeras rutas une hace uso de la esquina inferior izquierda.
Explicación
Comencemos desplegando el código y anotando las rutas de flujo de control:
Eso sigue siendo bastante desordenado, así que aquí está el mismo diagrama para el código "no golfista" que escribí primero (de hecho, esto es 20 de longitud lateral y originalmente escribí el código en 30 de longitud lateral pero fue tan escaso que no sería no mejora la legibilidad en absoluto, así que lo compacté solo un poco para que el tamaño sea un poco más razonable):
Haga clic para una versión más grande.
Los colores son exactamente los mismos, aparte de algunos detalles menores, los comandos sin control de flujo también son exactamente los mismos. Así que explicaré cómo funciona esto en función de la versión sin golf, y si realmente quieres saber cómo funciona el golf, puedes verificar qué partes corresponden a cuáles en el hexágono más grande. (El único inconveniente es que el código de golf comienza con un espejo para que el código real comience en la esquina derecha hacia la izquierda).
El algoritmo básico es casi idéntico a mi respuesta CJam . Hay dos diferencias:
.
en su lugar si lo he hecho.Eso significa que la idea básica se reduce a:
N
(y el número hexagonal centrado correspondientehex(N)
) que puede contener toda la entrada.2N-1
.2N-1
). Imprima la sangría, imprima las celdas (.
si la entrada ya está agotada), imprima un salto de línea.Tenga en cuenta que solo hay no-ops, por lo que el código real comienza en la esquina izquierda (el
$
, que salta sobre el>
, por lo que realmente comenzamos en el,
camino en gris oscuro).Aquí está la cuadrícula de memoria inicial:
Entonces, el puntero de la memoria comienza en la entrada etiquetada en el borde , apuntando hacia el norte.
,
lee un byte de STDIN o un-1
si hemos golpeado EOF en ese borde. Por lo tanto,<
justo después es condicional si hemos leído toda la entrada. Permanezcamos en el bucle de entrada por ahora. El siguiente código que ejecutamos esEsto escribe un 32 en el espacio etiquetado como borde y luego lo resta del valor de entrada en el borde etiquetado como diff . Tenga en cuenta que esto nunca puede ser negativo porque estamos garantizados de que la entrada contiene solo ASCII imprimible. Será cero cuando la entrada sea un espacio. (Como lo señala Timwi, esto aún funcionaría si la entrada pudiera contener saltos de línea o pestañas, pero también eliminaría todos los demás caracteres no imprimibles con códigos de caracteres menores que 32). En ese caso,
<
desvía el puntero de instrucción (IP) a la izquierda y se toma el camino gris claro. Ese camino simplemente restablece la posición del MP{=
y luego lee el siguiente carácter, por lo tanto, se omiten los espacios. De lo contrario, si el personaje no era un espacio, ejecutamosEste primero se mueve alrededor del hexágono a través del borde de longitud hasta su lado opuesto al borde de diferencia , con
=}}}
. Luego copia el valor de enfrente del borde de longitud en el borde de longitud , y lo incrementa con)&'+'+)
. Veremos en un segundo por qué esto tiene sentido. Finalmente, movemos una nueva ventaja con=}
:(Los valores de borde particulares son del último caso de prueba dado en el desafío.) En este punto, el ciclo se repite, pero con todo desplazado un hexágono al noreste. Entonces, después de leer otro personaje, obtenemos esto:
Ahora puede ver que estamos escribiendo gradualmente la entrada (menos espacios) a lo largo de la diagonal noreste, con los caracteres en cada otro borde, y la longitud hasta ese carácter se almacena paralela al borde etiquetado como longitud .
Cuando hayamos terminado con el bucle de entrada, la memoria se verá así (donde ya he etiquetado algunos bordes nuevos para la siguiente parte):
El
%
es el último carácter que leemos, el29
es el número de caracteres no espaciales que leemos. Ahora queremos encontrar la longitud lateral del hexágono. Primero, hay un código de inicialización lineal en la ruta verde / gris oscuro:Aquí,
=&
copia la longitud (29 en nuestro ejemplo) en el borde etiquetado como longitud . Luego se''3
mueve al borde etiquetado como 3 y establece su valor en3
(que solo necesitamos como constante en el cálculo). Finalmente se{
mueve al borde etiquetado N (N-1) .Ahora entramos en el bucle azul. Este bucle se incrementa
N
(almacenado en la celda etiquetada como N ) y luego calcula su número hexagonal centrado y lo resta de la longitud de entrada. El código lineal que hace eso es:Aquí,
{)
se mueve a y en incrementos de N .')&(
se mueve al borde etiquetado como N-1 , copiaN
allí y lo disminuye.{=*
calcula su producto en N (N-1) .'*)
multiplica eso por la constante3
e incrementa el resultado en el borde etiquetado como hexadecimal (N) . Como se esperaba, este es el enésimo número hexagonal centrado. Finalmente'-
calcula la diferencia entre eso y la longitud de entrada. Si el resultado es positivo, la longitud del lado aún no es lo suficientemente grande y el bucle se repite (donde}}
mueve el MP nuevamente al borde etiquetado como N (N-1) ).Una vez que la longitud lateral es lo suficientemente grande, la diferencia será cero o negativa y obtenemos esto:
En primer lugar, ahora existe el camino verde lineal realmente largo que realiza algunas inicializaciones necesarias para el bucle de salida:
Las
{=&
aperturas de copiar el resultado en el diff borde en la longitud del borde, ya que después no necesitamos algo no positivo.}}}32
escribe un 32 en el espacio etiquetado como borde .'"2
escribe un constante 2 en el borde sin marcar arriba de diff .'=&
copiasN-1
en el segundo borde con la misma etiqueta.'*)
lo multiplica por 2 y lo incrementa para que obtengamos el valor correcto en el borde etiquetado 2N-1 en la parte superior. Este es el diámetro del hexágono.{=&')&
copia el diámetro en el otro borde etiquetado como 2N-1 . Finalmente}}
regresa al borde etiquetado 2N-1 en la parte superior.Vuelva a etiquetar los bordes:
El borde en el que estamos actualmente (que todavía mantiene el diámetro del hexágono) se usará para iterar sobre las líneas de la salida. El borde etiquetado como sangría calculará cuántos espacios se necesitan en la línea actual. Las celdas etiquetadas de borde se usarán para iterar sobre el número de celdas en la línea actual.
Ahora estamos en el camino rosado que calcula la sangría .
('-
disminuye el iterador de líneas y lo resta de N-1 (en el borde de sangría ). La rama corta azul / gris en el código simplemente calcula el módulo del resultado (~
niega el valor si es negativo o cero, y no sucede nada si es positivo). El resto del camino rosado es el"-~{
que resta la sangría del diámetro al borde de las celdas y luego vuelve al borde de la sangría .El camino amarillo sucio ahora imprime la sangría. El contenido del bucle es realmente justo
Donde se
'"
mueve al borde del espacio , lo;
imprime,{}
vuelve al sangrado y lo(
disminuye.Cuando hayamos terminado con eso, el (segundo) camino gris oscuro busca el siguiente carácter para imprimir. Los
=}
movimientos en posición (lo que significa, en el borde de las celdas , apuntando hacia el sur). Luego tenemos un bucle muy apretado del{}
cual simplemente se mueve dos bordes hacia abajo en la dirección suroeste, hasta llegar al final de la cadena almacenada:¿Te das cuenta de que he vuelto a etiquetar un borde allí EOF? . Una vez que hayamos procesado este carácter, haremos que ese borde sea negativo, de modo que el
{}
ciclo termine aquí en lugar de la siguiente iteración:En el código, estamos al final del camino gris oscuro, donde
'
retrocede un paso hacia el carácter de entrada. Si la situación es uno de los dos últimos diagramas (es decir, todavía hay un carácter de la entrada que aún no hemos impreso), entonces estamos tomando el camino verde (el inferior, para las personas que no son buenas con el verde y azul). Ese es bastante simple:;
imprime el personaje en sí.'
se mueve al borde del espacio correspondiente que todavía tiene un 32 de antes e;
imprime ese espacio. Entonces{~
hace nuestro EOF? negativo para la siguiente iteración,'
retrocede un paso para que podamos volver al extremo noroeste de la cadena con otro}{
bucle cerrado . Que termina en la longitudcelda (la no positiva debajo del hex (N) . Finalmente se}
mueve de regreso al borde de las celdas .Sin embargo, si ya hemos agotado la entrada, ¿el bucle que busca EOF? en realidad terminará aquí:
En ese caso, se
'
mueve a la celda de longitud , y en su lugar estamos tomando el camino azul claro (superior), que imprime un no-op. El código en esta rama es lineal:El
{*46;
escribe un 46 en el borde marcado no-op y lo imprime (es decir, un período). Luego se{{;
mueve al borde del espacio e imprime eso. El{{=
retrocede al borde de las celdas para la siguiente iteración.En este punto, los caminos se unen y
(
disminuye el borde de las celdas . Si el iterador aún no es cero, tomaremos el camino gris claro, que simplemente invierte la dirección del MP=
y luego busca el siguiente carácter para imprimir.De lo contrario, hemos llegado al final de la línea actual, y la IP tomará el camino púrpura en su lugar. Así es como se ve la cuadrícula de memoria en ese punto:
El camino púrpura contiene esto:
El
=
revierte la dirección del MP nuevamente.M8
establece el valor de establece en778
(porque el código de caracteres deM
is77
y dígitos se agregarán al valor actual). Esto sucede10 (mod 256)
, así que cuando lo imprimimos;
, obtenemos un salto de línea. Luego~
hace que el borde sea negativo nuevamente,'"
retrocede al borde de las líneas e=
invierte el MP una vez más.Ahora, si el borde de las líneas es cero, hemos terminado. La IP tomará la ruta roja (muy corta), donde
@
termina el programa. De lo contrario, continuamos en el camino púrpura que vuelve al rosa para imprimir otra línea.Controle los diagramas de flujo creados con HexagonyColorer de Timwi . Diagramas de memoria creados con el depurador visual en su IDE esotérico .
fuente
CJam,
56525048 bytesMi primer pensamiento fue: "¡Oye, ya tengo código para esto!" Pero entonces no podía molestarme en juntar las piezas necesarias del código Ruby, especialmente porque no parecían muy adecuadas para el golf. Así que intenté algo más en CJam en su lugar ...
Pruébalo aquí.
Explicación
Un poco de matemática sobre números hexagonales centrados primero. Si el hexágono regular tiene longitud lateral
N
, contendrá3N(N-1)+1
celdas, que deben ser iguales a la longitud del código fuentek
. Podemos resolver esoN
porque es una ecuación cuadrática simple:Podemos ignorar la raíz negativa, porque eso da un N. negativo Para que esto tenga una solución, necesitamos que la raíz cuadrada sea un medio entero. O, en otras palabras,
√(1 + 4(k-1)/3) = √((4k-1)/3)
debe ser un número entero (por suerte, este número entero es el diámetroD = 2N-1
del hexágono, que necesitaremos de todos modos). Por lo tanto, podemos agregar una sola repetidamente.
hasta que se cumpla esa condición.El resto es un bucle simple que presenta el hexágono. Una observación útil para esta parte es que los espacios en la sangría más los no espacios en el código en cada línea se suman al diámetro.
Resulta que no necesitamos usar aritmética doble (excepto la raíz cuadrada). Debido a la multiplicación por 4, no hay colisiones al dividir por 3, y el deseado
k
será el primero en producir una raíz cuadrada entera.fuente
Perl,
203200198incluye + 1 para
-p
correr como:
echo abc | perl -p file.pl
Un enfoque muy ingenuo:
;
; código en sí bajo 200 bytes ahora!$s=~/\S+/g
lugar desplit/\n/,$s
fuente
JavaScript (ES6), 162
172Función anónima
El tamaño del hexágono se encuentra resolviendo la ecuación de wikipedia
La fórmula de resolución es básicamente
Con algo de álgebra y algo de aproximación (gracias a @ user18655 también) se convierte en
Más legible
Fragmento de prueba (mejor página completa - tiempo de ejecución ~ 1 minuto)
fuente
n=...+1-1e-9|0
lugar den=Math.ceil(...)
guardar 2 bytes. También puede usar ES7 y usar en**0.5
lugar de,Math.sqrt
pero eso depende de usted. Normalmente solo guardo mis respuestas ES6 porque funcionan en mi navegador jaja!Pyth,
5251 bytesPruébalo en línea. Banco de pruebas.
Cada línea tiene un espacio inicial adicional, según lo permitido por el OP.
Explicación
fuente
Retina , 161 bytes
Gracias a FryAmTheEggman por guardar 2 bytes.
Esta respuesta no es competitiva. Retina ha visto algunas actualizaciones desde este desafío, y estoy bastante seguro de que estoy usando algunas de las funciones más nuevas (aunque no lo he comprobado).
El recuento de bytes asume la codificación ISO 8859-1. La primera línea contiene un solo espacio. Tenga en cuenta que la mayoría
·
son puntos centrales (0xB7).Pruébalo en línea!
Bien...
Explicación
Parece más fácil construir el diseño primero usando un solo carácter (
·
en este caso) y luego llenar el diseño resultante con los caracteres de entrada. Las razones principales para esto son que el uso de un solo carácter me permite hacer uso de referencias inversas y la repetición de caracteres, donde el diseño de la entrada directamente requeriría costosos grupos de equilibrio.Aunque no parece mucho, esta primera etapa elimina espacios de la entrada.
Comenzamos anteponiendo una línea adicional que contiene
M
puntos centrales, dondeM
está la longitud de la entrada (después de eliminar espacios).Si la entrada era un solo carácter, eliminamos ese punto central nuevamente. Este es un caso especial desafortunado que no está cubierto en la siguiente etapa.
Esto calcula la longitud del lado requerido
N
menos 1. Así es como funciona: los números hexagonales centrados son de la forma3*N*(N-1) + 1
. Dado que los números triangulares sonN*(N-1)/2
, eso significa que los números hexagonales son seis veces un número triangular más 1. Eso es conveniente porque hacer coincidir los números triangulares (que son realmente justos1 + 2 + 3 + ... + N
) en una expresión regular es bastante fácil con referencias directas. El(^·|\2·)*
coincide con el número triangular más grande que puede. Como un buen bono,$2
mantendrá el índice de este número triangular. Para multiplicarlo por 6, lo capturamos en grupo1
y lo combinamos otras 5 veces. Nos aseguramos de que haya al menos dos más·
con el·
y el·+
. De esta manera, el índice del número triangular encontrado no aumenta hasta que haya un carácter más que un número hexagonal centrado.Al final, esta coincidencia nos da dos menos que la longitud del lado del hexágono requerido en el grupo
$2
, por lo que escribimos de nuevo junto con un punto central más para obtenerN-1
.Esto convierte nuestra cadena de
N-1
puntos centrales enN-1
espacios,2N-1
puntos centrales y otrosN-1
espacios. Tenga en cuenta que esta es la sangría máxima, seguida del diámetro del hexágono, seguida de la sangría nuevamente.Esto es desagradablemente largo, pero básicamente solo nos da coincidencias superpuestas , que son a)
2N-1
caracteres largos y en la primera línea ob) la segunda línea. Esto expande el resultado de la etapa anterior al hexágono completo, pero extrañamente sangrado. Por ejemplo, para la entrada12345678
obtendríamos:Es por eso que también necesitábamos agregar espacios en la etapa anterior.
Esto corrige la sangría de las líneas después del centro, al sangrar repetidamente cualquier línea que sea más corta que la anterior (ignorando los espacios finales), por lo que obtenemos esto:
Ahora solo insertamos algunos espacios con
Lo que nos da:
Uff, ya está hecho.
Es hora de llenar la cadena de entrada en los puntos centrales. Esto se hace con la ayuda de una etapa de clasificación. Unimos todos los puntos centrales y cada personaje en la última línea, y los clasificamos por el resultado de la sustitución dada. Esa sustitución está vacía para los caracteres en la última línea y
·
para los puntos centrales, por lo que sucede que los puntos centrales simplemente se ordenan hasta el final (ya que la clasificación es estable). Esto mueve los caracteres de entrada a su lugar:Solo quedan dos cosas ahora:
Esto convierte los puntos centrales en períodos regulares.
Y esto descarta la última línea.
fuente
JavaScript (ES6), 144 bytes
Donde
\n
representa el carácter literal de nueva línea. Utiliza una técnica para crear un hexágono que he usado previamente en varias otras respuestas de cuadrícula hexagonal . Para ES7, tomar raíces cuadradas resulta un poco más corto que el enfoque recursivo:fuente
Python 3 , 144 bytes
Pruébalo en línea!
Esto utiliza una cantidad bastante variable de espacios en blanco iniciales para hexágonos de diferentes tamaños, pero la forma general sobrevive.
fuente