Contando Quipu: Base 10 no Novo Mundo

41

Quipus é um dispositivo antigo usado pelos incas na era pré-colombiana para registrar números em um sistema posicional de base dez de nós em uma corda, que funciona da seguinte maneira:

Cada aglomerado de nós é um dígito e existem três tipos principais de nós: simples nós de overhand; "nós longos", que consistem em um nó de overhand com uma ou mais voltas adicionais; e figura oito nós.

  • Poderes de dez são mostrados pela posição ao longo da corda, e esta posição está alinhada entre as costas sucessivas.
  • Os dígitos nas posições de potências 10 e superiores são representados por grupos de nós simples (por exemplo, 40 são quatro nós simples seguidos na posição "dezenas").
  • Os dígitos na posição "uns" são representados por nós longos (por exemplo, 4 é um nó com quatro voltas). Devido à maneira como os nós são amarrados, o dígito 1 não pode ser mostrado dessa maneira e é representado nessa posição por um nó de oito dígitos.
  • Zero é representado pela ausência de um nó na posição apropriada.

Detalhes

Para esse desafio, cada fio de um quipu representa um único número (embora, como o artigo da Wikipedia declare, você possa representar muitos números em um fio, neste desafio, não o faremos).

Nós

Cada nó será representado por um único caractere ASCII.

  • . representa um nó simples
  • : representa uma volta de um longo nó
  • 8 representa um nó de oito
  • | representa a ausência de um nó e de um delimitador entre os dígitos.

Construindo Quipus

Quipu são construídos seguindo estas regras.

  1. Os fios passam de cima para baixo em ordem decrescente de posição (como em, o dígito das unidades estará na extremidade inferior de um fio). Os dígitos ao longo de um fio são separados pelo caractere ( |).
  2. A potência de 10 que um dígito representa é determinada por sua posição ao longo da cadeia, da mesma forma que a potência de 10 de um dígito seria calculada usando seu índice em um número com o nosso sistema de números. Ou seja, 24com um 2na casa das dezenas e um 4na casa das unidades, será representado por dois nós, um delimitador ( |), depois quatro nós.
  3. Os dígitos na mesma posição estão alinhados na parte inferior do fio. Se um dígito em uma posição tiver menos nós do que outros dígitos de outros números na mesma posição, a ausência desses nós será representada por ( |).
  4. Nós simples consecutivos ( .) representam um valor em sua posição.
  5. Cada dígito é representado por pelo menos 1 caractere. Quando um valor de dígitos é 0 para todos os números em um quipu, ele é representado pela ausência de um nó ( |).
  6. O local das unidades é tratado especialmente. Um no local da unidade é representado por um nó de oito ( 8). Um valor de dois ou mais no local da unidade é representado por nós longos consecutivos ( :).
  7. Quando o dígito das unidades é 0 para todos os números em um quipu, a ausência de um nó não é impressa, mas o delimitador à direita do dígito das dezenas é preservado.
  8. Não há delimitador após o dígito das unidades.

Regras

  • A entrada consistirá em uma lista não vazia de números inteiros não negativos que podem ser recebidos através de qualquer um dos métodos de entrada padrão . Você pode assumir que esses números inteiros são menores ou iguais a 2147483647ou 2^31-1. Enquanto os casos de teste são delimitados por espaço, seu formato de entrada pode separar as entradas da maneira que for mais conveniente para o seu idioma, seja separado por vírgula, separado por nova linha, em uma matriz e assim por diante.
  • A saída consiste em um único Quipu construído de acordo com as regras descritas acima. A saída pode ser fornecida através de qualquer um dos métodos de saída padrão .
  • Seu código deve ser um programa ou uma função, embora não precise ser uma função nomeada.
  • Nós demoramos algum tempo para empatar, para economizar tempo, seu código é o mais curto possível.

Como sempre, se o problema não estiver claro, entre em contato. Boa sorte e bom golfe!

Exemplos

Entrada:

5 3 1 0

Saída:

:|||
:|||
::||
::||
::8|

Entrada:

50 30 10 0

Saída:

.|||
.|||
..||
..||
...|
||||

Entrada:

330

Saída:

.
.
.
|
.
.
.
|

Entrada:

204 1

Saída:

.|
.|
||
||
||
:|
:|
:|
:8

Entrada:

201 0 100 222

Saída:

.||.
.|..
||||
|||.
|||.
||||
|||:
8||:

Entrada:

1073741823 2147483647

Saída:

|.
..
||
|.
||
.|
.|
.|
..
..
..
..
||
|.
|.
|.
|.
..
..
..
||
.|
.|
.|
..
..
..
..
||
|.
|.
|.
|.
..
..
..
..
||
|.
|.
..
||
.|
.|
..
..
..
..
..
..
||
|.
|.
..
..
||
|:
|:
|:
|:
::
::
::

Entrada:

0

Saída:

|

Casos de teste mais longos

Leitura adicional

Sherlock9
fonte

Respostas:

3

Pitão, 64 bytes

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

Experimente online!

Como 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)
Freira Furada
fonte
Esta é uma excelente resposta, exceto por um problema. O nó final nem sempre é um nó de oito 8. De fato, é apenas um 8nó quando o último dígito é 1 (consulte a regra 6). Você está convertendo todos os nós finais e isso não corresponde às especificações. Além disso, seu Try It Online! link tem código diferente do que é postado aqui, aparentemente
Sherlock9
22

Ilegível , 3183 3001 bytes

Este foi um desafio divertido para trabalhar, dentro e fora, entre as celebrações de Natal. Obrigado por postar! Jogar golfe foi interessante porque a especificação está cheia de exceções e casos especiais, que exigiam muitas condições. Além disso, embora não tenha sido necessário converter de e para decimal dessa vez, era necessária uma espécie de "max" para determinar o maior número de dígitos em cada número e o maior valor dos dígitos em cada local.

A primeira versão disso era 4844 bytes, apenas para lhe dar uma idéia do quanto eu joguei isso.

O programa espera a entrada como uma lista de números inteiros separados por vírgula . Sem espaços ou novas linhas. Utilizá-los produzirá um comportamento indefinido.

'"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" '""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " """ '""' "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" '""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '"" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" '""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" "" "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '"" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""'" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "'" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '"" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""'"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""'""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "'" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""'" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" ""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" ""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """'" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" '""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "'" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" "" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "'' ''" "" "" "" "" "" "" "" "" "" "" "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" '""' "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "'" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""

Explicação

Vou mostrar como o programa funciona, mostrando como ele processa a entrada específica 202,100,1.

No começo, construímos alguns valores que precisaremos mais tarde - principalmente os códigos ASCII dos caracteres que serão exibidos.

insira a descrição da imagem aqui

Como você pode ver, '8'e '.'já está disponível. '|', no entanto, é realmente 124, não 14. Usamos um loop while para adicionar o dobro do valor temporário no slot # 1 para obter 124 (que é 14 + 55 × 2, porque o loop while é executado por 56−1 = 55 iterações). Isso economiza alguns bytes porque literais inteiros grandes como 124 são realmente longos. No diagrama a seguir, mostro a localização de todas as variáveis ​​que o programa usa.

insira a descrição da imagem aqui

Em seguida, queremos inserir todos os caracteres e armazená-los na fita, começando na célula # 12 ( p é o ponteiro para isso). Ao mesmo tempo, queremos saber quanto tempo é o número mais longo (quantos dígitos). Para conseguir isso, mantemos um total contínuo em unário indo para a esquerda, começando na célula # -1 (usamos q como ponteiro em execução). Após o primeiro número de entrada ( 202), a fita agora fica assim:

insira a descrição da imagem aqui

Você deve ter notado que os números estão desativados por 4. Bem, quando os inserimos pela primeira vez, eles são seus valores ASCII, então eles estão desativados por 48 e a vírgula é 44. Para cada caractere, copiamos o 46 de '.'em ree subtraí-lo com um loop while (que subtrai 45) e depois adicionamos 1. Fazemos isso para que a vírgula (nosso separador) seja 0, para que possamos usar uma condicional para reconhecê-lo.

