Almost a year ago, I discussed on the Cemetech Discord server a terrible yet vaguely interesting programming challenging: TI-BASIC using only For( loops. Beyond just basic control flow, For( loops are capable of storing and adding variables, which can then be extended to multiplication, division, and pretty much any other math operation you'd need to do. Conditional statements are also quite easy, since For( loops only loop if the start is smaller than the end.


Code:
:A->B
becomes (when used before a loop)
:For(B,A,A
or (when used inside a loop)
:For(B,0,0,A:End


Code:
:2A->A
becomes
:For(A,A,A,A:End


Code:
:If A>=B
becomes
:For(X,B,A


Unfortunately, I/O presents a bit of challenge to the "language" I've dubbed For(T,R,A,N. The easiest solution is to allow Input and Disp commands; this is not particularly pure, however, so an alternative is to allow only one form of program input, via Ans, and program output dictated by the value of particular variables to be read at the end of execution. Neither are great, but what can you expect from TI-BASIC using only For( loops?

With this in mind, here are some other sample programs, which use the Disp/Input method:

Fibonacci generator

Code:
:Input M
:For(A,0,0:For(B,1,1
:For(D,2,M
:For(C,A,A,B:End
:For(A,B,0:End
:For(B,C,0:End
:Disp B
:End


Prime generator

Code:
:Input M
:Disp 2
:For(P,3,M,2
:For(Q,P,P,-1:End
:For(D,3,Q,2
:For(R,P,D,-D:End
:For(S,R,0
:For(D,Q,Q,Q:End
:End:End
:For(Q,Q,Q,Q:End
:For(S,D,Q
:Disp P
:For(S,Q,Q:End
:End:End


You'll notice the above program also negates a variable, which isn't particularly pure either. To formalize everything, here is the set of allowed tokens and commands for For(T,R,A,N as determined by myself and community consensus:
    Integer constants -- YES: 0, 7, -3, 12384 -- NO: 8.7, 9E15, pi, 2/3
    Real variables -- YES: A, B, Q, theta -- NO: I%, u, Str3, n
    For( commands -- YES: For(A,-1,B,Q -- NO: For(A,7.3,BC,-B
    Disp commands -- YES: Disp -7, Disp Q -- NO: Disp A+B, Disp CD (use sparingly)
    Ans (for input) -- YES: For(A,Ans,0 -- NO: For(A,AnsQ,3

Everything else, such as lists, strings, math commands, additional control flow, and operations on variables are disallowed. Seems pure enough, I guess, and just hard enough to make subtraction non-trivial.

So, yeah. This is what pops into my head messing with my calculator at 2 AM. Suggestions, additional programs, and convoluted attempts at a C compiler are welcome.
This is hilarious and impressive, and maybe useless. I wonder is this can be done with IS>( and DS<( instead of For(?
You'd probably have to include Lbl and Goto as well to do anything interesting with IS>( and DS<(. I was also going to say that you'd need to use the store operator, too, since IS>( and DS<( don't set a value, but you could probably run a loop decrementing or incrementing the number until the value is correct.
Though CBG is probably correct on the above, I think I'll post a neat tip for posterity about emulating Lbl and Goto in For(T,R,A,N

Consider the following program, which we'll call "prgmDEMO". For legibility in my examples, I use If statements and explicit incrementing, but this is accomplishable with for loops too.

Code:

Disp "A
Lbl SUB
Disp "B
Goto SUB


This is not very interesting and can trivially be written as a single for loop, but we're more interested in the process. I assume programs are run with a freshly reset calc.

To refactor this into only using a for loop:

Code:

For(A,0,2
If A>=1
Then
Disp "B
Else
Disp "A
End
1->A
End


These can be chained like this, which has some more explanation:

Code:

// 0 is the starting condition, 1000 is the ending condition.
For(A,0,1000
If A>=1
Then
If A>=2
Then
// A==2
Disp "C
1000->A // A being 1000 at the end of our code means we should exit
Else
// A==1
Disp "B
2->A
End
Else
// A==0, which is the starting condition- this is the entry point of our program
Disp "A
End
End


Note that there's a little bit of extra logic required because I don't think Else exists in this format, but the idea is what I wanted to present.

I think that variables, IO through Ans, For(, End, and commas are probably all you need. I don't think you'll even need the 4th parameter of For( for anything, but it does speed things up significantly.
I made an interpreter for For(T,R,A,N in JavaScript that you can run in your browser (and it took me way too long, too!).

Limitations:
- Subset of the language. I debated between allowing Input and not- it'd take me all of a few minutes to do, but I wanted to get it out. For now, you can specify input in Ans using the tools on the bottom right.
- My parser probably has some major bugs- if it parses anything blatantly wrong or throws a crazy error let me know in an issue or ping me on IRC or something.
- Nothing is saved.
- Basically every part of the whole system attempts to detect infinite loops (read: "if it takes longer than a couple seconds I detect an infinite loop"). If somehow this breaks and your browser hangs for longer than like 10 seconds, submit your code in an issue or ping me in IRC etcetcetc

edit:
- also my parser is so bad it just.. silently and incorrectly deals with any complete nonsense you type in there.
A fun additional quirk about For(T,R,A,N that has been noted before in various places is that For( loops don't do overflow checks like math expressions do, allowing variables in For(T,R,A,N to exceed the artificial 10^100 limit and go all the way to 10^128 (and similarly negative).
Alright, I think it would be totally rad to have a compiler from "something not terrible to work in" -> this, and I'm totally down for making it but there are a couple routines missing.

Therefore, I propose a golfing challenge: Make routines that can do the following operations in For(T,R,A,N so people can make compilers.

Here's the minimum that I think we should attempt first:

Integer Arithmetic:
# -> A (trivial)
A -> B (trivial)
~A -> B (nontrivial)
A + B -> C (trivial)
A - B -> C (nontrivial)
A * B -> C (trivial)
A / B -> A (nontrivial)

Boolean Logic:
One of:
- A nor B -> C
- A nand B -> C
- or, pick a set from the list here https://en.wikipedia.org/wiki/Functional_completeness#Minimal_functionally_complete_operator_sets

Conditionals:
If A (probably not too hard)


I think I'll define "best entry" as whoever has the least [size in bytes] * (1 + [number of variables modified besides the output])

So if I'm reinventing the wheel and doing B -> A and I somehow come up with a 20 byte solution that modifies B, C, and D, my score would be 20*4, or 80, which sucks.

Code:
(+)#->A     | 6  | For(A,#,0:End
A -> B      | 8  | For(B,A,0:End
~A -> B     | 58 | For(B,0,0:End:For(X,0,A:For(B,B,B,~1:End:End
A + B -> C  | 10 | For(C,A,A,B:End
A - B -> C  | 58 | For(C,A,A:End:For(X,0,B:For(C,C,C,~1:End:End
A * B -> C  | 58 | For(C,0,~1:End:For(X,1,A:For(C,C,C,B:End:End
A >= 0 -> B | 20 | For(B,0,A:End:For(B,B,2,~1:End
If A>=#:Then| 6  | For(A,#,A [will repeat is A!=#]
If A<=#:Then| 6  | For(A,A,# [will repeat is A!=#]

And for the crowning joule on my little pile,

Code:
ceil( A / B ) -> C

For(Y,0,A                                       | For(Y,0,A
For(D,0,~1:End:For(X,1,Y:For(D,D,D,B:End:End    | Y*B->D
For(X,1,A:For(D,D,D,~1:End:End                  | D-A->D
For(D,0,D:End:For(D,D,2,~1:End                  | D>=0->D
For(D,1,D                                       | If D>0:Then
For(C,Y,0:End                                   | Y->C
For(Y,A,0:End                                   | A->Y
End                                             | End
End                                             | End
With 107 bytes * (1 + 3 variables) = 428 points.

#ti-basic wrote:
Zeda: Division will be hell
Zeda: But doable
iPhoenix: I think the language may need some changes to subtract
iPhoenix: I'm not convinced it's possible
I'm still not sure whether iPhoenix was referring to division or subtraction, but they are both here, so it doesn't matter Razz

The division, at least, is definitely not optimal, but for now I'm done. Enjoy.
I don't think computing explicit scores for these snippets is all that important at the moment; if anything, minimizing vars used beyond the output should greatly favored to maximize utility. Nonetheless, here are my operand solutions thus far (with some extras):

Code:
A->B (nonzero)
:For(B,0,0,A:End
A->B (all integers)
:For(B,A,A:End
:For(B,B,B,-1:End
A+B->C (nonzero addend)
:For(C,A,A,B:End
A+B->C (non-negative addend)
:For(C,0,-1:End
:For(B,1,B
:For(C,C,C:End
:End
:For(B,B,B,-1:End
~A->B (non-negative)
:For(B,0,-1:End
:For(A,1,A
:For(B,B,B,-1:End
:End
:For(A,A,A,-1:End
~A->B (non-positive)
:For(B,0,-1:End
:For(A,-1,A,-1
:For(B,B,B:End
:End
:For(A,A,A:End
~A->B (all integers)
:For(B,0,-1:End
:For(C,1,A
:For(B,B,B,-1:End
:End
:For(C,A,-1
:For(B,B,B:End
:End
A-B->C (nonzero minuend, non-negative subtrahend)
:For(C,0,0,A:End
:For(B,1,B
:For(C,C,C,-1:End
:End
:For(B,B,B,-1:End
AB->C (A must be non-negative; B must be nonzero)
:For(C,0,-1:End
:For(A,1,A
:For(C,C,C,B:End
:End
:For(A,A,A,-1:End
max(A,B->C
:For(C,B,B,-1:End
:For(C,A,C:End
A/B->C (dividend & divisor have same sign, or dividend is zero)
:For(C,0,-1:End
:For(D,1,A,B
:For(C,C,C:End
:End

and some control flow implements:

Code:
If A=B
:For(C,A,B:For(C,B,A
If A (non-negative)
:For(B,1,A
If A (non-positive)
:For(B,A,-1
If A (all integers)
:For(B,-1,-2
:For(C,A,-1
:For(B,B,B:End
:End
:For(C,A,B:End
:For(C,1,C
While A (non-negative)
:For(B,1,0,-1
:For(A,1,A
:For(B,2,1:End
:End
:For(A,A,A,-1:End
While A (non-positive)
:For(B,1,0,-1
:For(A,-1,A,-1
:For(B,2,1:End
:End
:For(A,A,A:End
While A (all integers)
:For(B,1,0,-1
:For(C,1,A
:For(B,2,1:End
:End
:For(C,A,-1
:For(B,2,1:End
:End

That should cover all the requested non-Boolean operations, assuming you negate things where necessary to deal with signs (e.g. negate both ops before multiplying two negative numbers). The only one I've yet to see a good way to do is NOR/NAND, or perhaps NOT & OR individually.
Here's an integer root algorithm adapted from a Minecraft datapack that adapted it from the Babylonian method, where the input A is assumed to be positive. There's probably room to reduce the number of used vars:

Code:
:For(D,A,-1:End
:For(W,4,3,-1
:For(B,D,-1:End
:For(M,D,-1:End
:For(P,D,D,D:End
:For(N,M,M,M:End
:For(N,N,N,-1:End
:For(M,0,-1:End
:For(N,1,N,2
:For(M,M,M,N:End
:End
:For(A,1,A
:For(M,M,M,-1:End
:End
:For(A,A,A,-1:End
:For(N,0,-1:End
:For(S,1,M,P
:For(N,N,N:End
:End
:For(N,1,N
:For(D,D,D,-1:End
:End
:For(M,B,D:For(M,D,B
:For(W,1,0:End
:End:End
:For(W,W,W:End
:End

This routine only requires only division and one multiplication per cycle, with the multiplication being accomplished by an in-place squaring snippet:

Code:
:For(N,M,M,M:End
:For(N,N,N,-1:End
:For(M,0,-1:End
:For(N,1,N,2
:For(M,M,M,N:End
:End

Which computes M^2->M using only N; bonus points to first person to identify how it works. I wonder though if there is a way to square M using only M itself...
The remaining Boolean snippets:

Code:
not(A->B (non-negative)
:For(B,0,-1:End
:For(A,0,A
:For(B,1,0:End
:End
:For(A,A,A,-1:End
not(A->B (non-positive)
:For(B,0,-1:End
:For(A,0,A,-1
:For(B,1,0:End
:End
:For(A,A,A:End
not(A->B (all integers)
:For(B,0,-1:End
:For(C,0,A:For(C,A,0
:For(B,1,0:End
:End:End
not(A)not(B->C
:For(C,0,-1:End
:For(D,0,A:For(D,A,0
:For(D,0,B:For(D,B,0
:For(C,1,0:End
:End:End
:End:End

This should be sufficient to get cracking on a compiler out of some higher language.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement