BrainF ** k, 396 391 bytes
>+>>++++[-<++++++++>]->,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-<+[-<+]->>+[-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>[[->+]->>+<<<+[-<+]->]>+[-<->[[->+]->+>>+<<<<+[-<+]->]<+>->+[->+]->>[->+<]>+>++++++++++>>-<<[-<-[>>]<]<->>>+[-<<<+>>>[-<->]<+++++++++>>>+]++++++++[-<++++<++++++>>]<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]>.>.[-]<[-]<<<[->+<]<<+[-<+]>+]>>[-]<<<-<+[-<+]->>+]
Eu não pude resistir à tentação de fazer este. Pelo menos o triângulo está do lado pontudo para baixo.
A entrada é inserida como uma sequência de caracteres numéricos seguida por uma única nova linha.
A saída conterá um único espaço à direita em cada linha.
Exemplos:
$ bf sd.bf
010
0 1 0
1 1
2
$ bf sd.bf
123456
1 2 3 4 5 6
3 5 7 9 1
8 2 6 0
0 8 6
8 4
2
$ bf sd.bf
9245322
9 2 4 5 3 2 2
1 6 9 8 5 4
7 5 7 3 9
2 2 0 2
4 2 2
6 4
0
Explicação
Como é bastante difícil explicar o código de uma perspectiva funcional, podemos analisá-lo da perspectiva do estado da fita em vários momentos. A idéia central aqui é que o triângulo que produzimos seja inicializado como uma matriz compactada (para BF, enfim) que diminua de tamanho em 1 a cada iteração de um loop. Outro pensamento importante é que usamos 255
para indicar um "espaço reservado" que podemos procurar na fita.
Inicialização
Este é o passo mais fácil. No início do programa, executamos o seguinte:
>+>>++++[-<++++++++>]->
Isso força a fita no seguinte estado (onde >N<
indica o local do ponteiro na fita)
[ 0 1 32 255 >0< 0 0 ...]
O primeiro número aqui é um local "buffer". Não vamos usá-lo a longo prazo, mas é útil simplificar as operações e copiar dados.
O segundo número é o número de espaços que produziremos no início de cada linha, começando após a primeira linha. A primeira linha não terá espaços à esquerda.
O terceiro número é o caractere de espaço que produzimos.
O quarto número é um espaço reservado 255, para que possamos voltar a essa posição com relativa facilidade.
Entrada
Nesta posição, leremos todos os personagens. No final desta etapa, esperamos estar na seguinte situação:
[ 0 1 32 255 a b c d e f ... >255< 0 0 ... ]
Onde a b c d e f ...
indica a sequência de caracteres numéricos que foi inserida (não a nova linha).
Conseguimos isso com o seguinte:
,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-
Existem algumas nuances para isso. Antes de tudo, produziremos cada caractere à medida que os obtivermos e, em seguida, produziremos um espaço após ele. Em segundo lugar, não queremos copiar o valor ASCII para a fita, queremos copiar o dígito numérico real. Terceiro, queremos parar quando atingimos uma nova linha e nos deixamos em um bom lugar naquele momento.
Digamos que nossa opinião seja 6723
. Então, ao ler o primeiro 6
, nossa fita fica assim:
[ 0 1 32 255 >54< 0 0 ...]
Verificamos que esse valor não é igual a 10
(uma nova linha ASCII) com ,----------[++++++++++
. Em seguida, imprimimos o valor e continuamos subtraindo 48 do valor de entrada e adicionando 32 ao valor ao lado ( >>++++++++[-<++++<------>>]<
), deixando-nos aqui:
[ 0 1 32 255 6 >32< 0 ...]
Observe como, durante todo esse processo, podemos assumir que todos os dígitos à direita de nossa entrada são 0 - isso significa que não corremos o risco de arruinar qualquer estado anterior se usarmos valores à direita para calcular 6 * 8
e 4 * 8
.
Agora, produzimos o caractere de espaço que acabamos de gerar e recebemos uma nova entrada, excluindo o espaço que calculamos lá. Eventualmente, a entrada será finalizada por uma nova linha e o loop sairá, deixando um local 255
onde a nova linha estaria ( ,----------]-
). Este é o segundo caractere de espaço reservado que usaremos para navegar na fita. Neste ponto do nosso cenário, nossa fita é exatamente isso:
[ 0 1 32 255 6 7 2 3 >255< 0 0 ... ]
Cálculo
A maneira como isso funciona é que a lista de dígitos entre nossos 255
espaços reservados diminui um a cada iteração do loop. Quando resta apenas um dígito, terminamos e devemos parar imediatamente (observe que, neste momento, todos os dígitos dessa lista já foram emitidos, portanto, não precisamos nos preocupar em produzi-lo novamente).
Vamos agora usar esse truque para navegar para o primeiro 255
espaço reservado: <+[-<+]-
. Isso efetivamente pesquisa a fita à esquerda em busca de um 255
, não alterando nada no meio. Agora que movemos o ponteiro, podemos verificar nossa condição de saída: se houver apenas um dígito na lista, a célula dois espaços à direita serão mantidos 255
. Assim, verificamos isso e iniciamos um loop:>>+[-<<
O primeiro passo no nosso loop é gerar uma nova linha. Então, passamos para a primeira célula (nossa célula tampão), adicionamos 10 a ela e produzimos. O próximo passo é gerar todos os caracteres de espaço iniciais. Depois de produzi-los, aumentamos nossa contagem para o número de espaços à esquerda. Essas etapas são realizadas pelo seguinte:
-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>
O que nos deixa nesse estado:
[ 0 2 32 255 >6< 7 2 3 255 0 0 0 0 0 0 ]
Nosso próximo passo é copiar o primeiro valor da lista, além do segundo espaço reservado 255
:
[[->+]->>+<<<+[-<+]->]
Basicamente, fazemos isso alternando entre os espaços reservados 255
, deixando-nos aqui:
[ 0 2 32 255 >0< 7 2 3 255 0 6 0 0 ... ]
Agora, iniciamos um loop, percorrendo o restante da lista, parando quando clicamos em 255
:>+[-<
Nesse ponto, o dígito à nossa esquerda imediata é sempre 0. Portanto, como os amamos, colocamos um espaço reservado 255
lá para que possamos voltar ao nosso lugar na lista. O próximo passo é mover o segundo lugar na lista para os locais ao redor de onde movemos o primeiro lugar, além do segundo espaço reservado 255
. Essas etapas são realizadas pelo seguinte:
->
[[->+]->+>>+<<<<+[-<+]->]
Deixando-nos aqui: [ 0 2 32 255 255 >0< 2 3 255 7 6 7 0 ]
Agora, ambos 6
e 7
foram movidos para um local onde o cálculo pode ocorrer. Precisamos de duas cópias do 7
porque o próximo número da lista também precisará dele. O 7
imediatamente após o 255
serve a esse propósito, enquanto o outro 7
será consumido pelo cálculo.
Primeiro, adicionamos os dois dígitos:
<+>->+[->+]->>
[->+<]>
Deixando-nos aqui:
[ 0 2 32 255 0 255 2 3 255 7 0 >13< 0 ]
A próxima combinação de etapas é a mais complicada. Precisamos ver se o número para o qual estamos apontando é maior que 10 e, se for, subtraímos 10
. Na realidade, o que fazemos é subtraí-lo 10 e ver se ele atinge 0
algum ponto da subtração. Se isso acontecer, adicionamos 10
novamente mais tarde. No final, devemos ter a soma do módulo 10.
Prepare a 10 to the right
+>++++++++++
Leave yet another 255 for a loop condition later
>>-<<
If the number is greater than 10 end up one space to the left
else one space to the right
[-<-[>>]<]<->
Check if the previous 255 is two spaces to the right and if it is
add 10 back to our sum--we've subtracted too much
>>+[-<<<+>>>[-<->]<+++++++++>>>+]
Neste ponto, alcançamos o objetivo. Nós temos a soma módulo 10! Além disso, independentemente de o número ser maior que 10, acabaremos aqui:
[ 0 2 32 255 0 255 2 3 255 7 0 3 0 0 >0< ]
Nossos próximos objetivos são produzir essa nova soma, segui-la com um espaço e injetá-la novamente em nossa lista. Fazemos isso tudo com nossas técnicas anteriores de 255
-hopping e adicionando 48
à nossa soma, para que não seja abordado em detalhes.
++++++++[-<++++<++++++>>]
<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]
>.>.
E estamos aqui: [ 0 2 32 255 3 255 2 3 255 7 0 0 51 >32< ]
observe como colocamos um 255
espaço reservado adicional após a injeção recente, 3
para não perder o lugar na lista. Neste ponto, produzimos nossa soma e seu espaço, portanto, precisamos limpar e reverter para um estado em que a próxima iteração desse loop funcione. Precisamos limpar nossas células 51
e 32
, mover 7
uma vez para a direita e navegar para o espaço reservado da lista para que possamos começar de novo.
[-]<[-]<<<[->+<]<<+[-<+]
Agora, estamos aqui: [ 0 2 32 255 3 >0< 2 3 255 0 7 0 ... ]
que é exatamente onde queremos estar para a próxima iteração. Portanto, verifique 255 e siga em frente! ( >+]
)
Quando formos retirados do loop, teremos uma lista totalmente nova - composta pelas somas da lista anterior. A primeira vez, ficará assim:
[ 0 2 32 255 3 9 5 0 >0< ]
Agora, queremos repetir todo esse processo em nossa nova lista, para que 255
desça para a esquerda e recomeçemos! Precisamos fazer um pouco de limpeza e >>[-]<<
, em seguida, deixar nosso espaço reservado com <-
. Depois disso, estamos exatamente no mesmo lugar que estávamos após a entrada, para que possamos fazer as mesmas verificações: <+[-<+]->>+
e boom! Temos todo o nosso ciclo! Todos necessidade que é o colchete de fechamento, e quando termina Nós já tudo de saída, de modo que estamos a fazer: ]
.