Além disso, você deve ter notado que deixamos a célula nº 11 em 0. Precisamos disso para reconhecer o limite do primeiro número.

O próximo caractere será uma vírgula; portanto, armazenamos um 0 no # 15, mas é claro que desta vez não avançamos q . Em vez disso, colocamos q de volta em 0 e começamos a "substituir" os 1s que já colocamos.

Depois que todos os caracteres restantes são processados, obtemos o seguinte:

insira a descrição da imagem aqui

Como você pode ver, os 1s escritos por q agora indicam (em unário) o comprimento do número mais longo.

Agora usamos um loop while para mover q para a extrema esquerda e, em seguida, colocamos outro ponteiro lá, que chamarei de r2 . O objetivo de r2 ficará claro mais tarde.

insira a descrição da imagem aqui

Neste ponto, deixe-me esclarecer a terminologia que usarei ao longo disso.

  • Por número , quero dizer um dos números de entrada separados por vírgulas. No nosso exemplo, eles são 202, 100 e 1.
  • Por dígito , quero dizer um único dígito em um número específico. O primeiro número tem 3 dígitos.
  • Por local , quero dizer os locais, dezenas, centenas, etc. Então, se eu disser “os dígitos no local atual” e o local atual for o local, esses dígitos serão 2, 0 e 1 nesse local. ordem.

Agora, de volta à nossa programação regular. O restante do programa é um grande loop que move q para frente até atingir a célula # 0. Cada uma das células ao longo do caminho representa um local, com as localizadas na extrema direita, e q começará no mais significativo. No nosso exemplo, esse é o lugar das centenas.

Prosseguimos incrementando os pontos q da célula em (ou seja, * q ).

insira a descrição da imagem aqui

Agora estamos no "estágio 2" do lugar das centenas. Nesta etapa, descobriremos qual é o maior dígito entre todos os dígitos na casa das centenas. Utilizamos o mesmo truque de contagem unário para isso, exceto que, desta vez, o ponteiro é chamado reo ponteiro r2 marca sua posição inicial para a qual precisamos redefini-lo toda vez que passamos para o próximo número.

Vamos começar com o primeiro número. Começamos definindo p como 11 (a posição inicial codificada de todos os números). Em seguida, usamos um loop while para encontrar o final do número e configuramos p2 para marcar a posição. Ao mesmo tempo, também definimos q2 como 0:

insira a descrição da imagem aqui

Não se distraia com o fato de q2 estar apontando para os vars. Não temos um preenchimento de uma célula em branco porque podemos detectar a célula # 0 simplesmente porque é o número zero.

Em seguida, passamos o número atual por decrementing p e Q2 juntos até * p é zero. Em cada local, o valor de * q2 nos diz o que precisamos fazer. 1 significa "não fazer nada", por isso continuamos. Eventualmente, encontramos o 2 na célula # -3. Toda vez que * q2 não é igual a 1, q2 é sempre igual a q .

insira a descrição da imagem aqui

Como já afirmei, o estágio 2 é "determinar o maior dígito neste local". Então, definimos r como r2 , use um loop while para diminuir * p e mova r para a esquerda e preencha a fita com 1s; em seguida, use outro loop while para mover r de volta para a direita e incrementar * p novamente para restaurar o valor. Lembre-se de que todo loop while é executado por uma iteração a menos do que o valor em que o usamos; por isso, o número de 1s gravados será 3 a mais (em vez de 4 a mais) que o valor do dígito, e o valor final armazenado em * p será 2 a mais. Assim, isso efetivamente diminuiu * p por 2.

Depois disso, definimos p com o valor de p2 e depois fazemos tudo isso novamente. Pela segunda vez, definir q2 a 0, encontrar o final do número, movendo p para a direita, e depois percorrer os dígitos deste número por decrementing p e Q2 em conjunto. Mais uma vez, encontraremos o 2 na célula nº -3 e escreveremos os 1s restantes de * r .

No caso do terceiro número, acabamos não fazendo nada porque não tem um lugar de centenas (portanto, q2 nunca atinge q ), mas tudo bem, porque isso não afeta o cálculo do valor máximo do dígito.

insira a descrição da imagem aqui

Também definimos a célula * (r - 4) , que marquei com uma seta sem rótulo aqui, como 1 (mesmo que já esteja em 1). Ainda não vou lhe dizer por que, mas talvez você já tenha adivinhado?

O próximo incremento de * q nos leva ao estágio 3, que é "subtrair o dígito máximo de todos os dígitos no local atual". Como antes, redefinimos p para 11 e q2 para 0 e, em seguida, passamos por todos os números, como fizemos no estágio anterior; Só que desta vez, * q = 3 em vez de 2. Toda vez Q2 atende q e p está em um lugar centenas, usamos um loop while para diminuir * p tantas vezes quantas existem 1s no bloco de esquerda da * r2 (5 no nosso exemplo) usando rcomo um ponteiro em execução. Na verdade, nós o decrementamos mais uma vez para que o dígito maior termine em -2, por um motivo que ficará claro mais tarde:

insira a descrição da imagem aqui

Depois de processarmos todos os números, estamos no final do estágio 3. Aqui, realizamos duas coisas singulares.

  • Primeiro, também subtraímos o tamanho do bloco r (mais 1) de * q , mas usando o ponteiro r2 , que o deixa à esquerda. * q se torna negativo assim. No nosso caso, o bloco r possui cinco 1s, então * q se torna -3.
  • Em segundo lugar, definir uma variável fora para um valor diferente de zero para indicar que estamos entrando agora no estágio de saída. (Tecnicamente, o fato de * q ser negativo já indica o estágio de saída, mas isso é muito difícil de verificar, daí a variável extra.)

Agora você entende que continuamos examinando os números, localizamos o local atual (indicado pelo valor diferente de 1 de * q ) em cada número e fazemos algo dependendo do valor de * q . Vemos que * q é incrementado primeiro para 2 (= calcular o valor máximo do dígito), depois 3 (subtrai o valor máximo do dígito de cada dígito neste local) e depois subtraímos para torná-lo negativo. A partir daí, ele continuará subindo até atingir 1, restaurando assim o valor que significa "não faça nada". Nesse ponto, passamos para o próximo lugar.

Agora, quando * q é negativo, estamos produzindo. * q está exatamente no valor certo, para que possamos produzir o número certo de linhas de caracteres antes que ele atinja 1; se o dígito maior for 2, precisamos gerar 3 linhas. Vamos ver o que acontece em cada valor de * q :

  • * q = −2:
    • Para o primeiro número, * p é -2, o que indica que precisamos gerar um '.'(ponto) ou um ':'(dois pontos). Decidimos qual, olhando para q : se for -1, estamos no mesmo local, então produza a ':'(que calculamos como '8'+2), caso contrário a '.'.
    • Para o segundo número, * p é -3. Qualquer coisa que não seja -2 significa que produzimos um '|'(canal) e depois incrementamos o valor. Dessa forma, ele alcançará -2 no lugar certo e, em seguida, produzimos '.'s / ':'s para o restante desse dígito.
    • Em cada caso, também definimos uma variável pd como 0 antes de processar o número e definimos pd (= "impresso") para um valor diferente de zero para indicar que imprimimos um caractere.
    • Para o terceiro número, nenhum processamento ocorre porque o terceiro número não possui um lugar de centenas. Nesse caso, pd ainda será 0 após o processamento do número, indicando que ainda precisamos gerar a '|'(mas apenas se out for diferente de zero, porque, caso contrário, ainda estamos no estágio 2 ou 3).
    • Depois de processar todos os números, se a saída for diferente de zero, imprima uma nova linha. Observe que precisamos da variável out para não gerar a nova linha no estágio 2 ou 3.
  • * q = −1: O mesmo que antes, exceto que * p é −2 para os dois primeiros números, portanto, ambos produzem a'.'(e o terceiro gera a'|'como antes).
  • * q = 0: Quando * q é 0, isso significa "não faça nada se estivermos no mesmo local; caso contrário, imprima uma linha de'|'s, independentemente de * p ". Dessa forma, obtemos o preenchimento entre os dígitos.

Agora incrementamos q para passar para o próximo lugar, as dezenas colocam e incrementamos * q lá. No início do estágio 2, a fita fica assim:

insira a descrição da imagem aqui

Em seguida, realizamos o estágio 2 como antes. Lembre-se de que isso efetivamente subtrai 2 de cada dígito neste local e também deixa um número unário à esquerda de * r2 indicando o dígito máximo. Deixamos o número unário anterior em paz e continuamos estendendo a fita para a esquerda; custaria apenas um código extra desnecessário para "limpar". Quando terminamos e incrementamos * q , no início do Estágio 3, a fita está agora:

insira a descrição da imagem aqui

Na verdade, isso é uma mentira. Lembra-se anteriormente de onde eu disse que definimos * (r - 4) como 1 e não lhe disse por quê? Agora eu vou te dizer o porquê. É para casos como este, em que o maior dígito é de fato 0, significando que todos os dígitos neste local são 0. A configuração * (r - 4) , indicada pela seta não identificada acima, para 1 aumenta o número unário em 1, mas apenas neste caso especial. Dessa forma, fingimos que o maior dígito era 1, o que significa que produziremos uma linha extra.

Após o estágio 3 (subtrair o dígito máximo de todos os dígitos no local atual), incluindo a etapa extra que torna * q negativo, a fita fica assim. Da última vez, o dígito maior foi representado por -2 no bloco * p , mas desta vez são todos -3, porque na verdade são todos zeros, mas estamos fingindo como se o dígito máximo fosse 1.

insira a descrição da imagem aqui

Agora vamos ver o que acontece à medida que * q avança em direção a 1:

  • Quando * q = −1, os valores * p são todos −3, o que significa que produzimos se os '|'incrementamos.
  • Quando * q = 0, produzimos '|'porque é isso que sempre fazemos quando * q = 0, independentemente de * p .

Assim, temos duas linhas de tubos.

Por fim, movemos * q para o local da pessoa. Este se torna interessante porque precisamos produzir ':'s se o dígito real for qualquer coisa menos 1, mas um '8'se for 1. Vamos ver como o programa prossegue. Primeiro, incrementamos * q para iniciar o estágio 2:

insira a descrição da imagem aqui

Após o estágio 2 ("calcular o valor máximo de dígitos"), ficamos com isso:

insira a descrição da imagem aqui

Após o estágio 3 ("subtraia o valor máximo de todos os dígitos no local atual"), a fita ficará assim:

insira a descrição da imagem aqui

Agora vamos analisar cada iteração de * q por sua vez:

  • * q = −2:
    • Primeiro número: já em -2, então imprima a ':'(em vez de a '.'porque q = -1).
    • Segundo número: em -4, então imprima a '|'e aumente.
    • Terceiro número: em -3, então produza a '|'. No entanto, desta vez, em vez de incrementar, um caso especial é acionado. Somente se estivermos produzindo o último lugar ( q = −1) e estivermos na segunda última linha para isso ( * q = −2), e o dígito for realmente um 1 ( * p = −3) , em vez de incrementá-lo para -2, configuramos para -1. Em outras palavras, usamos -1 como um valor especial para indicar que na próxima iteração, precisaremos produzir em '8'vez de ':'.
  • * q = −1:
    • Primeiro número: já em -2, então faça a saída a ':'.
    • Segundo número: em -3, então produza a '|'. A condição especial não é acionada porque * q não é mais -2. Portanto, incremente.
    • Terceiro número: em -1, então imprima '8'.
  • * q = 0: Normalmente, exibiríamos a linha de preenchimento de'|'s aqui, mas no caso especial em que estamos no local ( q = -1), ignoramos isso.

Depois disso, q é incrementado para 0 e o loop while grande termina.

