Program Like It’s 1982

Retro
Author

Jim Carr

Published

March 26, 2022

Grab your parachute pants and hair spray. We’re headed back to the 80’s!

History

It’s 1982. A new talk show called “Late Night with David Letterman” has debuted on NBC. The Falklands War has begun. “E.T.: The Extra-Terrestrial” is released, and will become the biggest box office hit of the decade. The first compact discs will soon be produced in Germany. And I’m about to be introduced to something that will dramatically influence both my professional and personal life.

As a teenager, I didn’t have much interest in computers. But then, my good friend Mike got a Commodore VIC-20 (and later, a Commodore 64), and started showing me the cool things he was doing with it. It was fascinating! I started asking my Dad for a computer of my own.

He was hesitant, at first, since home computers of the time were quite expensive. Luckily for me, though, Commodore and Texas Instruments were engaged in a price war, and prices dropped steadily. When the price of the Texas Instruments 99/4A dropped to $150, Dad finally relented.

The Machine and the Software

By today’s standards, the TI-99/4A is a laughably under-powered machine. But with a 3MHz CPU, 16K of RAM, and display resolution of 32 characters/24 lines (text) and 192×256 16 colors (graphics), it was pretty capable as compared to other machines of the era.

The TI had its own flavor of the BASIC programming language baked in: TI-BASIC. (Not to be confused with the language used in Texas Instruments programmable calculators) The language is pretty crude by today’s standards: Lines of code are numbered, and flow control is diverted by referencing the line numbers. No structured code, and certainly nothing even vaguely resembling object-orientation. I thought it was amazing.

Just as it is today, computer owners of the time engaged in a lot of “my machine’s better than yours” puffery. I still laugh thinking about how Mike derided me for not getting a Commodore machine, and I shot right back, telling and showing him the cool stuff I was creating. I fancied myself a “game developer”, creating lots of simple games, and even a couple of pretty complex ones (“Lunar Drop” and “Turbo Tank”). I had so much fun!

To Now

Over the years, I’ve retained a lot of affection for the TI-99/4A. I’ve never forgotten the satisfaction of writing my first programs, and this has stayed with me to this very day. My youngest son actually bought one a few years ago, and it was really cool seeing him get it up and running, and typing a few very simple programs in.

I have a project I’ve worked on off-and-on during the last few years: The translation of a set of astronomical algorithms into various programming languages. I’ve completed implementing the algorithms in Python, C#, and Rust. I’ve also started some work in C, C++, and Java. Recently, it occurred to me: I wonder how difficult it would be to translate one of the simple algorithms into TI-BASIC? I decided to find out.

TI-BASIC

As I mentioned above, TI-BASIC is formatted as numbered lines. Here’s a simple example:

100 CALL CLEAR
110 PRINT "HELLO!"

When this program is run, it clears the screen, and then prints “HELLO!”.

Since you can’t write standalone functions in TI-BASIC, when you have code you want to reuse you must transfer control to that block of code, and then transfer control back when you’re done. For example, in order to reuse the PRINT command from the first example, you’d do something like this:

100 CALL CLEAR
110 GOSUB 140
120 GOSUB 140
130 END
140 PRINT "HELLO!"
150 RETURN

When you run this version of the program, the text “HELLO!” is printed twice.

So, what’s going on here? The GOSUB keyword transfers control to another line of code. On line 110, control is transferred to line 140, where we have our PRINT statement. The RETURN keyword on line 150 then transfers control to the line after the GOSUB (in this case, line 120). Since line 120 is another GOSUB, control is transferred to the PRINT statement again, and then transferred back. Finally, the END keyword on line 130 terminates execution of the program.

The Algorithm

For my algorithm code, I decided to implement “Date of Easter”. Given a year, this algorithm returns the full date for the occurrence of Easter in that year.

Here’s what my C version looks like:

typedef struct pa_full_date {
  int month;
  int day;
  int year;
} TFullDate;
 
