Optimizing BASIC, is it possible, is it a thing? My magic 8-ball says “signs point to yes!” and I’d say the 8-ball is correct. Allen Huffman of Sub-Etha software started a blog with a ton of great ideas, they start here: http://subethasoftware.com/2015/01/03/optimizing-color-basic/ If you search the Color Computer Archive for “20 Tips”, you’ll find a link to “20 Tips ‘n Hints to Shorten and Speedup Basic Programs.zip” which points you to this disk image which is an actual program written in BASIC that is somewhat of a “Poor man’s PowerPoint” it’s a series of text screens with tips and tricks for making BASIC programs run faster.
What is the secret to optimizing a slow and interpretive language? Part of that is understanding how the BASIC interpreter works, and using that knowledge to your advantage to avoid any inefficiencies. Allen does a great job in his blog series, so I’m going to avoid being completely redundant, but I’ll share some basic and specific examples of things I’ve done, and will continue to do, to tweak the code to get it running as fast as possible.
Here are some highlights:
Variables process faster than constants. Instead of saying X=X+1 which is adding the constant number “1” to variable X, you could have a separate variable A, for example, and code something like A=1:X=X+A. The reason? The number 1 in your BASIC statement is processed as ASCII TEXT first, that text then needs to be converted to a floating point decimal number, and then the math can be done based on that. Because BASIC is interpreted, that TEXT-to-Floating Point Decimal conversion needs to happen every time that line of code is executed by the interpreter. A variable, however, is reserved in RAM, and doesn’t need any conversions, it just needs to be called, so a step is removed from the interpreter’s processing needs, and the result is faster access and execution. In making a video game, where every second counts, shaving time of your game loops and routines really helps, this global change to all of my routines and formulas continues to be refined as I develop.
Division and Multiplication are some of the slowest operations. I’ve been told that having BASIC do a divide or multiply is one of the slowest things to ask the interpreter to do. There are enough smart people in our community that I don’t need to question this, I just accept it, and based on that, I account for it. One of the concessions I made to speed up the game, and make object locations and detection quicker and easier, was to break my screen into a 16*12 grid, each square in that grid contains one 16*16 pixel object, or “sprite”. I track a relative position of 0-15 for the X axis, and 0-11 for the Y. These are small numbers that are easy to process. HOWEVER, the relative screen coordinates are actually a multiple of 16 times the relative X coordinate. I used to multiply those coordinates every time in my game loop. Once I was told that was slow, I created a “lookup table” that has all of the exact X/Y coordinates of the screen positions which are a multiple of 16 on the X and Y, which represents the top-left corner of the object, I also have two more X/Y values that are 15 greater than the start for the bottom right corner. All of these are read into an array variable so I have X1(A),Y1(A) to represent to top-left precise coordinates and X2(A),Y2(A) represent the bottom-right. This makes using my GET/PUT command pretty simple, easy, and consistent throughout the program. I’m mentally only thinking in terms of 16×12 and the look-up table handles sets of starting and ending coordinates that represent 16×16 pixel grids, in an actual resolution of 256×192 pixels…. Mind=blown!
Remove variable names from NEXT loops. For X=1 to 100:Next X that’s how we always did it, however, For X=1 to 100:NEXT actually processes faster, trust me
A Gosub that returns to a return…. I have a routine that does the PCOPY to which is part of my double-buffering page-flipping routine to avoid any visible flicker. I GOSUB 605 to do the PCOPY. 605 does the PCOPY and returns. Some of my program lines read something like GOSUB 605:RETURN which means they were calling the routine, and then returning to the routine that called them… By changing that statement to GOTO 605, it went to where I wanted it, and the built in RETURN of that routine went back to the original home of the routine that called it, no extra coding, fewer commands to interpret, faster execution… trust me.
A double compare is slower than two single compares…. I used to check to see if the X and Y coordinates of an alien or bomb matched the X and Y coordinates of my shot or ship….. The short version of that would be something like:
10 IF AX=SX AND AY=SY THEN GOSUB "ALIENS HIT SHIP" 20 RETURN
This required two numbers to be compared each statement and cycle, it was broken into a few more lines of code that actually process faster
10 IF AX<>SX THEN 30 20 IF AY=SY THEN GOSUB "ALIEN HIT SHIP" 30 RETURN
This make the program look a little longer, but rather than having to compare if two variable matched every single cycle, determine that if one of them doesn’t match, then other doesn’t matter, and don’t even check for it. Longer listing, but faster execution.
An example of what some of these optimizations look like was visually demonstrated in the 0.17 video update:
There are so many more “little things” but we’ll end this one here, for now, hopefully more tips and tweaks in the future.