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.
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.
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:
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:
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.
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 ).
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:
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 .
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.
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:
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:
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:
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.
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:
Após o estágio 2 ("calcular o valor máximo de dígitos"), ficamos com isso:
Após o estágio 3 ("subtraia o valor máximo de todos os dígitos no local atual"), a fita ficará assim:
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,1
funciona. 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.