BrainF**k, 396 391 bytes
>+>>++++[-<++++++++>]->,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-<+[-<+]->>+[-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>[[->+]->>+<<<+[-<+]->]>+[-<->[[->+]->+>>+<<<<+[-<+]->]<+>->+[->+]->>[->+<]>+>++++++++++>>-<<[-<-[>>]<]<->>>+[-<<<+>>>[-<->]<+++++++++>>>+]++++++++[-<++++<++++++>>]<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]>.>.[-]<[-]<<<[->+<]<<+[-<+]>+]>>[-]<<<-<+[-<+]->>+]
I couldn't resist the temptation to do this one. At least the triangle is pointy-side down.
Input comes in as a string of numeric characters followed by a single newline.
Output will contain a single trailing space on every line.
Examples:
$ 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
Explanation
Since it's rather difficult to explain the code from a functional perspective, we can instead look at it from the perspective of the state of the tape at various times. The core idea here is that the triangle we output is initialized as a tightly-packed (for BF, anyway) array that shrinks in size by 1 every iteration of a loop. Another important thought is that we use 255
to indicate a "placeholder" that we can search for on the tape.
Initialization
This is the easiest step. At the start of the program, we execute the following:
>+>>++++[-<++++++++>]->
This forces the tape into the following state (where >N<
indicates the location of the pointer on the tape)
[ 0 1 32 255 >0< 0 0 ...]
The first number here is a "buffer" location. We're not going to use it on a long-term basis, but it's useful to make little operations simpler and for copying data around.
The second number is the number of spaces that we'll be outputting at the start of each line, starting after the first line. The first line will have no leading spaces.
The third number is the space character we output.
The fourth number is a placeholder 255, so that we can get back to this position relatively easily.
Input
From this position, we will read in all of the characters. At the end of this step, we hope to be in the following situation:
[ 0 1 32 255 a b c d e f ... >255< 0 0 ... ]
Where a b c d e f ...
indicates the string of numeric characters that was input (not the newline).
We accomplish this with the following:
,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-
There are some nuances to this. First of all, we will output each character as we get them, and then output a space after it. Secondly, we don't want to copy the ASCII value to the tape, we want to copy the actual numeric digit. Third, we want to stop when we hit a newline and leave ourselves in a good place at that time.
Say our input is 6723
. Then, upon reading the first 6
, our tape looks like this:
[ 0 1 32 255 >54< 0 0 ...]
We check that this value is not equal to 10
(an ASCII newline) with ,----------[++++++++++
. We then print out the value and continue by simultaneously subtracting 48 from the input value and adding 32 to the value next to it (>>++++++++[-<++++<------>>]<
), leaving us here:
[ 0 1 32 255 6 >32< 0 ...]
Notice how throughout this process we can assume that all digits to the right of our input are 0--this means that we're not in danger of ruining any previous state if we use values to the right to calculate 6 * 8
and 4 * 8
.
Now we output the space character we just generated, and take in a new input, deleting the space we calculated there. Eventually, the input will be terminated by a new line and the loop will exit, leaving a 255
where the newline would have been (,----------]-
). This is the second placeholder character we will use to navigate the tape. At this point in our scenario, our tape is exactly this:
[ 0 1 32 255 6 7 2 3 >255< 0 0 ... ]
Calculation
The way this works is that the list of digits between our 255
placeholders is going to shrink by one every iteration of the loop. When it only has 1 digit left in it, we're done and should halt immediately (Note that, at this point, every digit in that list has already been output, so we don't have to worry about outputting it again).
We now use this trick to navigate to the first 255
placeholder: <+[-<+]-
. This effectively searches the tape to the left for a 255
, changing nothing in between. Now that we've moved the pointer, we can check our exit condition: if there's only one digit in the list, then the cell two spaces to the right will hold 255
. Thus, we check against that and start a loop: >>+[-<<
The first step in our loop is to output a newline. So we move to the first cell (our buffer cell), add 10 to it and output. The next step is to output all leading space characters. After outputting them, we increment our count for number of leading spaces. These steps are accomplished by the following:
-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>
Which leaves us in this state:
[ 0 2 32 255 >6< 7 2 3 255 0 0 0 0 0 0 ]
Our next step is to copy the first value in the list over, past the second placeholder 255
:
[[->+]->>+<<<+[-<+]->]
We essentially do this by hopping back and forth between our placeholder 255
s, leaving us here:
[ 0 2 32 255 >0< 7 2 3 255 0 6 0 0 ... ]
We now start a loop, iterating through the rest of the list, stopping when we hit 255
: >+[-<
At this point, the digit to our immediate left is always 0. So, because we love them, we pop a placeholder 255
in there so that we can come back to our place in the list. The next step is to move the second place in the list to locations surrounding where we moved the first place to, past the second placeholder 255
. These steps are accomplished by the following:
->
[[->+]->+>>+<<<<+[-<+]->]
Leaving us here: [ 0 2 32 255 255 >0< 2 3 255 7 6 7 0 ]
Now, both the 6
and 7
have been moved to a location where the calculation can occur. We need two copies of the 7
because the next number in the list will need it as well. The 7
immediately after the 255
serves this purpose, whereas the other 7
will be consumed by the calculation.
First, we add the two digits:
<+>->+[->+]->>
[->+<]>
Leaving us here:
[ 0 2 32 255 0 255 2 3 255 7 0 >13< 0 ]
The next combination of steps is the most complicated. We need to see if the number we're pointing to is larger than 10, and if it is, we subtract 10
. In reality, what we do is we subtract 10 from it and see if it hits 0
at any point in the subtraction. If it does, we add 10
back on later. At the end of this, we should have the sum 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
>>+[-<<<+>>>[-<->]<+++++++++>>>+]
At this point, we've accomplished the goal. We have the sum modulo 10!
Also, whether or not the number was greater than 10, we'll end up here:
[ 0 2 32 255 0 255 2 3 255 7 0 3 0 0 >0< ]
Our next goals are to output this new sum, follow it with a space, and inject it back into our list. We do this all with our previous techniques of 255
-hopping and adding 48
to our sum, so I won't cover it in detail.
++++++++[-<++++<++++++>>]
<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]
>.>.
And we're here: [ 0 2 32 255 3 255 2 3 255 7 0 0 51 >32< ]
Notice how we put an additional 255
placeholder after our newly-injected 3
so that we don't lose place in the list. At this point, we have output our sum and its space, so we need to clean up and revert to a state where the next iteration of this loop is going to work. We need to clear out our 51
and 32
cells, move the 7
once to the right, and navigate to our list placeholder so that we can start over.
[-]<[-]<<<[->+<]<<+[-<+]
Now, we're here: [ 0 2 32 255 3 >0< 2 3 255 0 7 0 ... ]
Which is exactly where we want to be for our next iteration. So check for 255 and move on! (>+]
)
When we get dropped off from the loop, we're going to have a whole new list--made up of the sums from the previous list. The first time, it'll look like this:
[ 0 2 32 255 3 9 5 0 >0< ]
Now we want to repeat that whole process on our new list, so we plop a 255
down to the left and start all over! We need to do a little bit of cleanup with >>[-]<<
, and then drop our placeholder with <-
. After that, we're in exactly the same place as we were after input, so we can get away with doing the same checks: <+[-<+]->>+
, and boom! We've got our full loop! All we need is the closing bracket, and when it ends we've already output everything, so we're done: ]
.