Los quipus son un dispositivo antiguo utilizado por los incas en la era precolombina para registrar números en un sistema de nudos posicionales de base diez en un cordón, que funciona de la siguiente manera:
Cada grupo de nudos es un dígito, y hay tres tipos principales de nudos: nudos simples por encima de la cabeza; "nudos largos", que consisten en un nudo por encima de la cabeza con uno o más giros adicionales; y figura de ocho nudos.
- Las potencias de diez se muestran por posición a lo largo de la cuerda, y esta posición se alinea entre hilos sucesivos.
- Los dígitos en posiciones para 10 y más potencias están representados por grupos de nudos simples (por ejemplo, 40 son cuatro nudos simples en una fila en la posición "decenas").
- Los dígitos en la posición "unos" están representados por nudos largos (por ejemplo, 4 es un nudo con cuatro vueltas). Debido a la forma en que se atan los nudos, el dígito 1 no se puede mostrar de esta manera y se representa en esta posición mediante un nudo en forma de figura de ocho.
- El cero está representado por la ausencia de un nudo en la posición adecuada.
Detalles
Para este desafío, cada capítulo de un quipu representa un solo número (aunque, como dice el artículo de Wikipedia, puede representar muchos números en un capítulo, en este desafío, no lo haremos).
Nudos
Cada nudo estará representado por un único carácter ASCII.
.
representa un nudo simple:
representa una vuelta de un nudo largo8
representa un nudo en forma de ocho|
representa la ausencia de un nudo y un delimitador entre los dígitos.
Construyendo Quipus
Los quipu se construyen siguiendo estas reglas.
- Los filamentos van de arriba a abajo en orden descendente de posición (como en, el dígito de las unidades estará en el extremo inferior de un filamento). Los dígitos a lo largo de una cadena están separados por el carácter (
|
). - La potencia de 10 que representa un dígito está determinada por su posición a lo largo de la cadena de la misma manera que la potencia de un dígito de 10 se calcularía utilizando su índice en un número con nuestro sistema de números. Es decir,
24
con a2
en el lugar de las decenas y a4
en el lugar de las unidades, estará representado por dos nudos, un delimitador (|
), luego cuatro nudos. - Los dígitos en la misma posición están alineados hacia la parte inferior del hilo. Si un dígito en una posición tendrá menos nudos que otros dígitos de otros números en la misma posición, la ausencia de esos nudos está representada por (
|
). - Los nudos simples consecutivos (
.
) representan un valor en su posición. - Cada dígito está representado por al menos 1 carácter. Cuando un valor de dígitos es 0 para todos los números en un quipu, se representa por la ausencia de un nudo (
|
). - El lugar de las unidades es tratado especialmente. Uno en el lugar de las unidades está representado por un nudo de figura ocho (
8
). Un valor de dos o más en el lugar de las unidades está representado por nudos largos consecutivos (:
). - Cuando el dígito de las unidades es 0 para todos los números en un quipu, no se imprime la ausencia de un nudo, pero se conserva el delimitador final para el dígito de las decenas.
- No hay delimitador después del dígito de las unidades.
Reglas
- La entrada consistirá en una lista no vacía de enteros no negativos que se pueden recibir a través de cualquiera de los métodos de entrada predeterminados . Puede suponer que estos enteros son todos menores o iguales que
2147483647
o2^31-1
. Si bien los casos de prueba están delimitados por espacios, su formato de entrada puede separar las entradas de cualquier manera que sea conveniente para su idioma, ya sea separadas por comas, separadas por nueva línea, en una matriz, etc. - La salida consiste en un Quipu único construido de acuerdo con las reglas descritas anteriormente. La salida puede darse a través de cualquiera de los métodos de salida predeterminados .
- Su código debe ser un programa o una función, aunque no es necesario que sea una función con nombre.
- Los nudos tardan un tiempo en unirse para ahorrar tiempo, su código lo más corto posible.
Como siempre, si el problema no está claro, hágamelo saber. ¡Buena suerte y buen golf!
Ejemplos
Entrada:
5 3 1 0
Salida:
:|||
:|||
::||
::||
::8|
Entrada:
50 30 10 0
Salida:
.|||
.|||
..||
..||
...|
||||
Entrada:
330
Salida:
.
.
.
|
.
.
.
|
Entrada:
204 1
Salida:
.|
.|
||
||
||
:|
:|
:|
:8
Entrada:
201 0 100 222
Salida:
.||.
.|..
||||
|||.
|||.
||||
|||:
8||:
Entrada:
1073741823 2147483647
Salida:
|.
..
||
|.
||
.|
.|
.|
..
..
..
..
||
|.
|.
|.
|.
..
..
..
||
.|
.|
.|
..
..
..
..
||
|.
|.
|.
|.
..
..
..
..
||
|.
|.
..
||
.|
.|
..
..
..
..
..
..
||
|.
|.
..
..
||
|:
|:
|:
|:
::
::
::
Entrada:
0
Salida:
|
Respuestas:
Pyth, 64 bytes
Pruébalo en línea!
Cómo funciona
fuente
8
. De hecho, es solo un8
nudo cuando el último dígito es un 1 (ver la regla 6). Estás convirtiendo todos los nudos finales y eso no coincide con las especificaciones. Además, ¡pruébalo en línea! el enlace tiene un código diferente del que se publica aquí, aparentementeIlegible ,
31833001 bytesFue un desafío divertido trabajar dentro y fuera de las celebraciones navideñas. ¡Gracias por tu publicación! Jugar al golf fue interesante porque la especificación está llena de excepciones y casos especiales, que requieren muchas condiciones. Además, aunque esta vez no necesitaba convertir ay desde decimal, sí necesitaba una especie de función "máxima" para determinar el mayor número de dígitos en cada número y el mayor valor de los dígitos en cada lugar.
La primera versión de esto era 4844 bytes, solo para darte una idea de cuánto jugué al golf.
El programa espera la entrada como una lista de enteros separados por comas . Sin espacios ni líneas nuevas. Usarlos producirá un comportamiento indefinido.
Explicación
Le explicaré cómo funciona el programa mostrándole cómo procesa la entrada específica
202,100,1
.Al principio, construimos algunos valores que necesitaremos más tarde, principalmente los códigos ASCII de los caracteres que mostraremos.
Como puedes ver,
'8'
ya'.'
están disponibles.'|'
, sin embargo, es realmente 124, no 14. Usamos un ciclo while para agregar dos veces el valor temporal en la ranura # 1 para obtener 124 (que es 14 + 55 × 2, porque el ciclo while se ejecuta para 56−1 = 55 iteraciones). Esto ahorra algunos bytes porque los literales enteros grandes como 124 son realmente largos. En el siguiente diagrama, muestro la ubicación de cada variable que usa el programa.A continuación, queremos ingresar todos los caracteres y almacenarlos en la cinta comenzando en la celda # 12 ( p es el puntero en ejecución para esto). Al mismo tiempo, queremos saber cuánto mide el número más largo (cuántos dígitos). Para lograr esto, mantenemos un total acumulado en unario que va hacia la izquierda comenzando en la celda # -1 (usamos q como el puntero en ejecución). Después del primer número de entrada (
202
), la cinta ahora se ve así:Habrás notado que los números están apagados en 4. Bueno, cuando los ingresamos por primera vez, son sus valores ASCII, por lo que están "apagados" en 48 y la coma es 44. Para cada carácter, copiamos el 46 de
'.'
en r y luego lo restamos con un ciclo while (que resta 45) y luego sumamos 1. Hacemos eso para que la coma (nuestro separador) sea 0, de modo que podamos usar un condicional para reconocerlo.Además, habrás notado que dejamos la celda # 11 en 0. Necesitamos eso para reconocer el límite del primer número.
El siguiente personaje será una coma, por lo que almacenamos un 0 en el n. ° 15, pero, por supuesto, esta vez no avanzamos q . En cambio, establecemos q nuevamente en 0 y comenzamos a "sobrescribir" los 1 que ya hemos colocado.
Después de que se procesen todos los caracteres restantes, obtenemos esto:
Como puede ver, los 1 escritos por q ahora indican (en unario) la longitud del número más largo.
Ahora usamos un bucle while para mover q a la izquierda y luego colocamos otro puntero allí al que llamaré r2 . El propósito de r2 quedará claro más adelante.
En este punto, permítanme aclarar la terminología que usaré a lo largo de esto.
Ahora volvamos a nuestra programación regular. El resto del programa es un gran bucle que avanza q hacia adelante hasta llegar a la celda # 0. Cada una de las celdas en el camino representa un lugar, con las que están ubicadas en el extremo derecho, y q comenzará en el más significativo. En nuestro ejemplo, ese es el lugar de los cientos.
Procedemos incrementando los puntos q de la celda en (es decir, * q ).
Ahora estamos en la "etapa 2" para el lugar de los cientos. En esta etapa, descubriremos cuál es el dígito más grande entre todos los dígitos en el lugar de las centenas. Utilizamos el mismo truco de conteo unario para esto, excepto que esta vez el puntero se llama r y el puntero r2 marca su posición inicial a la que debemos restablecerlo cada vez que pasamos al siguiente número.
Comencemos con el primer número. Comenzamos configurando p en 11 (la posición inicial codificada de todos los números). Luego usamos un ciclo while para encontrar el final del número y establecemos p2 allí para marcar la posición. Al mismo tiempo, también establecemos q2 en 0:
No se distraiga por el hecho de que q2 apunta hacia los vars. No tenemos un relleno de una celda en blanco allí porque podemos detectar la celda # 0 simplemente porque es el número cero.
A continuación, revisamos el número actual disminuyendo p y q2 juntos hasta que * p sea cero. En cada lugar, el valor de * q2 nos dice lo que debemos hacer. 1 significa "no hacer nada", así que seguimos adelante. Finalmente encontramos el 2 en la celda # −3. Cada vez que * q2 no es igual a 1, q2 siempre es igual a q .
Como ya dije, la etapa 2 es "determinar el dígito más grande en este lugar". Por lo tanto, configuramos r en r2 , usamos un bucle while para disminuir * p y movemos r hacia la izquierda y llenamos la cinta con 1s, y luego usamos otro bucle while para mover r de nuevo a la derecha e incrementar * p nuevamente para restaurar el valor. Recuerde que cada ciclo while se ejecuta por una iteración menos que el valor en el que lo usamos; debido a esto, el número de 1s escritos será 3 más (en lugar de 4 más) que el valor del dígito, y el valor final almacenado de nuevo en * p será 2 más. Por lo tanto, esto ha disminuido efectivamente * p en 2.
Después de eso, establecemos p en el valor de p2 y luego hacemos todo eso nuevamente. Por segunda vez, establezca q2 en 0, encuentre el final del número moviendo p hacia la derecha y luego pase por los dígitos de este número decrementando p y q2 juntos. Una vez más, encontraremos el 2 en la celda # −3 y escribiremos los muchos 1 restantes de * r .
En el caso del tercer número, terminamos sin hacer nada porque no tiene un lugar de cientos (por lo que q2 nunca llega a q ), pero está bien porque eso no afecta el cálculo del valor máximo de dígitos.
También configuramos la celda * (r - 4) , que he marcado con una flecha sin etiqueta aquí, a 1 (aunque ya está en 1). No voy a decirte por qué todavía, pero ¿tal vez ya lo has adivinado?
El siguiente incremento de * q nos lleva a la etapa 3, que es "restar el dígito máximo de todos los dígitos en el lugar actual". Como antes, reiniciamos p a 11 y q2 a 0 y luego revisamos todos los números tal como lo hicimos en la etapa anterior; excepto esta vez, * q = 3 en lugar de 2. Cada vez que q2 se encuentra con q y p está en un lugar de cientos, usamos un bucle while para disminuir * p tantas veces como haya 1s en el bloque a la izquierda de * r2 (5 en nuestro ejemplo) usando rcomo un puntero corriendo. De hecho, lo decrementamos una vez más para que el dígito más grande termine en −2, por una razón que se aclarará más adelante:
Después de haber procesado todos los números, ahora estamos al final de la etapa 3. Aquí realizamos dos cosas singulares.
Ahora comprende que seguimos revisando los números, encontramos el lugar actual (indicado por el valor distinto de 1 de * q ) dentro de cada número y hacemos algo según el valor de * q . Vemos que * q se incrementa primero a 2 (= calcular el valor de dígito máximo), luego a 3 (restar el valor de dígito máximo de cada dígito en este lugar) y luego lo restamos para que sea negativo. A partir de ahí, continuará subiendo hasta llegar a 1, restaurando así el valor que significa "no hacer nada". En ese punto, pasamos al siguiente lugar.
Ahora, cuando * q es negativo, estamos generando. * q tiene exactamente el valor correcto para que generemos el número correcto de filas de caracteres antes de que llegue a 1; Si el dígito más grande es 2, necesitamos generar 3 filas. Veamos qué sucede en cada valor de * q :
'.'
(punto) o un':'
(dos puntos). Decidimos qué al mirar q : si es −1, estamos en el lugar de las unidades, por lo que genera a':'
(que calculamos como'8'
+2), de lo contrario a'.'
.'|'
(tubería) y luego incrementamos el valor. De esta forma alcanzará −2 en el lugar correcto y luego sacaremos'.'
s /':'
s para el resto de ese dígito.'|'
(pero solo si out no es cero, porque de lo contrario todavía estamos en la etapa 2 o 3).'.'
(y el tercero genera a'|'
como antes).'|'
s independientemente de * p ". De esta manera obtenemos el relleno entre los dígitos.Ahora incrementamos q para pasar al siguiente lugar, el lugar de las decenas, e incrementamos * q allí. Al comienzo de la Etapa 2, la cinta se ve así:
Luego realizamos la Etapa 2 igual que antes. Recuerde que esto resta efectivamente 2 de cada dígito en este lugar y también deja un número unario a la izquierda de * r2 que indica el dígito máximo. Dejamos solo el número unario anterior y seguimos extendiendo la cinta hacia la izquierda; solo costaría un código adicional innecesario para "limpiar". Cuando terminamos e incrementamos * q , al comienzo de la Etapa 3 la cinta ahora es:
En realidad, esto es una mentira. ¿Recuerdas antes dónde dije que establecimos * (r - 4) en 1 y no te dije por qué? Ahora te diré por qué. Es para casos como este, donde el dígito más grande es de hecho 0, lo que significa que todos los dígitos en este lugar son 0. La configuración * (r - 4) , indicada por la flecha sin etiqueta arriba, a 1 extiende el número unario en 1, pero solo en este caso especial. De esta manera, simulamos que el dígito más grande era 1, lo que significa que mostraremos una fila adicional.
Después de la Etapa 3 (restar el dígito máximo de todos los dígitos en el lugar actual), incluido el paso adicional que hace * q negativo, la cinta se ve así. La última vez que el dígito más grande fue representado por −2 en el bloque * p , pero esta vez son todos −3 porque en realidad todos son ceros, pero estamos fingiendo que el dígito máximo era un 1.
Ahora veamos qué sucede cuando * q avanza hacia 1:
'|'
sy los incrementamos.'|'
porque eso es lo que siempre hacemos cuando * q = 0, independientemente de * p .Por lo tanto, obtenemos dos filas de tuberías.
Finalmente, nos movemos * q a su lugar. Este se pone interesante porque necesitamos generar
':'
s si el dígito real es cualquier cosa menos 1, y'8'
si es 1. Veamos cómo procede el programa. Primero, incrementamos * q para iniciar la Etapa 2:Después de la Etapa 2 ("calcular el valor máximo de dígitos"), nos queda esto:
Después de la Etapa 3 ("restar el valor máximo de dígitos de todos los dígitos en el lugar actual") la cinta se ve así:
Ahora veamos cada iteración de * q a su vez:
':'
(en lugar de a'.'
porque q = −1).'|'
e incrementa'|'
. Sin embargo, esta vez, en lugar de aumentar, se desencadena un caso especial. Solo si estamos generando el último lugar ( q = −1), y estamos en la penúltima fila para eso ( * q = −2), y el dígito es en realidad un 1 ( * p = −3) , luego , en lugar de incrementarlo a −2, lo configuramos a −1. En otras palabras, usamos -1 como un valor especial para indicar que en la próxima iteración, tendremos que generar en'8'
lugar de':'
.':'
.'|'
. La condición especial no se activa porque * q ya no es −2. Por lo tanto, incremente.'8'
.'|'
s aquí, pero en el caso especial en el que estamos en el lugar de las unidades ( q = −1), nos saltamos eso.Después de esto, q se incrementa a 0 y finaliza el ciclo grande while.
Ahora ya sabes cómo funciona una entrada como
202,100,1
. Sin embargo, hay un caso especial más que todavía no hemos cubierto. Puede recordar que mientras procesábamos el último lugar, cuando * p era −3 lo configuramos en −1 para el1
(en lugar de incrementarlo a −2) para que la siguiente iteración produzca un'8'
en su lugar. Esto solo funciona porque tenemos una iteración en la que * p es −3 y tomamos una decisión sobre si aumentarlo o establecerlo en −1. Nosotros no tenemos una iteración como si todos los dígitos en el lugar de las unidades son 0 ó 1. En este caso, todos los * p valores para los 1s se comienza a cabo a -2; no hay oportunidad de decidir establecerlo en −1en lugar de incrementarlo desde −3 . Debido a esto, hay otra condición de carcasa especial dentro de la Etapa 3 ("restar el dígito máximo de cada dígito en el lugar actual"). Afirmé que después de restar el valor de dígito máximo de cada dígito (en cuyo punto el dígito máximo está en −1), simplemente lo decrementamos una vez más, pero en realidad hay una condición sobre eso que es la siguiente:Si el dígito que estamos viendo es igual al dígito máximo en este lugar ( * p = −1), y este lugar es el lugar de las unidades ( q = −1), y el dígito máximo es 1 ( * (r + 5) = 0, es decir, el bloque unario a la izquierda tiene solo 5 celdas de largo), solo entonces dejamos * p en −1 para indicar que la única iteración de la salida debe generar un
'8'
. En todos los demás casos, lo decretamos una vez más.Hecho. ¡Feliz año nuevo!
Edición 1 (3183 → 3001): ¡ Feliz año nuevo jugando al golf! ¡Logré deshacerme de las variables p2 y r2 por completo! p ahora corre de un lado a otro para seguir encontrando el principio y el final de los números, pero parece ser más corto en código. Traté de deshacerme de q2 también, pero no pude acortar el código de esa manera.
También encontré algunos lugares más donde podría aplicar los típicos trucos de golf ilegibles, como reutilizar el último valor de un ciclo while. Para darle un ejemplo, en lugar de
Puedo guardar el
'""""
(hacer el primero, luego el segundo) y el'"""
(constante 1) escribiéndolo de una manera similar aPor supuesto, esto solo funciona si sé que el ciclo while se ejecutará durante al menos una iteración, pero si lo hace, su valor de retorno es pd, por lo que puedo usarlo como condición para el if.
fuente
Javascript (ES6)
750744690604498346245234 bytesSoy nuevo en PPCG y pensé que podría intentarlo pensando que era bastante simple. ¡Estaba equivocado! He estado trabajando en ello durante un tiempo y tengo mucho golf que hacer ... ¡
Se recomiendan sugerencias! - aunque dar sentido a esto no será una tarea fácil.
Emite cuerdas cuando la entrada es una matriz de números (por ejemplo:)
[204, 1]
.Explicación
Ejemplo
Entrada: Matriz de números:
[4,8,15,16,23,42]
Salida:
fuente
Python 3,
624598595574561535532527525426345328324294288286283280267265255251245238235234230228 bytesBueno, como esta pregunta necesitaba una respuesta, he proporcionado una aquí, donde la entrada debe ser una cadena de números separados por espacios, como
"204 1"
. Chico, ¿es largo? Cualquier sugerencia de golf (o mejores respuestas) son bienvenidas.Editar: Bytes guardados mezclando pestañas y espacios.
Editar: ahorré muchos bytes al cambiar la forma en que obtuve los dígitos de un número (haga una lista de la cadena del número con relleno de cero, luego en el cuerpo del código, transponga para obtener cientos de dígitos, diez dígitos, etc. .)
Editar: Y guardé un poco más al incorporar ese último
:8
bucle en el bucle quipu principal.Ahora si solo pudiera entender por quéLo descubrí y la solución toma demasiados bytes. (También el recuento de bytes se redujo porque de alguna manera las pestañas se volvieron a convertir en cuatro espacios. Probablemente fue el formato de bloque de código en este sitio)b=d[j*v+i]==m(d[i::v])
no funcionará.Editar: reorganicé cómo se hizo el quipus. Ahora crea una hebra a la vez, luego se transpone para imprimir.
Editar: Volví mi respuesta a un programa de Python 3 para guardar algunos bytes más.
Editar: Encontré un error en mi código que lo hizo para que no imprimiera ceros en el medio de los números correctamente (vea el caso de prueba
204 1
anterior). Al arreglar esto, logré jugarlo :)Editar: cambié la impresión para ahorrar 10 bytes. Y puse todos los viejos bytes de cuenta atrás solo porque sí.
Editar: Golfed la asignación de
v
usarmap
para cuatro bytes. Gracias a CarpetPython , ya que obtuve la idea de su respuesta aquí .Editar: Convierte el "ciclo for dentro de un ciclo for", en uno solo para seis bytes.
Editar: ahora usando
enumerate
. Ya no lo usol=len(z)
. Convirtió el ternarioif-else
en una lista ternaria. Ver abajo para más detalles.Editar: Sp3000 sugirió editar
print
y editar la condición ternaria que guardó un byte cada uno.Sin golf:
fuente
0
, como0 12 4
.for r in zip(*x):print(''.join(r))
->print(''.join(r)for r in zip(*x))
C,
238235 bytesConfiar mucho en el preprocesador C para hacer el código lo más corto posible. Como efecto secundario, también lo hace prácticamente ilegible.
En Ubuntu 14.04, puede compilar el código de forma directa
gcc quipu.c
(ignore las advertencias). Un ejemplo de ejecución del ejecutable:Probado contra todos los casos de prueba de OP.
Código fuente no protegido:
fuente
Mathematica
436453357352347bytesLo anterior
IntegerDigits
; rellena cada número con ceros a la izquierda (para garantizar un espaciado igual); cada número de entrada, ahora descompuesto en dígitos, corresponde a una fila de una matriz; Cada columna representa un valor posicional. La matriz está transpuesta.Ejemplo
fuente
Transpose@Join
? Eso debería estar en, ¿verdad?R -
446444Veo que todavía no hay una solución R, así que aquí hay una. La función toma un vector con enteros.
Sin golf
fuente
if(v>0)
en tuif(i<r)
cláusula? ¿R acepta un rango comoz+1:z
cuandov==0
? De ser asíq[z+1:z,j]
, no se vería afectado en absoluto, creo. Además, ¿R tiene unaelse
palabra clave y algún tipo deelse if
palabra clave? Si es así, podría jugar al golf con algunos de estos condicionales.if(v>0)
es necesario porque siv=0
, el índice estará fuera de los límites (es decir, intenta obtener la fila nrow + 1). R síelse
, y de hecho probé su sugerencia y la uséelse
cuando fue posible, pero resultó ser la misma cantidad de bytes.