Contando Quipu: Base 10 en el Nuevo Mundo

41

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 largo
  • 8 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.

  1. 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 ( |).
  2. 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, 24con a 2en el lugar de las decenas y a 4en el lugar de las unidades, estará representado por dos nudos, un delimitador ( |), luego cuatro nudos.
  3. 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 ( |).
  4. Los nudos simples consecutivos ( .) representan un valor en su posición.
  5. 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 ( |).
  6. 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 ( :).
  7. 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.
  8. 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 2147483647o 2^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:

|

Casos de prueba más largos

Otras lecturas

Sherlock9
fuente

Respuestas:

3

Pyth, 64 bytes

=QjRTQjCmj\|+:R"[8:]"\.PdedCmm+*\|-h.MZdk*?tk\:\8kdC.[L0h.MZlMQQ

Pruébalo en línea!

Cómo funciona

=QjRTQ   Converts each number in input to decimal (as a list)
         123 becomes [1,2,3]

----

jCmj\|+:R"[8:]"\.PdedCmm+*\|-h.MZdk*?tk\:\8kdC.[L0h.MZlMQQ

                                              .[L0       Q  0-leftpad each #
                                                  h.MZlMQ   (max length) times

                                             C              transpose

                      mm                    d    for each digit:
                        +                        [convert to] sum of
                         *\|                     "|" repeated
                            -                    the difference of
                             h.MZd               maximum digit in same row
                                  k              and itself.. that many times
                                   *?tk\:\8      and (digit > 1 then ":" or "8") repeated
                                           k     itself many times


the list:
[11,23,52]
->[[1,1],[2,3],[5,2]]
->[[1,2,5],[1,3,2]]
->[["||||8","|||::",":::::"],["||8",":::","|::"]]

                     C      transpose

->[["||||8","||8"],["|||::",":::"],[":::::","|::"]]

  m                          for each number
      +                      [convert to] sum of
                 Pd          every element but the last
       :R"[8:]"\.            with "8" and ":" replaced by "."
                   ed        and the last element
   j\|                       joined with "|"

  C                          transpose
 j                           join (with newlines)
Monja permeable
fuente
Esta es una excelente respuesta, excepto por un problema. El nudo final no siempre es un nudo figura ocho 8. De hecho, es solo un 8nudo 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í, aparentemente
Sherlock9
22

Ilegible , 3183 3001 bytes

Fue 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, 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.

ingrese la descripción de la imagen aquí

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.

ingrese la descripción de la imagen aquí

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í:

ingrese la descripción de la imagen aquí

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:

ingrese la descripción de la imagen aquí

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.

ingrese la descripción de la imagen aquí

En este punto, permítanme aclarar la terminología que usaré a lo largo de esto.

  • Por número , me refiero a uno de los números de entrada que están separados por comas. En nuestro ejemplo, son 202, 100 y 1.
  • Por dígito , me refiero a un solo dígito en uno específico de los números. El primer número tiene 3 dígitos.
  • Por lugar , me refiero al lugar de las unidades, el lugar de las decenas, el lugar de las centenas, etc. Entonces, si digo "los dígitos en el lugar actual", y el lugar actual es el lugar de las unidades, esos dígitos son 2, 0 y 1 en ese orden.

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 ).

ingrese la descripción de la imagen aquí

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:

ingrese la descripción de la imagen aquí

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 .

ingrese la descripción de la imagen aquí

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.

ingrese la descripción de la imagen aquí

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:

ingrese la descripción de la imagen aquí

Después de haber procesado todos los números, ahora estamos al final de la etapa 3. Aquí realizamos dos cosas singulares.

  • Primero, también restamos el tamaño del bloque r (más 1) de * q , pero usando el puntero r2 , que lo deja a la izquierda. * q se vuelve negativo de esta manera. En nuestro caso, el bloque r tiene cinco 1s, por lo que * q se convierte en −3.
  • En segundo lugar, hemos creado una variable a cabo a un valor distinto de cero para indicar que ahora estamos entrando en la etapa de salida. (Técnicamente, el hecho de que * q sea ​​negativo ya indica la etapa de salida, pero esto es demasiado difícil de verificar, de ahí la variable adicional).

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 :

  • * q = −2:
    • Para el primer número, * p es −2, lo que indica que necesitamos generar un '.'(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 '.'.
    • Para el segundo número, * p es −3. Cualquier cosa que no sea −2 significa que sacamos una '|'(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.
    • En cada caso, también establecemos una variable pd a 0 antes de procesar el número, y establecemos pd (= "impreso") en un valor distinto de cero para indicar que hemos impreso un carácter.
    • Para el tercer número, no se procesa porque el tercer número no tiene un lugar de cientos. En este caso, pd seguirá siendo 0 después de procesar el número, lo que indica que todavía necesitamos generar un '|'(pero solo si out no es cero, porque de lo contrario todavía estamos en la etapa 2 o 3).
    • Después de procesar todos los números, si out no es cero, genera una nueva línea. Tenga en cuenta que necesitamos la variable out para no generar la nueva línea en la etapa 2 o 3.
  • * q = −1: Igual que antes, excepto que * p es −2 para los dos primeros números, por lo que ambos generan a'.'(y el tercero genera a'|'como antes).
  • * q = 0: cuando * q es 0, esto significa "no hacer nada si estamos en el lugar de las unidades; de lo contrario, generará una fila de'|'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í:

ingrese la descripción de la imagen aquí

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:

ingrese la descripción de la imagen aquí

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.

ingrese la descripción de la imagen aquí

Ahora veamos qué sucede cuando * q avanza hacia 1:

  • Cuando * q = −1, los valores * p son todos −3, lo que significa que sacamos '|'sy los incrementamos.
  • Cuando * q = 0, salimos '|'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:

ingrese la descripción de la imagen aquí

Después de la Etapa 2 ("calcular el valor máximo de dígitos"), nos queda esto:

ingrese la descripción de la imagen aquí

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í:

ingrese la descripción de la imagen aquí

Ahora veamos cada iteración de * q a su vez:

  • * q = −2:
    • Primer número: ya está en −2, así que emite a ':'(en lugar de a '.'porque q = −1).
    • Segundo número: en −4, de modo que emite a '|'e incrementa
    • Tercer número: en −3, entonces salida a '|'. 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 ':'.
  • * q = −1:
    • En primer número: ya a -2, por lo que la salida una ':'.
    • Segundo número: en −3, entonces salida a '|'. La condición especial no se activa porque * q ya no es −2. Por lo tanto, incremente.
    • Tercer número: en −1, entonces salida '8'.
  • * q = 0: Normalmente, mostraríamos la fila de relleno de'|'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 el 1(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

    while *(++p) { 1 }         // just increment p until *p is 0; the 1 is a noop
    if (pd) { x } else { y }   // where pd is a variable
    

    Puedo guardar el '""""(hacer el primero, luego el segundo) y el '"""(constante 1) escribiéndolo de una manera similar a

    if (while *(++p) { pd }) { x } else { y }
    

    Por 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.

Timwi
fuente
"Indescifrable" es sin duda un nombre apropiado ...
Alex A.
99
-1 explicación insuficiente
The Guy with The Hat
7

Javascript (ES6) 750 744 690 604 498 346 245 234 bytes

Soy 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].

a=>(o=m=s="",l=a.map(n=>(s+="|",l=(n+"").length)>m?m=l:l),h=[],a=a.map((n,i)=>[..."0".repeat(m-l[i])+n].map((d,j)=>d<h[j]?d:h[j]=d)),h.map((n,i)=>{i?o+=s+`
`:0;for(j=n;j--;o+=`
`)a.map(d=>o+="|.:8"[d[i]-j<1?0:i<m-1?1:d[i]-1?2:3])}),o)

Explicación

a=>(

  o=m=s="",                      // m = max number of digits in a number, s = separator string         
  l=a.map(n=>(                   // l = lengths of each number
      s+="|",                    // set the separator string
      l=(n+"").length                 // convert each number to a string
    )>m?m=l:l                    // get max length
  ),
  h=[],
  a=a.map((n,i)=>
    [..."0".repeat(m-l[i])+n]    // add leading 0s to make all same length
    .map((d,j)=>d<h[j]?d:h[j]=d) // set each digit of h to max
  ),

  h.map((n,i)=>{
    i?o+=s+`
`:0;
    for(j=n;j--;o+=`
`)
      a.map(d=>
        o+=
          "|.:8"[
            d[i]-j<1?0
            :i<m-1?1
            :d[i]-1?2:
            3
          ]
      )
  }),
  o
)

Ejemplo

Entrada: Matriz de números: [4,8,15,16,23,42]
Salida:

|||||.
|||||.
||||..
||....
||||||
|:||||
|:||||
|:|:||
|:::||
::::||
:::::|
::::::
::::::
Aᴄʜᴇʀᴏɴғᴀɪʟ
fuente
+1 golf impresionante. ¿Incluirá un ejemplo con entrada y salida?
DavidC
@DavidC ¡Gracias! Y el ejemplo está incluido. Llámalo desde la consola y devuelve una cadena. :)
Aᴄʜᴇʀᴏɴғᴀɪʟ
7

Python 3, 624 598 595 574 561 535 532 527 525 426 345 328 324 294 288 286 283 280 267 265 255 251 245 238 235 234 230 228 bytes

z=input().split();v=max(map(len,z));d=''.join(i.zfill(v)for i in z);x=['']*len(z)
for k,c in enumerate(d):j=k%v;m=int(max(d[j::v]));c=int(c);x[k//v]+="|"*(m-c+0**m+(j>0))+":8."[(c<2)|-(j<v-1)]*c
for r in zip(*x):print(*r,sep='')

Bueno, 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 :8bucle en el bucle quipu principal. Ahora si solo pudiera entender por qué b=d[j*v+i]==m(d[i::v])no funcionará. 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)

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 1anterior). 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 vusar mappara 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 uso l=len(z). Convirtió el ternario if-elseen una lista ternaria. Ver abajo para más detalles.

Editar: Sp3000 sugirió editar printy editar la condición ternaria que guardó un byte cada uno.

Sin golf:

s = input()
z = s.split()
v = max(map(len, z))                # the amount of digits of the largest number
d = ''.join(i.zfill(v) for i in z)  # pad zeroes until every number is the same length
                                     # then join the numbers into one string
x = ['']*len(z)                     # a list of strings for the output, one for each number

for k,c in enumerate(d):          # for every digit in every number
    i,j = divmod(k, v)            # i is the index of the number we're on
                                   # j is the index of the digit of the number we're on
    m = int(max(d[j::v]))         # the largest of all the digits in the j-th place
    c = int(c)                    # the digit in j-th place of the i-th number
    x[i] += "|"*(m-c+0**m+(j>0))  # pad | to size m-c, until the knots are correctly spaced
                                  # add a | if m<1, all j-th place digits are 0
                                  # add a | if j>0, if it's not at the start, as delimiters
    x[i] += ":8."[(c<2)|-(j<v-1)] * c
    # this is essentially the following code
    # if j<v-1:
    #     x[i] += "."*c      # . knots if not in the units place
    # else:
    #     if c == 1:
    #         x[i] += "8"*c  # 8 knots for ones in the units place
    #     else:
    #         x[i] += ":"*c  # : knots for something else is in the units place

for r in zip(*x):       # transpose so all the rows (the quipu strings) now hang down
    print(*r, sep='')    # join the strings together at each knot
                         # and print each on a separate line
Sherlock9
fuente
¿Hay algo específico para Python 3 aquí? Si no, convertirlo a Python 2 podría ahorrar bastantes bytes
Cyoce
@Cyoce Nada demasiado específico de Python 3. Acabo de comenzar en Python 3 porque esa es la versión que tengo. Probaré una versión de Python 2 en ideone o algo así.
Sherlock9
@Maltysen Eso no funciona con entradas que comienzan con 0, como 0 12 4.
Sherlock9
Puede guardar algunos bytes alternando pestañas y espacios para la sangría en Python 2. Creo que 1 carácter de pestaña == 8 espacios según el analizador de sangría de Python
Cyoce
for r in zip(*x):print(''.join(r))->print(''.join(r)for r in zip(*x))
Leaky Nun
4

C, 238 235 bytes

Confiar 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.

#define l strlen(a[i])
#define d l<k||a[i][l-k]-48
#define m(e) for(i=1;a[i];e<=r?i++:r++);
#define p(e) {m(!putchar(e?'|':k>1?46:d<2?56:58))puts("");}
k,r;main(int i,char**a){m(l)for(k=r,r=1;k;r=k>1){m(d)for(;r;r--)p(d<r)if(--k)p(1)}}

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:

$ ./a.out 1 2 3 2 1
||:||
|:::|
8:::8

Probado contra todos los casos de prueba de OP.

Código fuente no protegido:

// Standard library; leaving out the includes still gives executable code despite the warnings.
#include <stdio.h>
#include <string.h>

// 4 preprocessor macros.
// Note: some of these actually make use of the fact that parentheses have been left out

// l: length of argument i
#define l     strlen(a[i])

// d: shorthand for a digit
#define d     l<k || a[i][l-k]-'0'

// m: loop across all arguments; calculates r as the maximum of expression e
#define m(e)  for (i=1; a[i]; e<=r ? i++ : r++);

// p: prints one line of output
// note: intentionally does not use the r++ code branch of m;
//       putchar always returns a non-zero number here, so !putchar is zero,
//       which is always <=r (because r is never negative)
// note: the semicolon after m(...) is redundant;
//       the definition of m already contains a semicolon
// note: puts("") outputs a newline
#define p(e)  { m(!putchar(e ? '|' : k > 1 ? '.' : d < 2 ? '8' : ':')); puts(""); }

// k: knot position; 1 for units, 2 for tens, 3 for hundreds...
int k;

// r: input and output value for m
// note: the first time we call m, we need r to be zero;
//       by defining it outside main, it is automatically initialized as such
int r;

// function main
// note: parameter i (normally named argc by convention) is not needed
//       (the last element of argv is known; it is followed by a NULL pointer)
//       but we cannot leave it out (otherwise we cannot access argv)
//       so it serves as a local variable (to loop through arguments; see m)
// note: parameter a (normally named argv by convention)
//       is the array of arguments (starting from index 1)
int main(int i, char **a)
{
    // Determine the longest argument; store its length in r.
    // This is the number of knot positions to consider.
    m(l)

    // Iterate k through the knot positions from top to bottom.
    // Note: k > 0 has been abbreviated to k.
    // Note: for each iteration, we also initialize r with either 0 or 1.
    //       0 = suppress printing when all knots are zero
    //       1 = always print, even when all knots are zero
    for (k = r, r = 1; k > 0; r = k > 1)
    {
        // Determine the highest digit at this knot position.
        // Note: due to the absence of parentheses, d mixes up with <=r into:
        // (l < k) || (a[i][l-k]-'0' <= r)
        m(d)

        // Count the digits down.
        for (; r; r--)
        {
            // Print a single line of output.
            // When d (the digit in the current strand) is less than the counter,
            // then print a '|', otherwise print a knot.
            p(d < r)
        }

        // Decrement k (go to next knot position).
        // If this was not the last iteration...
        if (--k > 0)
        {
            // Print separator line.
            p(1)
        }
    }

    // Return exit code zero; redundant.
    return 0;
}
Ruud Helderman
fuente
¡Felicidades! Como la respuesta más corta publicada dentro del período de recompensa, ha recibido mi recompensa de +50 rep. ¡Buena respuesta! :)
Alex A.
4

Mathematica 436453357352347 bytes

t=Transpose;y=ConstantArray;a=Table;
g@j_:=(s=t[PadLeft[#,Max[Length/@i]]&/@(i=IntegerDigits@#)]&;p_~u~o_:=(m=Max@p;c=If[o==-2,":","."];w=If[o==-2,"8","."];p//.{0->a["|",Max@{1,m}],1->Join[a["|",{m-1}],{w}],n_/;MemberQ[2~Range~9,n]:>Join[y["|",m-n ],c~y~n]});t[Join@@@t@Join[u[#,0]&/@Most@#,u[#,-2]&/@{#[[-1]]}]]&[Riffle[(s@j),{a[0,Length@j]}]]//Grid)

Lo anterior

  • Rompe cada número entero en una lista de dígitos, usando 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.
  • Reemplaza los dígitos con una lista de nudos con relleno. Se utiliza una rutina de coincidencia de patrones ligeramente diferente para las unidades.

Ejemplo

g[Range[0, 50]]

cincuenta

DavidC
fuente
Transpose@Join? Eso debería estar en, ¿verdad?
CalculatorFeline
Sí. Gracias por atrapar esto.
DavidC
Espacio justo antes de eso.
CalculatorFeline
1

R - 446 444

Veo que todavía no hay una solución R, así que aquí hay una. La función toma un vector con enteros.

function(x){r=nchar(max(x));c=length(x);m=matrix(0,r,c);for(i in 1:c){t=as.numeric(strsplit(as.character(x[i]),"")[[1]]);m[(r+1-length(t)):r,i]=t};Q=c();for(i in 1:r){d=m[i,];z=ifelse(max(d)>0,max(d),1);q=matrix("|",z,c);for(j in 1:c){v=m[i,j];if(i==r){if(v==1)q[z,j]=8;if(v>1)q[(z-v+1):z,j]=rep(":",v)};if(i<r){if(v>0)q[(z-v+1):z,j]=rep(".",v)}};if(i!=1&sum(d)>0)q=rbind(rep("|",c),q);Q=rbind(Q,q)};for(i in 1:nrow(Q))cat(Q[i,],sep="",fill=T)}

Sin golf

# Some test data
test <- c(201, 0, 100, 222, 53)

# Define function
quipu <- function (x) {

    # Create matrix with a row for each digit and a column for each number
    r=nchar(max(x));c=length(x);m <- matrix(0,r,c)
    for(i in 1:c) {
        t=as.numeric(strsplit(as.character(x[i]),"")[[1]])
        m[(r+1-length(t)):r,i]=t
    }

    # Loop through each row (digit) starting at the top of the quipu
    Q=c() # Empty matrix to store quipu 
    for(i in 1:r){

        d=m[i,]
        z=ifelse(max(d)>0,max(d),1)
        q=matrix("|",z,c)

        # Loop through each column (number in the vector) starting at the leftmost quipu
        for(j in 1:c){

            # The digit
            v=m[i,j]

            # If it is the last segment of the quipu
            if(i==r){
                if(v==1){q[z,j]=8} # If unit digit =1
                if(v>1){q[(z-v+1):z,j]=rep(":",v)} # If unit digit >1               
            }

            # If it is not the last segment of the quipu
            if(i<r){
                if(v>0){q[(z-v+1):z,j]=rep(".",v)} # If non-unit digit >0   
            }
        }

        # Add segment to Q
        if(i!=1 & sum(d)>0){q=rbind(rep("|",c),q)}
        Q=rbind(Q,q)    
    }

    # Print quipu
    for(i in 1:nrow(Q)) {cat(Q[i,], sep="", fill=T)}
}

# Test
quipu(test)
Loris lento
fuente
¿Necesitas if(v>0)en tu if(i<r)cláusula? ¿R acepta un rango como z+1:zcuando v==0? De ser así q[z+1:z,j], no se vería afectado en absoluto, creo. Además, ¿R tiene una elsepalabra clave y algún tipo de else ifpalabra clave? Si es así, podría jugar al golf con algunos de estos condicionales.
Sherlock9
if(v>0)es necesario porque si v=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é elsecuando fue posible, pero resultó ser la misma cantidad de bytes.
Slow loris