28
\$\begingroup\$

What general tips do you have for golfing in TI-BASIC for the TI-83/84+ series calculators? I'm looking for ideas which can be applied to code-golf problems and which are also at least somewhat specific to TI-BASIC (e.g. "remove comments" is not an answer).

Please post one tip per answer.

\$\endgroup\$
1
  • 7
    \$\begingroup\$ Please always include which version you are refering to! \$\endgroup\$
    – flawr
    Commented Jun 24, 2015 at 11:39

12 Answers 12

23
\$\begingroup\$

Your calculator is pretty smart at inferring the end of lines for you, and thus you can omit quite a few characters.

:Disp "HELLO WORLD    //is the same as...
:Disp "HELLO WORLD"

For( loops have a syntax like this - For(variable, start, end, increment), but you can omit the increment and it will use 1:

:For(A,1,5     //is the same as...
:For(A,1,5,1)

and you can omit ending parentheses (at the end of lines) across the board:

:Output(1,1,A
:int(A
:round(A
etc.

Tested on my TI-84 Silver Edition calculator

If you think this is more than one idea (inferring endings) then I'll split them up

\$\endgroup\$
3
  • 6
    \$\begingroup\$ ....this is just wrong 😭 \$\endgroup\$
    – Beta Decay
    Commented Jun 23, 2015 at 12:36
  • 2
    \$\begingroup\$ Also, try to rewrite code so you use the least number of closing parentheses. On only the last expression of every line, you get the parentheses for free, so move the most nested statements to the end. That is, not(iPart(B))+(A=5 can be (A=5)+not(iPart(B. \$\endgroup\$
    – lirtosiast
    Commented Jun 23, 2015 at 16:17
  • 4
    \$\begingroup\$ This applies for everything that needs closing, not just parentheses (namely {lists}, "strings" and [[matrices]]). Expressions will automatically be closed when you reach a newline, colon (a stand-in for the newline; doesn't apply to strings, though, as they can contain colons) or the variable assignment arrow (, typed with the STO▶` button). Such a weird feature of the language. \$\endgroup\$
    – user39326
    Commented Jun 23, 2015 at 20:49
16
\$\begingroup\$

Use Ans

If you will only use an expression in the next line, don't store it to a variable! The special Ans variable is a one-byte token that stores the value of the last expression evaluated. Thus:

Xsin(A)->R
Disp R+tanh(R

can be

Xsin(A)
Disp Ans+tanh(Ans

saving two bytes.

\$\endgroup\$
10
\$\begingroup\$

Use a lookup table encoded in floating-point numbers

A slightly advanced tip:

Small lookup tables are useful for code golf: it's very often that we need a function that maps, for example, 0 to 1, 1 to 2, 2 to 1, and everything else to 0. However, TI-BASIC arrays are not suited for this purpose: for one thing, they're one-based, and for another, a value cannot be extracted until the array is stored in Ans or a list variable.

In my answer here, I store a small lookup table in a magic constant in base 11. Simply list the values you want to use,

{0,-1,5,-1,-1,2,9,-1,8,6}

convert to a useful form

{1,0,6,0,0,3,10,0,9,7}

write in your desired base (base 11)

.106003A097

and convert to base 10

-1+int(11fPart(11^Ans.0954191904

The shortest array approach is 8 bytes longer!

{1,0,6,0,0,3,10,0,9,7}-1:Ans(X+1

TI-BASIC only stores floats to 14 decimal digits, so you can store up to 44ish bits but only 14 decimal digits.

This technique can often be improved further by using brute-force search to find a magic constant rather than base-N encoding. I'm still in the process of golfing the answer above, but the lengendary TI-BASIC golfer Weregoose used this method to generate the differences between numbers coprime with 30 (that is, a repeating list of 6, 4, 2, 4, 2, 4, 6, 2 ) on the wiki/forum TI-BASIC Developer with this snippet:

2+2iPart(3fPart(576e^(fPart(I/8

The magic constant 576 was found using Mathematica, but if you don't own a copy use a script in your favorite language.

\$\endgroup\$
6
\$\begingroup\$

Put repeated expressions equation variables.

EX:

Remainder(randInt(1,9),1
Remainder(randInt(1,9),5
Remainder(randInt(1,9),10

Can be:

"randInt(1,9→u
Remainder(u,1
Remainder(u,5
Remainder(u,10

Note: it is hard to find a good use for this, but that does not mean you should forget equation variables :P

Source: http://tibasicdev.wikidot.com/selfmodify

-c4ooo from Omnimaga

\$\endgroup\$
1
  • \$\begingroup\$ In this example, you could save more by adding n to the first expression, along with the Remainder( function. \$\endgroup\$ Commented Oct 5, 2015 at 3:08
6
\$\begingroup\$

Skip unnecessary variable initialization

Current consensus is to allow all code to be run on a fresh interpreter. We can take advantage of this—all uninitialized real variables start at 0 in TI-BASIC, and Xmin starts as the possibly useful value -10. So if you ever need to take a running total in a program that doesn't take input from Ans, or you really need a -10 in one less byte, this tip can help you.

\$\endgroup\$
1
  • \$\begingroup\$ Xmax is 10 and Ymin and Ymax behave similarly, right? Also there are some other graph parameters that have some other values, I think. \$\endgroup\$ Commented Jun 12, 2018 at 10:49
5
\$\begingroup\$

Eliminate End statements for If blocks at the end of a program

Saves two bytes: one for the End and one for the linebreak. It also allows you to use the implied Disp on the last line, often saving an additional byte.

[code]
If A>5
Then
Output(1,1,Ans²+Ans+A
Disp 3ln(A
End
//end of program

Can be:

[code]
If A>5
Then
Output(1,1,Ans²+Ans+A
3ln(A
//end of program
\$\endgroup\$
1
  • \$\begingroup\$ It should be noted that this tip doesn't work for loop blocks. +1 for the good tip though \$\endgroup\$ Commented Apr 30, 2019 at 13:28
5
\$\begingroup\$

Smaller list generation

If you need a list {1,2,...,N}, where N is, say, 42, the obvious way to create it is

seq(X,X,1,42. 

However, one byte smaller than that is a neat hack using the binomcdf( (cumulative binomial distribution) command.

cumSum(binomcdf(41,0

This only works when N is a constant, because the savings comes from replacing N-1 with its value in the code.

There are two cases that allow even shorter code.

If you already have a list L1 of dimension N:

cumSum(1 or L1

If you don't care about order:

randIntNoRep(1,N     ;random permutation of numbers from 1 to N
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Guaranteed to be one byte smaller (and stupidly slower) than seq(X,X,1,N even when N isn't constant is cumSum(1 or rand(N. \$\endgroup\$ Commented Sep 30, 2017 at 3:40
5
\$\begingroup\$

Know your idioms

Here are some snippets I commonly use in code golf:

  • Convert to truth-value (0/1): not(not(Ans, or Ans and 1. Which one to use depends on the parentheses needed.
  • Add one to a truth-value: int(e^(Ans. Saves an open-paren over 1+(Ans. Very useful, because TI-BASIC has one-based arrays.
  • Map {0,1} to {1,-1}: cos(πAns. Saves one byte over 1-2Ans.

  • Sign function of a number: tanh(ᴇ9Ans
  • Round towards positive infinity: -int(-Ans
  • Number of digits in a positive integer: 1+int(log(Ans
  • Complex number to list {Re,Im}: imag(Ans{i,1

  • Convert string to list: seq(inString("...",sub(Ans,X,1)),X,1,length(Ans (where ... is the search string)
  • Chop off first element of a list: ΔList(cumSum(Ans
  • Chop off last element of a list: ΔList(cumSum(Ans)-Ans
  • Check if all elements of list L1 are unique: SortA(L1:min(ΔList(L1
  • Search for the number X in a list (returns first occurrence): 1+sum(not(cumSum(Ans=X
  • Mode of a list when a single mode exists, and the list has at most 10 elements: (ugly, but short): median(Ans,10^(seq(sum(Ans=Ans(X)),X,1,dim(Ans
\$\endgroup\$
2
  • \$\begingroup\$ I really don't understand why the tanh(ᴇ9Ans one works. \$\endgroup\$ Commented Oct 6, 2015 at 22:27
  • 1
    \$\begingroup\$ @SuperJedi224 Well, tanh(0 is zero, and the limits to infinity on the left and right are -1 and 1. It gets exponentially close to those values, so past +-17 or so it's within rounding error of +-1. If the absolute values are greater than 17ish already, we just use tanh( alone. \$\endgroup\$
    – lirtosiast
    Commented Oct 6, 2015 at 22:34
4
\$\begingroup\$

If you find yourself using

0→G ;or any other variable
;other lines of code

Then, you could use (to save a byte):

DelVar G;other lines of code

This is because when you delete a variable (G), it becomes its default value, in this case, 0. Then, you could put another line after the DelVar statement, without a newline. Be careful when putting crucial control statements directly after a DelVar statement.

(Tested on TI-84)

\$\endgroup\$
5
  • \$\begingroup\$ This is rarely useful; variables are initialized to 0 by default, and you can zero Y by doing a ZStandard. \$\endgroup\$
    – lirtosiast
    Commented Oct 4, 2015 at 23:38
  • 1
    \$\begingroup\$ @ThomasKwa It's been useful to me on many instances, esp. when a reset is required partway through execution. \$\endgroup\$ Commented Oct 5, 2015 at 2:59
  • 2
    \$\begingroup\$ In code golf? When? If you show me the program I think I'll be able to optimize out the DelVar. \$\endgroup\$
    – lirtosiast
    Commented Oct 5, 2015 at 3:02
  • \$\begingroup\$ @ThomasKwa Not xode golf per se, rather, programming on low disk space (TI-83). I don-t have the program right now. I'll get back to you on that. \$\endgroup\$ Commented Oct 5, 2015 at 3:16
  • 1
    \$\begingroup\$ After a few minutes of thought, I can think of a couple of scenarios when DelVar can possibly be shortest, like after single-line If statements. \$\endgroup\$
    – lirtosiast
    Commented Oct 5, 2015 at 3:17
4
\$\begingroup\$

Which list variables to use?

When using lists, avoid the default lists L₁ through L₆ in favor of named lists with one-letter names: ᶫA through ᶫZ (where is the little L).

Either one costs two bytes to reference (though L₁ is a single token, it is a two-byte token) but when storing values in a list, you can drop the symbol, saving a byte:

{1,2,3,4,5→ᶫA

can be

{1,2,3,4,5→A

The calculator checks the data type of the expression when deciding where the result is stored.

Similarly, Input A or Prompt A will store to ᶫA if the user enters a list instead of a number.

Several other commands can be used without the , though most of them are rarely used in golfing. For example, Matr►list( allows the to be removed in its third, fourth, and higher arguments.

The general rule is that, if the command takes a list variable name and not a list expression, and if there is no alternative syntax that could put a different kind of variable there, then the command might work with the left off.

This doesn't work with modifying a single entry of a list: 1→ᶫA(3 cannot be changed to 1→A(3.

Of course, the best list variable to use is always Ans.

\$\endgroup\$
2
  • \$\begingroup\$ Wait, what? "Input A" stores to ᶫA if the user enters a list." That means that many of my programs are pretty easy to break. Then it's good that I don't have that many Input programs anyway, I mostly have either small tools with no error checking or complete games that use GetKey instead of Input. \$\endgroup\$ Commented Jun 12, 2018 at 10:53
  • 1
    \$\begingroup\$ If you are really keen on user-proofing your programs against this, you can always store a random value to A and check if it has changed after Input A. \$\endgroup\$ Commented Jun 12, 2018 at 13:24
2
\$\begingroup\$

Know your variable assignment costs

If you use a B-byte expression N times, should you assign it to a variable?

Ans costs 1+N bytes to use (one for the linebreak and one for each time it's used, so use Ans when (B-1)*(N-1)>2. There can be only one Ans per line, so try all values for Ans that might be useful.

Real variables (e.g. X) cost 3+N bytes, so use them when (B-1)*(N-1)>4.

List variables cost 3+2N bytes, so use them when (B-2)*(N-1)>5.

Equation variables are the least useful: they need 4+2N bytes. Use them when (B-2)*(N-1)>6.

Min. bytes in an expression to save
 N \ var. | Ans | Real | List | Eqn
------------------------------------
 2           4     5      8      9
 3           3     4      5      6
 4           2     3      4      5

When a function evaluates to a list, store it to a list rather than an equation variable like u; this saves one byte.

Keep in mind that the presence or absence of close parentheses can often cause storing expressions to be advantageous if they're rearranged.

Now I'll contradict myself and say that one should write code on one line as much as possible. Why? Usually when there's a long repeated expression on a line, it can be simplified.

\$\endgroup\$
1
\$\begingroup\$

int(rand over randInt(

X+int(Yrand is equal to or fewer bytes than randInt(X,Y as randInt is a 2 byte token. Some potential benefits:

X+ can be left out when lower bound is 0, saving two bytes

X+ is necessary before randInt( anyway in certain situations, for example random from a step function like {2,5,8,11}

X+int(Yrand(N can be used just as randInt(X,Y,N to generate a list of N random numbers

Graphscreen initialization

To use functions like Line( easily with pixel coordinates it's necessary to initialize the graphscreen axes to square pixels and remove axes:

AxesOff
84→Xmin
72→Ymax
ZInteger

Clamp

min(U,max(L,N

Where N is the number or algorithm and U and L are upper and lower bounds

Is N in List

max(N={X,Y,Z

More List math

L1*L2→L3

instead of

for(A,1,dim(L1
L1(A)*L2(A→L3(A
End

This also works for things like this:
not(L1
L1 and L2

Output

Disp and Text( can both be chained, so Disp A,B will Display A then B on separate lines and Text(28,40,A,B will print A next to B on one line

If you only need to display a single thing at the end of a program you can drop the Disp command, the final line acts as an implicit Disp

Tech from the optimal movement loop

A lot of these optimizations are part of the tech used to move a character around the screen in the fewest bytes

http://tibasicdev.wikidot.com/movement

Token Size Lists

http://tibasicdev.wikidot.com/tokens

For help scoring

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.