Forte, 101 bytes
1INPUT0
2LET4=(0*(0+1))*5
4END
6PUT42:LET7=6+1
7LET6=6+10
8PUT10:LET9=((9+9)+14)-3:LET3=8+5
3LET8=9-1
Try it online!
I've been wanting to try Forte for a while, and this seemed like a fine challenge for it. It was quite an effort writing the program, then golfing it and making it fit in one-digit numbered lines. It was also quite fun :) Kudos to ais523 for inventing this and many more incredible languages.
Since I'm in the mood I'll write an explanation in details, covering also the basis of the language.
Explanation
First, a very brief introduction for those who don't know this language, you can find the full specification and guide on its esolang page.
The syntax of Forte is similar BASIC, with line numbers prepended to each line, only that in Forte you dont GOTO 10
, you make 10 come to you!
With the command LET, you can assign a number to... another number. If the command LET 10=20
is executed, from now on every time the number 10 is referenced, directly or indirectly (5+5 counts too), it is replaced by 20 instead. This affects line numbers too, so if we were on line 19 when executing that instruction, the next line to be executed will be our old line 10, now line 20.
Now, the actual code (with spaces added for clarity):
1 INPUT 0
This is practically LET 0=<a number taken from stdin>
, in this program 0
is used like a variable, and only in line number 2
2 LET 4=(0*(0+1))*5
4 END
Line 4 is the one that terminates the program, so we want to put it at the position where we are done printing asterisks. How many of them do we need to print, though? As fitting for a "draw a triangle" challenge, the answer is given by triangular numbers!
The formula to calculate the nth triangular number is n*(n+1)/2
. We will print an asterisk every 10 lines, so we multiply it by 10 and get n*(n+1)*5
. Use 0
instead of n
, add parentheses for every operation (always mandatory in Forte), and you get line 2.
6 PUT 42:LET 7=6+1
7 LET 6=6+10
Here we print the asterisks. The ASCII code for *
is 42, so you get what PUT 42
does. The colon separates multiple instructions on the same line, so we then execute LET 7=6+1
. What use do we have in redefining 7 as 6+1? Isn't it the same thing? Let's see what happens next.
Line 7 redefines 6
as 6+10
, so 16
. Ignoring for a moment the rest of the code, this means that when we reach line 16 we will print another asterisk, and then redefine 7
as 6+1
. But now 6
is 16
, so we are redefining it as 16+1
! Line 7 is now line 17 and is the next one to be executed, changing 6
to 6+10
, which means changing 16
to 16+10
, so on line 26 we will print another asterisk, and so on.
Since in Forte a line cannot change its own number, this is the simplest structure for a loop, two lines changing each other's numbers repeatedly. I know this can be quite confusing, but that's kind of the point of the whole language ;)
8 PUT 10:LET 9=((9+9)+14)-3:LET 3=8+5
3 LET 8=9-1
Ok, that line 3 put here may seem out of place, but in Forte line order doesn't matter, only line numbering. I've chosen to put this line at the end because this pair of lines forms again a cycle, redefining each other's numbers, so it's easier to see them together. Moreover, the first time line 3 is executed (when 3 is still equal to 3 and nothing else), it has no effect on the program, redefining 8
as 8
.
As you probably have guessed PUT 10
prints a newline, then the hard part comes. We want each line to have one more asterisk than the one before, so to know where to put the next newline we need to know where the previous one was. To do this, we use another "variable": the number 9
. In practice, when we are about to print a newline on line 8, line 3 will be positioned (near) where the previous newline was printed, we'll use it to calculate where the next newline must be printed and move 9
(near) there. (Remember that line 8 can't move itself). Then we move line 3 a bit further than the current position, and use it to move line 8 to our 9
.
These three numbers (3
,8
, and 9
) were chosen in order not to conflict with any other redefinition of a number, and to be easy to use together (since neither 5
nor 1
will ever be redefined by this program we can do LET 3=8+5
and LET 8=9-1
).
All of these numbers will always be redefined as themselves+10n. This means that 8
will only ever be redefined to numbers ending with an 8 (28,58,98...). This same property is valid for any other number redefinintion in this program (except 0
), because this helped greatly my reasoning while writing the code (if you are crazy enough you can try to golf some bytes by using a smaller step, but I doubt there is much room for golfing without completely changing approach).
So, the actual difficult part of this program: LET 9=((9+9)+14)-3
. This operation can be better explained if expanded to LET 9=(9+(9-(3-4)))+10
, where 4 and 10 represent their respective actual numerical values (in the code they are grouped as 14, 4 wouldn't actually be usable because it was redefined in line 2). As we said before 3
is still placed near the previous newline; we subtract 4 from it to get the previous position of 9
(if 3
is 63, our previous 9
was 59), then we compute the difference between the current and the previous 9
to know how many program-lines have passed since the last newline was printed. We add this value to the current 9
, plus 10 because the next time we will want to print one more asterisk. Our 9
is now where we want to print the next newline, so we move 3
to the current position, it will then move 8
to where it's needed, just before 9
.
Phew, that was long. And hard. No dirty jokes, please
6
Not duplicate, just subset of Generate a right triangle.
– manatwork – 2016-10-10T12:20:48.4772Training spaces allowed on each line? – Luis Mendo – 2016-10-10T12:33:41.797
2Is a trailing new line acceptable? – Fatalize – 2016-10-10T12:34:40.720
1Is a leading newline allowed? – Riley – 2016-10-10T14:38:53.197
I don't see a reason why not. – Sickboy – 2016-10-11T11:35:55.017
For the new challenge, I recommend posting in the sandbox first. I find it very useful for my challenges, even if they seem finished already.
– trichoplax – 2016-10-24T16:47:34.703In the comments you said that a leading new line is allow, but the spec now requires one asterisk in the first line. Which is it? – Riley – 2016-10-24T23:46:18.430
Riley: You can do both, as you please; trichoplax: Thanks, already saw the sandbox :-); Dennis: thanks fr the info! – Sickboy – 2016-10-25T08:52:23.297
Is a preceding new line acceptable? – Stan Strum – 2017-09-19T18:51:02.763
This has already been asked: yes, it is. – Sickboy – 2019-12-11T14:50:05.057