BrainF ** k, 396 391 byte
>+>>++++[-<++++++++>]->,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-<+[-<+]->>+[-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>[[->+]->>+<<<+[-<+]->]>+[-<->[[->+]->+>>+<<<<+[-<+]->]<+>->+[->+]->>[->+<]>+>++++++++++>>-<<[-<-[>>]<]<->>>+[-<<<+>>>[-<->]<+++++++++>>>+]++++++++[-<++++<++++++>>]<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]>.>.[-]<[-]<<<[->+<]<<+[-<+]>+]>>[-]<<<-<+[-<+]->>+]
Non ho resistito alla tentazione di farlo. Almeno il triangolo è rivolto verso il basso.
L'input arriva come una stringa di caratteri numerici seguita da una singola nuova riga.
L'output conterrà un singolo spazio finale su ogni riga.
Esempi:
$ 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
Spiegazione
Poiché è piuttosto difficile spiegare il codice da una prospettiva funzionale, possiamo invece guardarlo dalla prospettiva dello stato del nastro in varie occasioni. L'idea di base qui è che il triangolo che emettiamo viene inizializzato come un array compatto (per BF, comunque) che si restringe di dimensioni di 1 ogni iterazione di un ciclo. Un altro pensiero importante è che usiamo 255
per indicare un "segnaposto" che possiamo cercare sul nastro.
Inizializzazione
Questo è il passo più semplice. All'inizio del programma, eseguiamo quanto segue:
>+>>++++[-<++++++++>]->
Ciò forza il nastro nel seguente stato (dove >N<
indica la posizione del puntatore sul nastro)
[ 0 1 32 255 >0< 0 0 ...]
Il primo numero qui è una posizione "buffer". Non lo useremo a lungo termine, ma è utile per semplificare le operazioni e per copiare i dati.
Il secondo numero è il numero di spazi che verrà distribuito all'inizio di ogni riga, iniziando dopo la prima riga. La prima riga non avrà spazi iniziali.
Il terzo numero è il carattere spaziale che emettiamo.
Il quarto numero è un segnaposto 255, in modo che possiamo tornare in questa posizione relativamente facilmente.
Ingresso
Da questa posizione, leggeremo tutti i personaggi. Alla fine di questo passaggio, speriamo di trovarci nella seguente situazione:
[ 0 1 32 255 a b c d e f ... >255< 0 0 ... ]
Dove a b c d e f ...
indica la stringa di caratteri numerici che è stata immessa (non la nuova riga).
Realizziamo questo con il seguente:
,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-
Ci sono alcune sfumature a questo. Prima di tutto, daremo in uscita ogni personaggio man mano che li otteniamo, e quindi produciamo uno spazio dopo di esso. In secondo luogo, non vogliamo copiare il valore ASCII sul nastro, vogliamo copiare la cifra numerica effettiva. Terzo, vogliamo fermarci quando colpiamo una newline e ci lasciamo in un buon posto in quel momento.
Di 'che il nostro input è 6723
. Quindi, dopo aver letto il primo 6
, il nostro nastro si presenta così:
[ 0 1 32 255 >54< 0 0 ...]
Controlliamo che questo valore non sia uguale a 10
(una nuova riga ASCII) con ,----------[++++++++++
. Quindi stampiamo il valore e continuiamo sottraendo contemporaneamente 48 dal valore di input e aggiungendo 32 al valore accanto ad esso ( >>++++++++[-<++++<------>>]<
), lasciandoci qui:
[ 0 1 32 255 6 >32< 0 ...]
Si noti come durante questo processo possiamo supporre che tutte le cifre a destra del nostro input siano 0 - questo significa che non corriamo il rischio di rovinare alcuno stato precedente se usiamo i valori a destra per calcolare 6 * 8
e 4 * 8
.
Ora produciamo il carattere dello spazio che abbiamo appena generato e riceviamo un nuovo input, eliminando lo spazio che abbiamo calcolato lì. Alla fine, l'input verrà terminato da una nuova riga e il loop uscirà, lasciando un punto in 255
cui la nuova riga sarebbe stata ( ,----------]-
). Questo è il secondo personaggio segnaposto che useremo per navigare nel nastro. A questo punto del nostro scenario, il nostro nastro è esattamente questo:
[ 0 1 32 255 6 7 2 3 >255< 0 0 ... ]
Calcolo
Il modo in cui funziona è che l'elenco delle cifre tra i nostri 255
segnaposto si ridurrà di uno ogni iterazione del ciclo. Quando è rimasta solo una cifra, abbiamo finito e dovremmo fermarci immediatamente (nota che, a questo punto, ogni cifra in quella lista è già stata emessa, quindi non dobbiamo preoccuparci di inviarla di nuovo).
Ora usiamo questo trucco per navigare al primo 255
segnaposto: <+[-<+]-
. Questo cerca efficacemente il nastro a sinistra per un 255
, senza cambiare nulla nel mezzo. Ora che abbiamo spostato il puntatore, possiamo verificare la nostra condizione di uscita: se c'è solo una cifra nell'elenco, allora la cella con due spazi a destra conterrà 255
. Quindi, controlliamo contro questo e iniziamo un ciclo:>>+[-<<
Il primo passo nel nostro ciclo è quello di creare una nuova riga. Quindi passiamo alla prima cella (la nostra cella buffer), aggiungiamo 10 e output. Il passaggio successivo consiste nell'output di tutti i caratteri spaziali iniziali. Dopo averli emessi, aumentiamo il nostro conteggio per il numero di spazi iniziali. Questi passaggi sono eseguiti dai seguenti:
-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>
Che ci lascia in questo stato:
[ 0 2 32 255 >6< 7 2 3 255 0 0 0 0 0 0 ]
Il nostro prossimo passo è copiare il primo valore nell'elenco, oltre il secondo segnaposto 255
:
[[->+]->>+<<<+[-<+]->]
Sostanzialmente lo facciamo saltando avanti e indietro tra i nostri segnaposto 255
, lasciandoci qui:
[ 0 2 32 255 >0< 7 2 3 255 0 6 0 0 ... ]
Ora iniziamo un ciclo, ripetendo il resto dell'elenco, fermandoci quando colpiamo 255
:>+[-<
A questo punto, la cifra alla nostra sinistra immediatamente è sempre 0. Quindi, poiché li adoriamo, inseriamo un segnaposto 255
in modo che possiamo tornare al nostro posto nell'elenco. Il passaggio successivo è spostare il secondo posto nell'elenco nelle posizioni circostanti in cui abbiamo spostato il primo posto, oltre il secondo segnaposto 255
. Questi passaggi sono eseguiti dai seguenti:
->
[[->+]->+>>+<<<<+[-<+]->]
Lasciandoci qui: [ 0 2 32 255 255 >0< 2 3 255 7 6 7 0 ]
Ora, sia l' 6
e 7
sono stati spostati in una posizione in cui può verificarsi il calcolo. Abbiamo bisogno di due copie del 7
perché anche il prossimo numero nell'elenco ne avrà bisogno. Il 7
immediatamente dopo 255
serve a questo scopo, mentre l'altro 7
sarà consumato dal calcolo.
Innanzitutto, aggiungiamo le due cifre:
<+>->+[->+]->>
[->+<]>
Lasciandoci qui:
[ 0 2 32 255 0 255 2 3 255 7 0 >13< 0 ]
La prossima combinazione di passaggi è la più complicata. Dobbiamo vedere se il numero a cui stiamo puntando è maggiore di 10 e se lo è, sottraggiamo 10
. In realtà, ciò che facciamo è sottrarre 10 da esso e vedere se colpisce 0
in qualsiasi punto della sottrazione. In tal caso, aggiungeremo 10
più tardi. Alla fine, dovremmo avere la somma modulo 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
>>+[-<<<+>>>[-<->]<+++++++++>>>+]
A questo punto, abbiamo raggiunto l'obiettivo. Abbiamo la somma modulo 10! Inoltre, indipendentemente dal fatto che il numero fosse maggiore di 10, finiremo qui:
[ 0 2 32 255 0 255 2 3 255 7 0 3 0 0 >0< ]
I nostri prossimi obiettivi sono produrre questa nuova somma, seguirla con uno spazio e reinserirla nel nostro elenco. Facciamo tutto questo con le nostre precedenti tecniche di 255
-hopping e aggiunta 48
alla nostra somma, quindi non lo tratterò in dettaglio.
++++++++[-<++++<++++++>>]
<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]
>.>.
E siamo qui: [ 0 2 32 255 3 255 2 3 255 7 0 0 51 >32< ]
notate come inseriamo un 255
segnaposto aggiuntivo dopo la nostra nuova iniezione in 3
modo da non perdere posto nella lista. A questo punto, abbiamo generato la nostra somma e il suo spazio, quindi abbiamo bisogno di ripulire e tornare a uno stato in cui la prossima iterazione di questo ciclo funzionerà. Abbiamo bisogno di cancellare il nostro 51
e le 32
cellule, spostare il7
volta verso destra e navigare verso il segnaposto del nostro elenco in modo da poter ricominciare da capo.
[-]<[-]<<<[->+<]<<+[-<+]
Ora siamo qui: [ 0 2 32 255 3 >0< 2 3 255 0 7 0 ... ]
che è esattamente dove vogliamo essere per la nostra prossima iterazione. Quindi controlla 255 e vai avanti! ( >+]
)
Quando usciremo dal ciclo, avremo un nuovo elenco - composto dalle somme dell'elenco precedente. La prima volta, sembrerà così:
[ 0 2 32 255 3 9 5 0 >0< ]
Ora vogliamo ripetere l'intero processo nel nostro nuovo elenco, quindi ploppiamo 255
verso il basso a sinistra e ricominciamo da capo! Dobbiamo fare un po 'di pulizia con >>[-]<<
, quindi rilasciare il nostro segnaposto <-
. Dopodiché, siamo esattamente nello stesso posto in cui eravamo dopo l'input, quindi possiamo cavarcela facendo gli stessi controlli: <+[-<+]->>+
e boom! Abbiamo il nostro ciclo completo! Tutti abbiamo bisogno è la parentesi di chiusura, e quando finisce abbiamo già uscita tutto, così abbiamo finito: ]
.