Agora você sabe como uma entrada 202,100,1funciona. No entanto, há mais um caso especial que ainda não abordamos. Você deve se lembrar que enquanto processávamos o último local, quando * p estava -3, o definimos como -1 para 1(em vez de aumentá-lo para -2), para que a próxima iteração produza uma '8'alternativa. Isso funciona apenas porque temos uma iteração na qual * p é -3 e tomamos a decisão de incrementá-lo ou configurá-lo para -1. Nós não têm tal uma iteração se todos os dígitos no local queridos são 0 ou 1. Em tal caso, todos os * p valores para os 1s seria começam a -2; não há oportunidade de decidir configurá-lo para -1em vez de incrementá-lo de -3 . Por esse motivo, existe outra condição de revestimento especial dentro do Estágio 3 ("subtraia o dígito máximo de cada dígito no local atual"). Afirmei que, depois de subtrair o valor máximo do dígito de cada dígito (nesse ponto, o dígito máximo está em -1), apenas o diminuímos mais uma vez, mas, na verdade, existe uma condição que é a seguinte:

Se o dígito que estamos vendo for igual ao dígito máximo nesse local ( * p = -1), e esse local for o local ( q = -1), e o dígito máximo for 1 ( * (r + 5) = 0, ou seja, o bloco unário à esquerda tem apenas 5 células); somente então deixamos * p em -1 para indicar que a única iteração da saída deve gerar an '8'. Em todos os outros casos, diminuímos novamente.