TFullDate get_date_of_easter(int input_year) {
  double year = (double)input_year;
 
  double a = (int)year % 19;
  double b = floor(year / 100.0);
  double c = (int)year % 100;
  double d = floor(b / 4.0);
  double e = (int)b % 4;
  double f = floor((b + 8.0) / 25.0);
  double g = floor((b - f + 1.0) / 3.0);
  double h = (int)((19.0 * a) + b - d - g + 15.0) % 30;
  double i = floor(c / 4.0);
  double k = (int)c % 4;
  double l = (int)(32.0 + 2.0 * (e + i) - h - k) % 7;
  double m = floor((a + (11.0 * h) + (22.0 * l)) / 451.0);
  double n = floor((h + l - (7.0 * m) + 114.0) / 31.0);
  double p = (int)(h + l - (7.0 * m) + 114.0) % 31;
 
  double day = p + 1.0;
  double month = n;
 
  TFullDate return_value = {(int)month, (int)day, (int)year};
 
  return return_value;
}

As I started to write the TI-BASIC version, it didn’t take long for me to encounter a problem: TI-BASIC has no modulo operator! The modulo operator (% in the C code above) returns the remainder from a division operation. For example, take a look at this C statement:

int remainder = 14 % 3;

After this statement is executed, the remainder variable contains 2, because 3 divides into 14 four times, with 2 left over.

For TI-BASIC, I wrote my own. My custom modulo subroutine in TI-BASIC looks like this:

530 REM  MODULO SUB
540 MODRESULT=MODX-INT(MODX/MODY)*MODY
550 RETURN

The REM statement on line 530 is a remark, serving the same purpose as a comment in other languages.

Since arguments can’t be passed to a subroutine in TI-BASIC, the MODX and MODY variables must be set before the GOSUB call. A TI-BASIC subroutine also can’t return a value, so after the GOSUB call, you simply use the MODRESULT variable directly.

Translating the rest of the code wasn’t too bad. Here’s what I ended up with:

100 INPUT "YEAR? ":YEAR     
110 GOSUB 130               
120 END                     
130 REM  DATE OF EASTER SUB 
140 MODX=YEAR               
150 MODY=19                 
160 GOSUB 530               
170 A=MODRESULT             
180 B=INT(YEAR/100)         
190 MODX=YEAR               
200 MODY=100                
210 GOSUB 530               
220 C=MODRESULT             
230 D=INT(B/4)              
240 MODX=B                  
250 MODY=4                  
260 GOSUB 530               
270 E=MODRESULT             
280 F=INT((B+8)/25)         
290 G=INT((B-F+1)/3)        
300 MODX=((19*A)+B-D-G+15)  
310 MODY=30                 
320 GOSUB 530               
330 H=MODRESULT             
340 I=INT(C/4)              
350 MODX=C                  
360 MODY=4                  
370 GOSUB 530               
380 K=MODRESULT             
390 MODX=(32+2*(E+I)-H-K)   
400 MODY=7                  
410 GOSUB 530               
420 L=MODRESULT             
430 M=INT((A+(11*H)+(22*L))/451)
440 N=INT((H+L-(7*M)+114)/31)
450 MODX=(H+L-(7*M)+114)    
460 MODY=31                 
470 GOSUB 530               
480 P=INT(MODRESULT)        
490 DAY=P+1                 
500 MONTH=N                 
510 PRINT "DATE OF EASTER FOR";YEAR;"IS";MONTH;DAY;YEAR
520 RETURN                  
530 REM  MODULO SUB         
540 MODRESULT=MODX-INT(MODX/MODY)*MODY
550 RETURN                  

The program uses two subroutines: the “Date of Easter” logic starting at line 130, and the modulo operation at line 530.

When the program is run, it prompts for a year, and then displays the full date for Easter in that year. Example:

.>RUN                         
YEAR? 2013                  
DATE OF EASTER FOR 2013 IS 3 31 2013

** DONE **                  

This was a lot of fun to write. I hadn’t written any significant TI-BASIC code for 35+ years, and it was quite a nostalgic experience working through this.

(But, I’ll also say I’m grateful I don’t have to write all of my code this way anymore!)