Feito. Feliz Ano Novo!

  • Edição 1 (3183 → 3001): Golfe de feliz ano novo! Consegui me livrar completamente das variáveis p2 e r2 ! p agora corre para frente e para trás para encontrar o início e o fim dos números, mas parece ter um código mais curto. Tentei me livrar do q2 também, mas não consegui diminuir o código dessa maneira.

    Também encontrei mais alguns lugares onde eu poderia aplicar truques típicos de golfe ilegíveis, como reutilizar o último valor de um loop while. Para dar um exemplo, em vez 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
    

    Eu posso salvar o '""""(faça o primeiro, depois o segundo) e o '"""(constante 1) escrevendo-o de uma maneira que é como

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

    Obviamente, isso só funciona se eu souber que o loop while será executado por pelo menos uma iteração, mas se o fizer, seu valor de retorno será pd, para que eu possa usá-lo como condição para o if.

Timwi
fonte
"Ilegível" é certamente um nome adequado ...
Alex A.
9
-1 explicação insuficiente
O cara com o chapéu
7

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

Eu sou novo no PPCG e achei que poderia tentar este, pensando que era bastante simples. Cara, eu estava errado !! Estou trabalhando nisso há um tempo e tenho muito golfe para fazer ... As
sugestões são incentivadas! - embora entender isso não seja uma tarefa fácil.

Emite cordas quando a entrada é uma matriz de números (por exemplo [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)

Explicação

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
)

Exemplo

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

|||||.
|||||.
||||..
||....
||||||
|:||||
|:||||
|:|:||
|:::||
::::||
:::::|
::::::
::::::
Aᴄʜᴇʀᴏɴғᴀɪʟ
fonte
+1 golfe impressionante. Você incluirá um exemplo com entrada e saída?
DavidC
@DavidC Thanks! E o exemplo está incluído. Chame a partir do console e ele retorna uma string. :)
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='')

Bem, como essa pergunta precisava de uma resposta, forneci uma aqui, em que a entrada deve ser uma sequência de números separada por espaço, como "204 1". Rapaz, é longo. Quaisquer sugestões de golfe (ou melhores respostas) são bem-vindas.

Editar: bytes salvos misturando guias e espaços.

Editar: salvei muitos bytes alterando a forma como obtive os dígitos de um número (faça uma lista com a string preenchida com zero do número e, em seguida, no corpo do código, transponha para obter centenas, dez dígitos, etc. .)

Edit: E eu salvei um pouco mais, incorporando esse último :8loop no loop principal do quipu. Agora, se eu pudesse descobrir por b=d[j*v+i]==m(d[i::v])que não funcionaria. Descobri e a solução leva muitos bytes. (Também a contagem de bytes caiu porque, de alguma forma, as guias se transformaram em quatro espaços. Provavelmente era a formatação do bloco de código neste site)

Edit: Eu reorganizei como fez o quipus. Agora, ele cria um fio de cada vez e depois transpõe para impressão.

Edit: Transformei minha resposta novamente em um programa Python 3 para economizar mais alguns bytes.

Edit: Encontrei um bug no meu código que o fazia de modo que não estava imprimindo zeros no meio dos números corretamente (veja o caso de teste 204 1acima). Ao consertar isso, eu consegui jogar golfe :)

Editar: Alterei a impressão para salvar 10 bytes. E eu coloquei todas as antigas contagens de bytes, apenas porque.

Edit: Golfed a atribuição de vusar mappara quatro bytes. Os meus agradecimentos a CarpetPython , pois recebi a ideia da resposta deles aqui .

Edit: Transformado o meio "para loop dentro de um loop for", em apenas um loop for por seis bytes.

Edit: Agora usando enumerate. Não está mais usando l=len(z). Transformado o ternário if-elseem uma lista ternária. Veja abaixo os detalhes.

Editar: o Sp3000 sugeriu uma edição printe uma edição na condição ternária que salvou um byte cada.

Ungolfed:

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
fonte
Existe algo específico para Python 3 aqui? Caso contrário, convertê-lo em Python 2 poderia economizar alguns bytes
Cyoce
@ Cyoce Nada também Python 3 específico. Eu comecei no Python 3 porque essa é a versão que tenho. Vou testar uma versão do Python 2 em ideone ou algo assim.
Sherlock9
@ Maltysen Isso não funciona com entradas que começam com 0, como 0 12 4.
Sherlock9
Você pode salvar alguns bytes alternando tabulações e espaços para a indentação em Python 2. Eu acredito 1 guia Caractere == 8 espaços de acordo com analisador recuo de python
Cyoce
for r in zip(*x):print(''.join(r))->print(''.join(r)for r in zip(*x))
Freira Furada
4

C, 238 235 bytes

Confiando fortemente no pré-processador C para tornar o código o mais curto possível. Como efeito colateral, também o torna praticamente ilegível.

#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)}}

No Ubuntu 14.04, você pode compilar o código de maneira simples gcc quipu.c(ignore os avisos). Um exemplo de execução do executável:

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

Testado em todos os casos de teste do OP.

Código fonte ungolfed:

// 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
fonte
Parabéns! Como a resposta mais curta publicada no período de recompensa, você recebeu minha recompensa de +50 representantes. Boa resposta! :)
Alex A.
4

Mathematica 436453357352 347 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)

O de cima

  • Divide cada número inteiro em uma lista de dígitos, usando IntegerDigits; preenche cada número com zeros à esquerda (para garantir espaçamento igual); cada número de entrada, agora decomposto em dígitos, corresponde a uma linha de uma matriz; cada coluna representa um valor de local. Matriz é transposta.
  • Substitui dígitos por uma lista de nós por preenchimento. Uma rotina de correspondência de padrões ligeiramente diferente é usada para as unidades.

Exemplo

g[Range[0, 50]]

cinquenta

DavidC
fonte
Transpose@Join? Isso deve ser, certo?
CalculatorFeline
Sim. Obrigado por capturar isso.
DavidC
Espaço logo antes disso.
CalculatorFeline
1

R - 446 444

Vejo que ainda não existe uma solução R, então aqui está uma. A função pega um vetor com números inteiros.

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

Ungolfed

# 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)
Lóris lento
fonte
Você precisa if(v>0)de sua if(i<r)cláusula? R aceita um intervalo como z+1:zquando v==0? Se assim q[z+1:z,j]não seria afetado, eu pensaria. Além disso, R tem uma elsepalavra - chave e algum tipo de else ifpalavra-chave? Nesse caso, você poderá jogar golfe alguns desses condicionais.
Sherlock9
if(v>0)é necessário porque v=0, se o índice estiver fora dos limites (ou seja, tentar obter a linha nrow + 1). R tem else, e eu realmente tentei sua sugestão e usei sempre elseque possível, mas acabou sendo o mesmo número de bytes.
Loris lentos