# ON/GOTO/GOSUB with arbitrary values!?!

Someone named Rob posted a comment to my recent ELSE article that simply contained one line of weird BASIC code:

It looked like Rob was presenting a way to do an ON/GOTO with arbitrary values. Will that actually work?

## ON GOTO/GOSUB

ON/GOTO (and ON/GOSUB) normally expects values from 1 to X, and a corresponding line number for each consecutive value:

``````10 INPUT "ENTER 1-5";A
20 ON A GOTO 100,200,300,400,500
30 GOTO 10
100 PRINT "YOU CHOSE 1":GOTO 10
200 PRINT "YOU CHOSE 2":GOTO 10
300 PRINT "YOU CHOSE 3":GOTO 10
400 PRINT "YOU CHOSE 4":GOTO 10
500 PRINT "YOU CHOSE 5":GOTO 10``````

If A is 1, it will go to 100. If A is 2, it will go to 200. And so on.

## Mind the gaps

If you had wanted gaps in the choices, like 1, 3 and 5, you’d have to fill out the ON/GOTO with numbers for the missing choices:

``````10 INPUT "ENTER 1, 3 OR 5";A
20 ON A GOTO 100,10,300,10,500
30 GOTO 10
100 PRINT "YOU CHOSE 1":GOTO 10
300 PRINT "YOU CHOSE 3":GOTO 10
500 PRINT "YOU CHOSE 5":GOTO 10``````

That might be a nice approach if the numbers were relatively close to each other, but at some point, adding a bunch of dummy numbers to the ON/GOTO line would take more time to parse than just using separate IF/THEN statements.

## Arbitrary GOTO

My example was based on some VIC-20 code I wrote back in 1983. I was reading which key was currently being held down, and would get back three different values for the keys I was reading:

• 17 – ‘A’ key is pressed (LEFT)
• 42 – ‘S’ key is pressed (RIGHT)
• 39 – ‘F1’ key is pressed (JUMP)

I couldn’t use ON/GOTO for values 17, 42 and 39.

But Rob’s code does just that!

``20 ON -(K=41)-2*(K=17)-3*(K=39) GOTO 30,40,50``

In BASIC, any comparison returns a -1 if it is TRUE, or a 0 if it is FALSE:

…so in Rob’s example, the checks in parenthesis will be turned in to either a -1 or a 0 based on the value of K.

• If K is 41, then (K=42) will be (-1) and (K=17) and (K=39) will both be (0).
• If K is 17, then (K=17) will be (-1) and (K=41) and (K=3) will both be (0).
• If K is 39, then (K-39) will be (-1) and (K=42) and (K=17) will both be (0).

Let’s see what that does:

```20 ON -(K=41)-2*(K=17)-3*(K=39) GOTO 30,40,50

K = 41 produces:
ON -(-1) - 2*(0) - 3*(0) GOTO 30,40,50
ON    1  -    0  -    0  GOTO 30,40,50
ON    1                  GOTO 30,40,50

K-17 produces:
ON -(0) - 2*(-1) - 3*(0) GOTO 30,40,50
ON   0  -    -2  -    0  GOTO 30,40,50
ON            2          GOTO 30,40,50

K-39 produces:
ON -(0) - 2*(0) - 3*(-1) GOTO 30,40,50
ON   0  -    0  -    -3  GOTO 30,40,50
ON                    3  GOTO 30,40,50```

Fantastic! Subtracting a negative makes it a positive, and multiplying by zero makes zero.

Math rules! And it actually works:

``````0 REM robgoto.bas
10 INPUT "41, 17 OR 39";K
20 ON -(K=41)-2*(K=17)-3*(K=39) GOSUB 30,40,50
25 GOTO 10
30 PRINT "30":RETURN
40 PRINT "40":RETURN
50 PRINT "50":RETURN``````

Fantastic! What a great tip. Thanks, Rob!

## Arbitrary benchmark

So of course, I now have to see how this compares to separate IF/THEN’s speed-wise. Let’s pull out the trusty benchmark test code and do a version for best case (first choice) and worst case (last choice) for each approach (Rob’s, and IF/THENs).

Arbitrary ON/GOSUB, best case:

``````0 REM robgoto1.bas
5 DIM TE,TM,B,A,TT
6 K=41
10 FORA=0TO3:TIMER=0:TM=TIMER
20 FORB=0TO1000
30 ON -(K=41)-2*(K=17)-3*(K=39) GOSUB 100,200,300
70 NEXT
80 TE=TIMER-TM:PRINTA,TE
90 TT=TT+TE:NEXT:PRINTTT/A:END
100 RETURN
200 RETURN
300 RETURN``````

This produces 1368.

Arbitrary ON/GOSUB, worse case:

``````0 REM robgoto2.bas
5 DIM TE,TM,B,A,TT
6 K=39
10 FORA=0TO3:TIMER=0:TM=TIMER
20 FORB=0TO1000
30 ON -(K=41)-2*(K=17)-3*(K=39) GOSUB 100,200,300
70 NEXT
80 TE=TIMER-TM:PRINTA,TE
90 TT=TT+TE:NEXT:PRINTTT/A:END
100 RETURN
200 RETURN
300 RETURN``````

This produces 1434

Separate IF/THEN/GOSUB, best case:

``````0 REM ongoto1.bas
5 DIM TE,TM,B,A,TT
6 K=41
10 FORA=0TO3:TIMER=0:TM=TIMER
20 FORB=0TO1000
30 IF K=41 THEN GOSUB 100:GOTO 70
40 IF K=17 THEN GOSUB 200:GOTO 70
50 IF K=39 THEN GOSUB 300
70 NEXT
80 TE=TIMER-TM:PRINTA,TE
90 TT=TT+TE:NEXT:PRINTTT/A:END
100 RETURN
200 RETURN
300 RETURN``````

This produces 518 – almost three times faster!

Separate IF/THEN/GOSUB, worse case:

``````0 REM ongoto2.bas
5 DIM TE,TM,B,A,TT
6 K=39
10 FORA=0TO3:TIMER=0:TM=TIMER
20 FORB=0TO1000
30 IF K=41 THEN GOSUB 100:GOTO 70
40 IF K=17 THEN GOSUB 200:GOTO 70
50 IF K=39 THEN GOSUB 300
70 NEXT
80 TE=TIMER-TM:PRINTA,TE
90 TT=TT+TE:NEXT:PRINTTT/A:END
100 RETURN
200 RETURN
300 RETURN``````

This produces 1098, meaning even worst case is still faster.

BUT, we are doing a bunch of number parsing and math here. We can’t do anything about the math, but on Color BASIC, we can change those decimal values to HEX and speed up that part. Let’s try that:

``````0 REM robgoto3.bas
5 DIM TE,TM,B,A,TT
6 K=41
10 FORA=0TO3:TIMER=0:TM=TIMER
20 FORB=0TO1000
30 ON -(K=&H29)-&H2*(K=&H11)-&H3*(K=&H27) GOSUB 100,200,300
70 NEXT
80 TE=TIMER-TM:PRINTA,TE
90 TT=TT+TE:NEXT:PRINTTT/A:END
100 RETURN
200 RETURN
300 RETURN``````

By switching the five integer values in line 30 one to HEX, the speed of best case goes from 1368 to 1150! That’s faster, but it still doesn’t beat 518 using separate IF/THEN/GOSUB.

We might be able to make this a bit faster by using variables, so lets try that:

``````0 REM robgoto4.bas
5 DIM TE,TM,B,A,TT
6 K=41
7 L=&H29:M=&H2:N=&H11:O=&H3:P=&H27
10 FORA=0TO3:TIMER=0:TM=TIMER
20 FORB=0TO1000
30 ON -(K=L)-M*(K=N)-O*(K=P) GOSUB 100,200,300
70 NEXT
80 TE=TIMER-TM:PRINTA,TE
90 TT=TT+TE:NEXT:PRINTTT/A:END
100 RETURN
200 RETURN
300 RETURN``````

This brings the time down slightly to 1092. Still not enough to beat the separate IF/THEN/GOSUB (and that could also be sped up slightly using HEX or variables).

## Conclusion

This trick is very cool. From my calculations, it looks like it save code space, which could be very important on a low-memory system like a 4K CoCo or the 5K VIC-20. That alone might make this trick worth doing.

But for speed, such as a BASIC game, it looks like brute force IF/THEN may be a better approach.

It’s really nice to have options. I can’t wait for an opportunity to use this technique in something.

Thanks, Rob, for leaving such a cool comment!

Until next time…

# VIC-20: Sky-Ape-Er code dissection – part 4

See also: part 1, part 2, part 3, part 4 or part 5 (with more coming).

Hey hey! It’s another VIC-20 Tuesday!

I have completed my code walk-through of one of my earliest computer programs, a Donkey Kong-inspired VIC-20 game called Sky-Ape-Er. But, the version I presented was not the only version of the game I created. I have dozens of saved copies of this game in various stages of completion, but one in particular stood out. It used completely different graphics.

## Sky-Ape-Er: The Prototype

As a reminder, here is what the graphics were later changed to in the release version:

The ape was completely different, and the platform graphics were meant to resemble the ones used in the arcade game Donkey Kong. But why were there pinwheels? I have so many questions for my junior high self.

When I first uncovered these tapes I was unaware of how many variations of my programs were on them. When I started this article on my Sky-Ape-Er game, I discovered that the earlier version with different graphics was also using some different code — most notably in how it read the keyboard input.

I thought it might be fun to look at the programming choices I originally made, and speculate on why I changed them.

## Sky-Ape-Er: The Mystery

The first thing I want to discuss is a mystery I am currently trying to solve. My VIC-20 games that used custom character sets seem to come in three forms:

### DATA STATEMENTS

The BASIC program reads the character set from DATA statements and POKEs it into memory. This is what the Sky-Ape-Er INSTRUCTIONS program does. I believe these character sets may have been designed by the Eight by Eight Create program I previously mentioned. If true, I don’t envy my junior high self having to manually copy down the numbers to paper and type them in to my own program later. From the documentation:

“Once you have created, designed and examined enough characters, you can copy their associated numbers on paper to be used in any programs you make.”

Eight by Eight Create instruction from January 1983 Creative Computing magazine (Volume 9, Number 1), page 270.

Yipes.

A standalone binary “program” of the custom character set that can be loaded into memory, presumably at the address of where the character data goes. I have found several programs called things like CHARS and TNTCH that do not have any BASIC code in them. I suspected these were character set data (especially TNTCH which was on the tape after the main program TNT) but I had no idea how to use them. I was finally able to see what was inside by importing them into the CBM prg Studio‘s characters set editor. CBM prg Studio is a Windows integrated development environment (IDE) for making Commodore programs in BASIC or assembly. It has some great features and is worth checking out.

This let me see that these were indeed character sets, though my first attempt to import them had all the graphics off by a few lines. I needed to use an offset (bytes to skip in the file) of 2 for the characters to load properly. That told me that whatever type of file this was had some 2 byte header at the start (perhaps memory location where to load the data?).

### ALL-IN-ONE PROGRAM WITH CHARACTER SET

And this is the mystery! My early prototype version of Sky-Ape-Er was just one program, and it loaded up with the custom character set. There was no font in DATA statements. There was no pre-loader that did it. It just loaded and “just worked.” I have no idea how I created this, nor do I know why, for the release version, I change it to use two programs and DATA statements.

But I have theories.

## Dissecting the data

Thanks to suggestions from a VIC-20 group on Facebook and the Denial Commodore forum, I looked at the contents of the mystery SKY-APE-ER program file.

Using a free hex editor, I opened the file and looked for the end of the BASIC program. I could tell it ended around byte 2612 because the last line was a “SYS xxxxx” command that would reboot the VIC-20. The xxxxx numeric value was visible as plain text in the tokenized BASIC file, so it was easy to spot.

After this was a bunch more data. Somewhere in there must be the character set. But where? I decided to try opening the entire program file in the character set editor and using the 2612 offset where the BASIC program ended.

Doing this showed garbage between the BASIC program and character data, but scrolling down let me visibly see where the font data began.

I now knew that approximately 58 characters (each character is 8×8, so 8 bytes per) into the file was the start of the font data. A little math (which was hard) and some trial and error (which was easy) and I came up with 3073 as the offset to use from the stat of the .prg to where my custom characters were. I imported using that value and got this:

If I knew what the font data was to begin wish (from DATA statements), I could have just scanned the HEX file looking for those values. But I didn’t, so I couldn’t.

Now I have a BASIC file for the game, as well as a character set file in the CBM prg Studio editor. But how did I combine them together in the first place?

## Where does the data go from here?

The clue is in these POKEs found on the first line of the program:

`POKE45,56:POKE46,26:POKE51,0:POKE52,28:POKE55,0:POKE56,28:CLR`

They reminded me of similar POKEs in Color BASIC that track where the program starts in memory as well as where variables and strings go. I expected CBM BASIC would be similar, so I went searching for a VIC-20 memory map.

I found this one archived on Bo Zimmerman’s site. He’s the guy behind the incredible Zimodem firmware that lets you wire up a WiFi serial modem for under \$10.

http://www.zimmers.net/cbmpics/cbm/vic/memorymap.txt

I want to do a deep dive into this later, but for now, here are what those POKEs are doing:

```*002D-002E 45-46 Pointer: Start of Variables
*0033-0034 51-52 Pointer: String storage (moving down)
*0037-0038 55-56 Pointer: Limit of memory```

The “*” notes “Useful memory locations” in the memory map. I agree. I seem to be changing where variables and strings start, as well as where the end of memory is on startup.

Why was I changing the start of variables, the end of string storage, and limiting the end of BASIC? I have a theory, which parallels something I’ve done on the CoCo.

In Color BASIC, we use the CLEAR command to allocate more string space (“CLEAR 500” for 500 bytes for strings). It looks like CBM BASIC doesn’t do that, and allows strings to use as much memory as is available (the memory between the end of the BASIC program + variable arrays, and the limit of memory).

CLEAR can also limit how much memory BASIC can use (“CLEAR 200,&H3F00”). That’s useful when you are wanting to use some of that memory for machine language and don’t want BASIC to overwrite it. I am betting POKE 51/52 is like CLEAR x,XXXX.

## VIC-20 Memory Map

To better visualize this, let’s take a quick look at where the 5K of RAM in the VIC-20 is located.

```   0 -> +------------------------------+
....    | 1K of System Memory          |
1024 -> +------------------------------+ <- 1023
| 3K Expansion RAM (cartridge) |
4096 -> +------------------------------+ <- 4095
| User BASIC Area (3583 bytes) |
7680 -> +------------------------------+ <- 7679
| Screen Memory (512 bytes)    |
+------------------------------+ <- 8191```

Hey, look at that! The memory range used by BASIC (4096-7679) is the “3583 BYTES FREE” value shown on the startup screen:

Notice the 3K gap (1024-4095) which is where the 3K RAM expansion cartridge goes if you have one. I never did, though I did have the Super Expander cartridge which gave extra memory as well as enhanced graphics and sound commands.

Side Note: When memory expansion cartridges are plugged in, more memory becomes available and some things shift around. But for this discussion, we will talk only about the stock 5K VIC-20. It was only in recent years that I learned the VIC-20 was a 5K computer. I’d always thought it was 4K. That now makes the weird 3K memory expansion make more sense, since that would boost it to a nice even 8K. But I digress…

Now let’s zoom in on just the memory BASIC is using:

```43/44 -> +---------------+
| BASIC program |
45/46 -> +---------------+
| Variables     |
47/48 -> +---------------+
| Arrays        |
+---------------+ <- 49/50 End of Arrays
|               |
|               |
51/52 -> |---------------+
| Strings       |
+---------------+ <- 55/56 Mem Limit (7679)```

When a new numeric variable is added, it goes into the Variables section, which grows larger downward. When a new array is added, it goes into the Arrays area (and likely the entries there point to the Variable) and it grows larger downward. When a string is added, it gets an entry in the Variable section (“A\$”) which has a pointer into the actual string content in the Strings section, which grows upwards.

So why was I changing the start of variables, the end of string storage, and limiting the end of BASIC? I believe I was making BASIC think the program was larger than it really was so it would SAVE out (and thus LOAD back later) the program PLUS some custom character data. When the program would run, it would need to reset the pointers to be at the actual end of the BASIC program, and limit memory so BASIC did not write over the character data.

In order to explain this, we need to look at how the VIC-20 custom characters worked.

## How the VIC-20 custom characters worked

The VIC-20 character set was 4K of data stored in ROM starting at 0x8000:

```8000-83FF 32768-33791 Upper case and graphics
8400-87FF 33792-33815 Reversed upper case and graphics
8800-8BFF 33816-35839 Upper and lower case
8C00-8FFF 35840-36863 Reversed upper and lower case```

Each character was 8 pixels wide (one byte) by 8 pixels tall (8 bytes total). There is room for 512 characters in that 4K. Normal printable ASCII characters are 0-127, so it looks like the Commodore PETASCII was similar, with 128 special Commodore characters per bank (128 characters * 8 bytes per character = 1024 bytes).

On power up, the VIC’s video chip is programmed to use the first of those four 1K blocks of ROM for its character set. There is a register with four bits that can be changed to select which of those four ROM blocks it uses, or point it to four 1K RAM blocks in RAM. By loading a character set in to one of those RAM areas and setting the register, the VIC will now display the custom character set rather than the one built in to the ROM. Here are the important four bits:

```9005 36869 bits 0-3 start of character memory (default = 0)
bits 4-7 is rest of video address (default= F)
HEX   DEC
0000   ROM   8000  32768
0001         8400  33792
0010         8800  34816
0011         8C00  35840
1000   RAM   0000  0000
1100         1000  4096
1101         1400  5120
1110         1800  6144
1111         1C00  7168```

Memory location 36869 can be one of these 8 values:

• 0xF0 / 240 / 11110000 – Use 8000-83FF (Upper case and graphics)
• 0xF1 / 241 / 11110001 – Use 8400-87FF (Reversed upper case and graphics)
• 0xF2 / 242 / 11110010 – Use 8800-8BFF (Upper and lower case)
• 0xF3 / 243 / 11110011 – Use 8C00-8FFF (Reversed upper and lower case)
• 0xfc / 252 / 11111100 – Use 1000-13FF RAM area #1
• 0xfd / 253 / 11111101 – Use 1400-17FF RAM area #2
• 0xfe / 254 / 11111110 – Use 1800-1BFF RAM area #3
• 0xff / 255 / 11111111 – Use 1C00-1FFFF RAM area #4

The four RAM locations all are within the 4K that is used by BASIC and screen memory:

• 0x1000 – 0x1dff – 3583 bytes used by BASIC programs.
• 0x1e00 – 0x1fff – 512 bytes used by screen memory.

We can’t use RAM area #1 for characters because that is where our BASIC program is. If we kept our BASIC program and all its variables very small (1K, 0x1000-0x13FF), we could use area #2. But, it makes more sense to use area #4 and give as much memory as possible to BASIC.

In my programs I see POKE 36869,255 and POKE 36869,240. The first POKE makes the video chip start using characters in RAM starting at 0x1c00 (bit pattern 1111). This means a BASIC program and all its variables can’t be any larger than 3072 bytes (0x1000-0x1bff). The second poke switches the characters back to using the standard ROM location for uppercase and graphics characters (bit pattern 0000).

My Sky-Ape-Er INSTRUCTIONS program would READ character data and then POKE it into memory starting at 0x1c00 (7168). It then did POKE 36869,255 to start using them. To display a normal text screen, or at the end of the program, it would POKE 36869,240 to get back to the ROM character set. (This is the part I actually mostly remembered.)

I do want to point out that the character RAM area #4 overlaps with the screen memory:

• 0x1c00 – 0x1fff – Character RAM area #4.
• 0x1e00 – 0x1fff – 512 bytes used by screen memory.

This tells me that you really only have 0x1c00 to 0x1dff (7168-7679) for custom characters. That’s 512 bytes, and at 8 bytes per letter, there is only room for 64 custom characters. Assembly language programs that did not need BASIC could move things around and use one of the other blocks in its entirety, but this last block shares memory with the screen so not all of it can be used for character data.

## Character sets

The PETSCII character set starts at zero with an “@” symbol, followed by the alphabet characters “A-Z” (1-26), then various punctuation and symbols (27-47), then numbers (48-57), then more punctuation and symbols (59-63). This covers the basic characters and uppercase alphabet just like standard ASCII does for characters 32-96. This means being limited to just 64 characters is not bad at all.

And, as I was working through this, I discovered why my Factory TNT game is not displaying the score correctly! I did not realize it also contained updated number characters (48-57) that I was not properly loading during my “restoration” of the game:

But I digress…

## Stay on target… Stay on target…

This means that you could have a BASIC program from 0x1000 to 0x1bff followed by custom character data from 0x1c00 to 0x1dff. If you had the characters in memory for your BASIC program to use, and you SAVEd your BASIC program, those custom characters would NOT be saved with it since BASIC doesn’t know anything about them.

But … you could lie to BASIC and tell it your BASIC program actually ENDS at 0x1dff, then when you SAVE it should write out the entire range of memory (0x1c00 to 0x1dff) thinking it’s just one large BASIC program…

Then, when you loaded it back it, BASIC would start loading it into memory at 0x1c00 and keep going until it got to the end of the program. You now have loaded memory that is part BASIC, and part character set!

But, if you tried to RUN it, you wouldn’t get very far because BASIC would think there is no memory left for variables. You would need to un-lie to BASIC and tell it where the program really ends, and do so without using varaibles.

That is what my six POKEs were apparently doing.

In part 5, we’ll see if this theory works.

Until next time…

# VIC-20: Sky-Ape-Er code dissection – part 3

See also: part 1, part 2, part 3, part 4 or part 5 (with more coming).

Its time for another VIC-20 Tuesday!

In this installment, I will walk through the code for my VIC-20 game Sky-Ape-Er. Thanks to a wonderful utility I mentioned in part one, I have this ASCII program listing. The utility replaces the special PETASCII control characters with {words} so they can be viewed on non-Commodore systems.

## Sky-Ape-Er program listing

### Initialization

`1 POKE 808,100`
• That poke would “disable the RUN/STOP key, the RESTORE key, and the LIST command” to keep someone from being able to save a copy of it.
`5 REM  ************          *SKY-APE-ER*        *******BY*******6 REM*ALLEN  HUFFMAN*      ****************{\$cc}`
• Comments, but with no dates. Thanks, me. One of my tapes had the game in various stages of completion, named “SKY-APE-ER 1”, “SKY-APE-ER 2” and “SKY-APE-ER 3”, but all my other tapes just called it SKY-APE-ER, and I’ve found at least two distinct versions of the game so far.
• I am not sure what the {\$cc} is at the end. From looking at the c64list.exe command I used to make this listing, it seems to be an unknown token. This might have been something I placed in that line to prevent listing, even after a LOAD without the POKE being executed. But, you can LIST 10- and still see it ;-)
`10 S=1:POKE36879,26:POKE36878,15:S1=36875:POKE775,200:POKE36869,255`
• S is the screen (level) to display. Sky-Ape-Er contained three screens, and a “game won” screen.
• 36879 is the border color, with 26 being red.
• 36878 is something to do with the music chip.
• S1 is being set to the sound note location 36875.
• 775,200 disables LIST. Or maybe not. There was conflicting information in the magazine I looked that up in.
• 36869 enables the custom font characters.

### Set up game screen

`15 PRINT"{clear}":L=8118:B=7772:M=15`
• L is the starting memory location for the player.
• B is the starting memory location of the chimp (B for barrel, I suppose, as this was inspired by Donkey Kong).
• M is the character to POKE to the screen for the player (man). 15 is the letter”O”.
`20 FORA=38400TO38905:POKEA,0:NEXTA`
• This clears the color for each character on the screen. The characters for the screen are stored in one block of memory, and the color of each character is stored in a different block of memory.

### Display ape

`25 PRINT"{home}{down}{right}{black}ABC{down}{left:3}DEF{down}{left:3}GHI{down}{left:3}JKL"`
• This clears the screen, then draws the letters that make up the ape character. The VIC-20 has no PRINT@ or LOCATE function, but you could embed cursor movement commands in the PRINT statements. Thus, it would “home” to the top fo the screen, move the cursor {down} one, then {right} one, set the color to {black}, print ABC, then go {down} one and {left} three times (cursor is now back under the A) and print DEF, and repeat for the other lines. The ape was 3×4 characters in size!

### Display game screen

`30 ONSGOTO35,45,55,500`
• This goes to the appropriate routine to display the current screen (level) based on the value of S. There were three screens. If S is 4, it goes to a “win” screen.

### Screen 1

`35 PRINT"{red}@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@{down}{left}";40 PRINT"@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@":GOTO70`

That would draw this:

### Screen 2

`45 PRINT"{blue}@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}";50 PRINT"@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@":GOTO70`

That would draw this:

### Screen 3

`55 PRINT"{purple}@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{up:3}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}";60 PRINT"@@@{up:4}{left}@@@{down}{left}@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@{up}{left}@{up}{left}@"`

That would draw this:

### Begin game

`70 T=0`
• T is used for time. It starts at zero and increments, so the goal is to get to the top as fast as possible.

### Main game loop

Display player and check to see if we made it to the top, or were hit by a chimp.

```80 POKEL,M:POKEB,32:POKES1,0
83 IFL=7772ORL=7749THEN400
84 IFL=BTHEN250```
• Line 80 pokes the Man on the screen at its Location. The Barrel is poked to a space, so erased. The S1 sound is stopped. Nothing would be playing the first time this code is ran.
• If the Location is 7772 or 7749, we go to 400.

### Move the chimp

`85 B=B+23:IFPEEK(B)=0THENB=B-22:POKEB,16`
• This controls the movement of the enemy (chimp). B is the location. The VIC-20 screen is 22 characters per line, so incrementing B by 23 would move the position down and to the right.
• The new location of B is checked to see if it is 0 (the brick). If it is, it moves the location back 22 (up one). Thus, the chimp always tries to go down and to the right, and if it can’t it just goes right.
• The POKE is what puts the chimp character on the screen at that position.
• From looking at this, it seems the chimp is not displayed if it goes down and to the right successfully. I wonder why? Bug? It would get displayed the next time. Or inteitonal? I’ll look into this.

### Handle player falling

`87 IFPEEK(L+22)=32THENPOKEL,32:L=L+22:POKEL,M`
• This looks at the block under the player. If it is 32 (empty), it erases the player and moves it down, then displays it at the new location.
• This code is what makes the player “fall” when it jumps or, on screen 3, when it falls off the edge. Cool.

### Make “tick” sound

`90 POKES1,240:POKES1,0`
• S1 is the address of one of the sound channels (the VIC-20 has three musical channels, plus noise). This turns one on and off, making the “tick” sound.
• I did not even consider being able to do background music for a game back then. I bet I could today, memory permitting, even in BASIC.

### Collision detection (player and chimp)

`95 IFB=LTHEN250`
• This is the collision detection. If the chimps location (B) is the same as the players Location, we go to 250 (death).

`100 IFB=8118THENPOKEB,32:B=7772:POKEB,12`
• This checks to see if the chimp is at the bottom right of the screen.
• If it is, it gets erased, and the position is reset back to the top left starting position and it is displayed there.

### Update and check timer

`105 PRINT"{home}{blue}{rvrs on}{right}TIME:";T:T=T+1110 IFT>200THEN300`
• This homes the cursor, changes the color to blue, turns on reverse video, then displays “TIME:” and the current time value. The reason it goes reverse is because we are using a special character set that replaces the lower alphabet characters. In this mode, there is some memory thing that happens that wraps around the inverse video characters to the standard characters. When using special characters, you have access to the basic letters by using reverse. Apparently.

### Keyboard input

`115 K=PEEK(197):IFK=64THEN80`
• Memory location 197 is the current key being pressed. If no key is pressed, 64 is returned and the program goes back to the top and continues. (Move the chimp, update the time, etc.)
`120 POKEL,32:POKES1,230`
• If there was input, then this line will erase the player, and turn on the sound chip to start making a tone.

### Move player or jump

`125 IFK=17THENL=L-1:M=14130 IFK=41THENL=L+1:M=13135 IFK=39THEN180140 IFPEEK(L)=0THEN150145 GOTO80`
• K is the value of the key being pressed.
• 17 is “A”, so if that is pressed, we move the player’s location to the left and change the player’s character to the “facing left” letter.
• 41 is “S”, so if that is pressed, we move the player’s location to the right and change the player’s character to the “facing right” letter.
• 39 is the F1 function key. If that is seen, we go to the jump routine at line 180.
• If the player’s position (which may or may not have been updated) is 0, it is in a wall, so go to line 150 to fix that location.
• If still here, we go back to line 80 and continue with the main loop.

### Handle running into wall collision

`150 IFK=17THENL=L+1155 IFK=41THENL=L-1160 M=15:GOTO80`
• This is kind of silly, but if we are here, we hit a wall, so we look at what the last key was pressed and reverse the direction that it did.
• We set the player’s character to the “facing forward” character.

### Jump routine

`180 POKES1,235:IFM=14THENL=L-23183 IFM=15THENL=L-22185 IFM=13THENL=L-21190 IFPEEK(L)=0THEN200195 M=15:GOTO80`
• First we start to make a tone.
• Then we check to see if the player’s character is 14 (facing left). If it is, we move the player’s position up and to the left (22 characters per row, so -23).
• If the player’s character is 15 (facing forward), we move the location up,
• If the player’s character is 13 (facing right), we move the location up and to the right.
• If the new location is in a wall, we go to 200 to fix that.
• We set the player’s character to 15 (facing forward) so the jump will land facing that way.
• We go back to 80 to continue the main game loop.

### Handle jumping into wall collision

```200 IFM=13THENL=L+21
210 M=15:GOTO80```
• This code takes care of jumping into walls.
• If the character is facing right, then we move the position down and to the left back where it came from.
• Else, we know the only other place it can hit a wall is to the right (wow, I was clever here!) so we just make the character face forward and go back to the main loop.

### Death screen

`250 FORA=1TO11:READN,L:POKES1,N:FORP=1TOL:NEXTP:POKES1,0:NEXTA255 PRINT"{clear}{black}{rvrs on}{down} GUESS WHAT! YOU HAVE {down}JUST BEEN STRUCK DOWN {down}  BY A LUCKY CHIMP!"260 PRINT"{rvrs on}{down}({blue}THAT MEANS {red}GAME OVER{black})"265 GOTO450`
• The first line reads musical note and duration values from DATA statements, then makes each note sound for that amount of time.
• The screen is then cleared, and a game over message is displays.
• It then goes to 450 to see if the player wants to play again.
`270 DATA202,250,202,250,202,150,202,350,210,250,208,150,208,200,202,200,202,250,200,200275 DATA 202,400`
• Those DATA statements contain the note value and length of the tune that plays when you die (funeral march). I did not know anything about music at the time, so I figured it out by ear. The timing is awful.

### Time exceeded

`285 PRINT"{down:2}{rvrs on}PRESS ANY KEY TO START"300 PRINT"{clear}{black}{rvrs on}{down:3}WELL WHAT DO YOU KNOW?"305 PRINT"{rvrs on}{down:2}WHILE YOU WERE DOWN ONTHE GROUND JUMPING A- ROUND,YOUR TIME CLOCK"310 PRINT"{rvrs on}    JUST RAN OUT!"315 PRINT"{rvrs on}{down:2}  NEXT TIME {red}WATCH{black} THE CLOCK!"320 GOTO450`
• This message is displayed when time runs out. It then goes to the “play again?” screen.

### Screen completed

`400 S=S+1:GOTO15`
• This increments the screen, and then goes back to display it.

### Play again prompt

```450 PRINT"{black}{rvrs on}{down:2}{right}WILL YOU TRY AGAIN?"
455 GETA\$:IFA\$=""THEN455
460 IFA\$="N"THEN550
465 IFA\$="Y"THEN480
470 GOTO455```
• This prompts the user to ask if they want to play again. It waits for a key press, then if it is “Y”es, it goes to 480 (start a new game). If it is “N”o, it goes to 550 (end the game).

### Press any key to play again prompt

`480 PRINT"{clear}{black}{rvrs on}{down:2}AT LAST! SOMEONE BRAVE ENOUGH TO {red}TRY{black} TO STOP  KING KING'S COUSIN!"490 GETA\$:IFA\$=""THEN490495 RUN`

If the player chooses “Y”es to play again, this messages is displayed. It waits for any key to be pressed, then re-runs the program.

### Game won – Falling ape animation

`500 PRINT"{clear}{black}"505 FORZ=0TO16:PRINT"{home}":FORR=0TOZ:PRINT:NEXTR510 PRINT"   {down}{left:3}ABC{down}{left:3}DEF{down}{left:3}GHI{down}{left:3}JKL"515 NEXTZ`
• This cleans the screen, draws the ape, and then makes it “fall” to the bottom of the screen. Remember how Donkey Kong would fall at the end of the rivets level? Kinda like that. Just not as good. I had forgotten about this!
`525 POKE36874,128530 FORX=15TO0STEP-.1:POKE36878,X:NEXTX:POKE36874,0`
• That plays a sound effect when the ape hits the bottom of the screen.

### Game won message

`535 PRINT"{clear}{black}{rvrs on}{down:3}CONGRATULATIONS!!!!!!!{down} YOU NOW KNOW WHAT IT  FEELS LIKE TO BE ON"540 PRINT"{rvrs on}TOP!{\$a0}YOU PLAYED WELL!"545 PRINT"{rvrs on}{down:2}{blue}BET YOU DON'T WIN NEXT       TIME!"548 PRINT:GOTO450`
• This displays the “game won” message, then goes to 450 to ask the player if they wish to play again.

### Quit game message

`550 PRINT"{clear}{black}{rvrs on}I DIDN'T THINK YOU HAD ENOUGH COURAGE TO TRY   TO STOP A MAD APE!"560 PRINT"{down}{rvrs on}{red}I HOPE YOU ENJOYED NOT SAVING THE BUILDING!"565 FORG=1TO10000:NEXTG570 SYS64802`
• This would display a message, wait, and then reboot the VIC-20.

## Programmer’s thoughts

I actually expected this code to be far worse than it actually is. If I were writing it today, I see a number of things I could do to make it more efficient. I also have many ideas of ways I could use the VIC-20 features to make the game fancier (animated characters, better music and sounds).

But, overall, I am fairly pleased with how my junior high self programmed this. I was completely self-taught from reading the VIC-20 manual and articles in magazines.

But since I know I could do it better today, I think I might just give that a shot.

Here is the full listing of this version of the program. If you want to run it, I would do two things:

• Delete line 1 entirely.
• In line 10, remove the POKE772,200.
• And I’d get rid of the same POKEs in the INSTRUCTIONS loader.

And if you don’t want to type it in, here is a virtual tape for the VICE Commodore emulator. It has the above changes made, but otherwise is exactly as I last touched it in 1983. Enjoy!

Until next time…

## Full SKY-APE-ER listing:

``````1 POKE 808,100
5 REM  ************          *SKY-APE-ER*        *******BY*******
6 REM*ALLEN  HUFFMAN*      ****************L
10 S=1:POKE36879,26:POKE36878,15:S1=36875:POKE775,200:POKE36869,255
15 PRINT"{clear}":L=8118:B=7772:M=15
20 FORA=38400TO38905:POKEA,0:NEXTA
25 PRINT"{home}{down}{right}{black}ABC{down}{left:3}DEF{down}{left:3}GHI{down}{left:3}JKL"
30 ONSGOTO35,45,55,500
35 PRINT"{red}@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@{down}{left}";
40 PRINT"@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@":GOTO70
45 PRINT"{blue}@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}";
50 PRINT"@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@":GOTO70
55 PRINT"{purple}@@@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{up:3}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}";
60 PRINT"@@@{up:4}{left}@@@{down}{left}@@@@@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@{down}{left}@@@@@@@@@{up}{left}@{up}{left}@{up}{left}@{up}{left}@{up}{left}@"
70 T=0
80 POKEL,M:POKEB,32:POKES1,0
83 IFL=7772ORL=7749THEN400
84 IFL=BTHEN250
85 B=B+23:IFPEEK(B)=0THENB=B-22:POKEB,16
87 IFPEEK(L+22)=32THENPOKEL,32:L=L+22:POKEL,M
90 POKES1,240:POKES1,0
95 IFB=LTHEN250
100 IFB=8118THENPOKEB,32:B=7772:POKEB,12
105 PRINT"{home}{blue}{rvrs on}{right}TIME:";T:T=T+1
110 IFT>200THEN300
115 K=PEEK(197):IFK=64THEN80
120 POKEL,32:POKES1,230
125 IFK=17THENL=L-1:M=14
130 IFK=41THENL=L+1:M=13
135 IFK=39THEN180
140 IFPEEK(L)=0THEN150
145 GOTO80
150 IFK=17THENL=L+1
155 IFK=41THENL=L-1
160 M=15:GOTO80
180 POKES1,235:IFM=14THENL=L-23
183 IFM=15THENL=L-22
185 IFM=13THENL=L-21
190 IFPEEK(L)=0THEN200
195 M=15:GOTO80
200 IFM=13THENL=L+21
210 M=15:GOTO80
255 PRINT"{clear}{black}{rvrs on}{down} GUESS WHAT! YOU HAVE {down}JUST BEEN STRUCK DOWN {down}  BY A LUCKY CHIMP!"
260 PRINT"{rvrs on}{down}({blue}THAT MEANS {red}GAME OVER{black})"
265 GOTO450
270 DATA202,250,202,250,202,150,202,350,210,250,208,150,208,200,202,200,202,250,200,200
275 DATA202,400
285 PRINT"{down:2}{rvrs on}PRESS ANY KEY TO START"
300 PRINT"{clear}{black}{rvrs on}{down:3}WELL WHAT DO YOU KNOW?"
305 PRINT"{rvrs on}{down:2}WHILE YOU WERE DOWN ONTHE GROUND JUMPING A- ROUND,YOUR TIME CLOCK"
310 PRINT"{rvrs on}    JUST RAN OUT!"
315 PRINT"{rvrs on}{down:2}  NEXT TIME {red}WATCH{black} THE CLOCK!"
320 GOTO450
400 S=S+1:GOTO15
450 PRINT"{black}{rvrs on}{down:2}{right}WILL YOU TRY AGAIN?"
455 GETA\$:IFA\$=""THEN455
460 IFA\$="N"THEN550
465 IFA\$="Y"THEN480
470 GOTO455
480 PRINT"{clear}{black}{rvrs on}{down:2}AT LAST! SOMEONE BRAVE ENOUGH TO {red}TRY{black} TO STOP  KING KING'S COUSIN!"
490 GETA\$:IFA\$=""THEN490
495 RUN
500 PRINT"{clear}{black}"
505 FORZ=0TO16:PRINT"{home}":FORR=0TOZ:PRINT:NEXTR
510 PRINT"   {down}{left:3}ABC{down}{left:3}DEF{down}{left:3}GHI{down}{left:3}JKL"
515 NEXTZ
525 POKE36874,128
530 FORX=15TO0STEP-.1:POKE36878,X:NEXTX:POKE36874,0
535 PRINT"{clear}{black}{rvrs on}{down:3}CONGRATULATIONS!!!!!!!{down} YOU NOW KNOW WHAT IT  FEELS LIKE TO BE ON"
540 PRINT"{rvrs on}TOP!{shft space}YOU PLAYED WELL!"
545 PRINT"{rvrs on}{down:2}{blue}BET YOU DON'T WIN NEXT       TIME!"
548 PRINT:GOTO450
550 PRINT"{clear}{black}{rvrs on}I DIDN'T THINK YOU HAD ENOUGH COURAGE TO TRY   TO STOP A MAD APE!"
560 PRINT"{down}{rvrs on}{red}I HOPE YOU ENJOYED NOT SAVING THE BUILDING!"
565 FORG=1TO10000:NEXTG
570 SYS64802
``````

# What ELSE can you do when you don’t have ELSE?

NOTE: I have a follow-up to this ELSE thing already written which “changes everything” for me. There’s stuff about ELSE I never knew, which makes me want to never use it. More on that in the next installment. And now back to your regularly scheduled blog post…

First, a quick BASIC memory saving tidbit.

Shaun Bebbington left a comment about my VIC-20 dissection article asking if I knew you could omit zeros from DATA statements like this:

`100 DATA 128,0,0,50,239,0,123,42,0,4`

If you leave them out (comma comma), READ will still get a zero! It saves a byte each time you do that, which could be important on a machine with 3584 bytes free on startup like my VIC-20.

`100 DATA 128,,,50,239,,123,42,,4`

Good tip, Shaun! Thanks!

And while I had his attention, I asked him a few Commodore BASIC questions. I was wondering how you did IF/THEN/ELSE without ELSE! One of the many things I liked about the BASIC in the CoCo was it had ELSE and commands like PLAY, DRAW, CIRICLE, etc. My VIC-20 had no ELSE. In my Sky-Ape-Er game, I’d see my young self doing things like this:

```125 IF K=17 THEN L=L-1:M=14
130 IF K=41 THEN L=L+1:M=13
135 IF K=39 THEN 180```

In that code snippet, K represented the key value that was pressed. If it was 17 (left), I’d move the player left one and change its graphic character. If it was 41 (right), I’d move the player right one and change its graphics character. If it was 39 (F1, jump), I’d go to a routine that would handle the jump.

Without ELSE, if K was 17, it would do that, then check K two more times, even though it didn’t need to. Maybe I did not “see” it back then, but If I had the bytes to spare, I probably should have done something like this:

```125 IF K=17 THEN L=L-1:M=14:GOTO 140
130 IF K=41 THEN L=L+1:M=13:GOTO 140
135 IF K=39 THEN 180```

That way, if K=17 was true, it would do it’s thing, then GOTO would skip over the next two lines. This could be a huge time saver if there were a bunch of conditions (up, down, left, right, diagonals, jump, fire, punch, windshield wipers, etc.)

Someone has already suggested that I may have done it my original way to get consistent timing in the game loop. Somehow I doubt my junior high self was that clever. But I digress…

With ELSE, it could have been written like this:

`125 IF K=17 THEN L=L-1:M=14 ELSE IF K=41 THEN L=L+1:M=13 ELSE IF K=39 THEN 180`

Less code (the ELSE token takes up less memory than an addition line number and/or the extra GOTO to skip lines), and faster execution, maybe.

Side Note: Maybe? There is still the issue of, when completing a successful IF, BASIC’s parser still having to run through the rest of the line characters to find the end and the next line. Adding a “GOTO” wouldn’t help, either, since it would have to parse that and then STILL have to scan to the end of the line. (At least on Color BASIC, which does not remember line pointers once it is parsing a line.) It may actually be faster to break up a long set of IF/ELSE into small lines with a GOTO.

But Shuan mentioned a way of using ON to simulate an ELSE. A quick search led me to a forum post discussing this very thing.

It supposedly works like this… since a compare (K=42, A\$=”RED”, G>100) will return either -1 (false) or 0 (true), you can do an ON GOTO based on the result of that compare. Since it’s a -1 or 0, you can just make the result negative (thus, -1 becomes 1, and 0 becomes -0 which is still 0):

```10 ON -(A=42) GOTO 20:PRINT "NOT 42":END
20 PRINT "42!"```

Er… what? I thought BASIC did not execute anything after a GOTO. It doesn’t, does it?

But… but… How can ON/GOTO with something after it work, then? It turns out, ON/GOTO is special since the conditions of the “ON” may not be met, and thus the GOTO part may not get executed and BASIC will continue.

`ON A GOTO 100,200,300:PRINT "A WAS NOT 1, 2 or 3"`

Looking at it like that makes perfect sense to me. If A is not 1, 2 or 3, it won’t GOTO anywhere and the line continues to be processed.

Thus, this odd code serves as a simple “ELSE” when you don’t have ELSE:

```10 INPUT "VALUE";A
20 ON -(A=42) GOTO 30:GOTO 10
30 PRINT "YOU KNOW THE ANSWER!"```

…would be like…

```10 INPUT "VALUE";A
20 IF A=42 THEN 30 ELSE 10
30 PRINT "YOU KNOW THE ANSWER!"```

Interesting! I have not benchmarked this to see if it’s faster than using GOTO to skip lines, but it might be smaller due to not needing another few bytes for each line number.

Would this have helped my “left, right, jump” code? Maybe not. You can string these together like this:

```124 ON -(K=17) GOTO 125:ON -(K=42) GOTO 130:ON -(K=39) GOTO 180
125 L=L-1:M=14:GOTO 140
130 L=L+1:M=13:GOTO 140```

Since I was doing code in response to the IF, the ON/GOTO approach would just let me GOTO a line that does that code, which then still needs a GOTO to skip the lines after it that shouldn’t be executed. Not great for that use.

But, if I were dispatching to routines based on direction (like I do with the “jump” check to line 180), it would have worked just fine. Instead of this:

```125 IF K=17 THEN 200
130 IF K=41 THEN 300
135 IF K=39 THEN 400
...
200 REM Handle LEFT
...
300 REM Handle RIGHT
...
400 REM Handle JUMP
...```

Those three lines could be combined into one like this:

`124 ON -(K=17) GOTO 200:ON -(K=42) GOTO 300:ON -(K=39) GOTO 400`

But, doing a quick test typing in JUST those lines on a VIC-20 emulator, I got 3530 bytes free after each approach. No penalty, but no savings, and all the parsing with parens and the negatives is probably slower.

Interesting, for sure. Useful? I guess I’ll find out if I get around to updating my VIC-20 code.

## Bonus offer

I also saw this example in the Commodore forum:

```10 rem if then else demo
20 input a
30 if a = 1 then goto 60
40 print "this is the else part"
50 goto 70
60 print "this is the if (true) part"
70 end```

This is how I’d write that with ELSE:

```20 INPUT A
30 IF A=1 THEN PRINT "THIS IS THE IF (TRUE) PART" ELSE PRINT "THIS IS THE ELSE PART"```

So we could change the Commodore example to match this a bit closer:

```20 input a
30 if a = 1 then print "this is the if (true) part":goto 70
40 print "this is the else part"
70 end```

…which leads us back to just adding a GOTO at the end of each separate IF:

```10 GET A\$:IF A\$="" THEN 10
20 IF K\$="U" THEN Y=Y-1:GOTO 70
30 IF K\$="D" THEN Y=Y+1:GOTO 70
40 IF K\$="L" THEN X=X-1:GOTO 70
50 IF K\$="R" THEN X=X+1:GOTO 70
60 GOTO 10
70 REM DRAW X,Y...
80 GOTO 10```

…which on the CoCo’s Extended Color BASIC might look like:

```10 GET A\$:IF A\$="" THEN 10
20 IF K\$="U" THEN Y=Y-1 ELSE IF K\$="D" THEN Y=Y+1 ELSE IF K\$="L" THEN X=X-1 ELSE IF K\$="R" THEN X=X+1 ELSE 10
70 REM DRAW X,Y...
80 GOTO 10```

Ultimately, we are just trading “ELSE” with “GOTO xx” and a new line, with ELSE being smaller due it it just being a token, verses the overhead of a GOTO token and the line number characters after it, AND a new line for each additional “else” condition.

Until next time, ELSE maybe sooner…

# VIC-20: Sky-Ape-Er code dissection – part 2

See also: part 1, part 2, part 3, part 4 or part 5 (with more coming).

Welcome to my second VIC-20 Tuesday!

Previously, I began to dissect my old VIC-20 game Sky-Ape-Er. It was made up of two BASIC programs:

1. INSTRUCTIONS – Display instructions, set up custom character set, then load and run the main game.
2. SKY-APE-ER – The main game.

## VIC-20 custom fonts

The VIC-20 did not have a true graphics screen. Instead, it used font characters that could be dynamically changed. Each character on the 22×20 screen was 8×8. You could create custom 8×8 characters to represent anything you wanted.

I believe I used a program called Eight by Eight Create by Robert Spahitz from the January 1983 issue of Creative Computing (Vol 9, Number 1). See page 270 (or 272 of this PDF scan):

https://archive.org/details/creativecomputing-1983-01/page/n271/mode/2up

Or this text version of just the article.

This also helps me confirm that I got my VIC-20 in 1982 since I initially did not have a Commodore Datasette tape deck for it and had no way to save programs until later. By the time this issue came out, I had the tape deck.

But I digress…

## VIC-20 custom fonts on the CoCo

I have screen shots of what the custom characters looked like in the VIC-20 game, but thought it would be fun to take those DATA statements and display them on my CoCo. Using lines 100 to 125 from the INSTRUCTIONS program, I created this Color BASIC program:

```0 REM skychars.bas
5 POKE 65495,0
10 CLS:XO=4:YO=2
15 DIM BM(7):FOR A=0 TO 7:BM(7-A)=(2^A):NEXT
20 FOR R=0 TO 7
25   READ V:IF V=-1 THEN 99
30   FOR C=0 TO 7
35     IF V AND BM(C) THEN SET(XO+C,YO+R,8) ELSE RESET(XO+C,YO+R)
40   NEXT
45 NEXT
50 XO=XO+10:IF XO>60 THEN XO=4:YO=YO+10
55 GOTO 20
99 GOTO 99
100 DATA223,223,223,0,253,253,253,0,0,0,0,0,1,3,3,7,0,60,126,219,129,165,165,129
105 DATA0,0,0,0,128,192,192,224,31,63,127,255,252,254,127,63,0,126,126,0,255,0,231,231
110 DATA248,252,254,255,63,127,254,252,15,7,8,30,31,31,31,31,231,219,60,255,126,126
115 DATA189,195,240,224,16,120,248,248,248,248,31,31,31,15,15,63,127,0,231,129,0,0,129
120 DATA129,129,0,248,248,248,240,240,252,254,0,12,12,24,47,8,15,82,36,48,48,24,244,16
125 DATA240,74,36,28,8,28,42,8,20,20,54,12,76,40,47,40,159,82,36
130 DATA -1```

It now displays what those font characters look like:

These custom characters would replace “@ABCDEFGHIJKLMNOP”. The “@” symbol was the brick used to make the game playfield.

Letters A-L were used to make the ape, like this:

```ABC
DEF
GHJ
JLK```

Letters M-O were the player’s character, facing right, left and forward.

Letter P were the small apes that were running towards the player. They never turned back, so no additional characters we needed for them.

My program was written to just put those characters on the screen, which would look like this:

But with the custom font in use, it looks like this:

In the next installment, I’ll walk through the actual SKY-APE-ER game code and see how it works.

Until next time…

# VIC-20: Sky-Ape-Er code dissection – part 1

See also: part 1, part 2, part 3, part 4 or part 5 (with more coming).

NOTE: This article was originally started on February 29, 2016, shortly after I discovered my cigar box of VIC-20 cassette. When I say “recently,” that now means “four years ago…”

Welcome to VIC-20 Tuesday!

I have slowly been importing my old VIC-20 programs in to the VICE emulator. This has been a tricky process. The tapes are over 30 years old and I no longer posses any real hardware to read them on. (I let my dad take my VIC-20 in exchange for getting me a Radio Shack TRS-80 Color Computer.) I played them on a higher end late 1990s Radio Shack dual cassette deck, and record them at 96khz stereo in Audacity on my Mac. The original tapes were mono, but some are stronger in one channel so I have been preserving both tracks as stereo audio files. I then use wav-prg to convert them to image files I can load in the VICE Commodore emulator.

My Sky-Ape-Er game has caught my attention. On the tape was a program called INSRTUCTIONS (with that typo I apparently never noticed) that will display instructions, wait for a keypress, then load the game as a second program called SKY-APE-ER. There were actually three copies of the main program, and at least two were different versions (oh, if only I had added version numbers to the file name). I also found several other copies of the main game program on other tapes in various forms of completion. I am hoping that this one is the “final” complete version.

…then you would type “RUN” (assuming you didn’t use the shortcut “RUN” key, which would do the “LOAD” and “RUN” automatically):

Then you press any key…

…and the program will have you “PLEASE WAIT” for a moment, then will erase itself with “NEW” and the “LOAD” the actual game.

I scanned the code to see how it did this, but I saw nothing obvious. No “NEW” or “LOAD” commands or anything. How did it work? Thanks to the Internet, I believe I figured it out.

First, let’s look at the source code of the program:

• Lines 5-6 – REMarks (comments).
• Line 10 – POKE stores a value at a memory location. But what is 36879, 808 and 775? A quick search lead me to some answers. 36879 (\$900f) is “Screen color / Reverse mode / Border color”. In the VIC-20 manual, Appendix E shows that 26 would be red border, and white screen. Another search led me to a Compute magazine article showing that  808 (\$328) is used to disable STOP, RESTORE and LIST (to prevent the user from BREAKing out of the program). 775  (\$307) showed up in a correction article from the same magazine, stating that it is what disabled LIST. (Not sure about 808, then. Maybe there were two POKEs required and the first article had a typo or left the second one out by mistake.)
• Line 15-25 – The Commodores allowed embedded special control characters, and the inverted heart is clear screen. The others are likely color codes and cursor movements, to position the text where I wanted it to be.
• Line 25-50 – More things that print the text on the screen.
• Line 55 – Gets a keypress then, if the keypress is nothing (“”), go back and get another keypress. This causes the program to spin in a loop until a key is pressed on the keyboard.
• Line 60 – Please wait … for what? It looks like what happens next may take a few seconds.
• Line 65 – This is clearing out memory locations 7424 to 7432. But why? All I can tell so far is this is some memory location in RAM with other places saying it’s in the User BASIC area. A helpful forum post gave me a hint. This is actually clearing out the 8 bytes that will make up the “space” character so once I customize the character set with game graphics, that character will still be a space. More on this next…
• Line 70 – This walks through memory locations 7168 to 7303 and POKEs them with the values read from DATA statements below. This is storing values in that range of memory. But what is 7168? According to this page, that is the start of “half RAM, half ROM of upper case normal characters since the 14-bit address space of the VIC wraps around”. I believe this is the font/character set, and the DATA statements are the custom graphics for the Sky-Ape-Er program (such as the bricks for the levels, the pieces that make up the ape, the chimps, and the player).
• Line 80 – This is the magic! According to this page, memory location 198 is the number of characters in the keyboard buffer. The VIC-20 has a keyboard buffer from 631-640 (9 bytes?). I am stuffing the buffer with 78 (“N”), 69 (“E”), 87 (“W”), 13 (“ENTER”) and then 131 (the “RUN” key). Thus, it’s like I typed “NEW” and pressed ENTER (clearing out the BASIC memory), followed by hitting the “RUN” key, which does a “LOAD/RUN” sequence, loading the next file from tape and running it. Huzzah! The autostart with done by stuffing the keyboard buffer as if the user typed commands. This tells me just putting in “LOAD:RUN” in a line of BASIC wouldn’t have worked (probably because it would overwrite the program, and you could never get to the RUN part). Cool
• Line 110-END – The rest of the code are the DATA statements that make up the custom character set. I will have to dissect them so I can see what the bitmaps look like.

I have no recollection of how this works, so I assume these POKE values were things I found in the Commodore VIC-20 manual or read in magazines such as Compute’s Gazette. There was very little information around back then. In fact, when I got this computer, I knew of only one store in all of Houston that sold software for it (other than Commodore cartridges at some places that sold the computer). I had my grandmother drive me across town to go there once, and that is the store where I bought the Krazy Kong game that inspired me to write Sky-Ape-Er.

There was a Commodore Houston’s User’s Group (CHUG) that I attended a meeting of, but that was the only time I ever met other VIC-20 users (other than going to meet the publishers of the FOX-20 cassette magazine at their house). It was a whole different world back then, and it’s amazing that I can go from from “what does this do?” to writing this article in just a few web searches.

Up next: A look at the actual Sky-Ape-Er game itself, including how it uses this custom character set for game graphics.

## Converted Source Code

Here is the INSTRUCTIONS program converted from PETASCII to ASCII. I found a utility that does this thanks to this blog post. The utility is found here:

It does a nice job of translating the PETASCII characters to {words} so I can better understand what was supposed to be there.

``````5 REM  ************          *SKY-APE-ER*        *******BY*******
6 REM*ALLEN  HUFFMAN*      ****************{\$cc}
10 POKE36879,26:POKE808,100:POKE775,200
15 PRINT"{clear}{black}{right:2}-=<<SKY-{red}APE{black}-ER>>=-{right:5}BY:{blue}ALLEN HUFFMAN"
20 PRINT"{purple}{\$a4:22}{\$a5}    INSTRUCTIONS    {\$a7}{\$a3:22}"
25 PRINT"{black}{down}CLIMB THE BUILDINGS TO CAPTURE THE MAD APE!"
30 PRINT" JUMP OVER CHIMPS AND UP STEPS TO GET TO THETOP. YOU MUST FACE THE";
35 PRINT"  DIRECTION TO JUMP."
40 PRINT"{down}{blue}      CONTROLS :{down}"
45 PRINT"{red}<LEFT>='A'{right}<RIGHT>='S'{right:4}<JUMP>='F1 KEY'"
50 PRINT"{down}{black}{rvrs on}    PRESS ANY KEY.    "
55 GETA\$:IFA\$=""THEN55
65 FORA=7424TO7432:POKEA,0:NEXTA
80 POKE198,6:POKE631,78:POKE632,69:POKE633,87:POKE634,13:POKE635,131
100 DATA223,223,223,0,253,253,253,0,0,0,0,0,1,3,3,7,0,60,126,219,129,165,165,129
105 DATA0,0,0,0,128,192,192,224,31,63,127,255,252,254,127,63,0,126,126,0,255,0,231,231
110 DATA248,252,254,255,63,127,254,252,15,7,8,30,31,31,31,31,231,219,60,255,126,126
115 DATA189,195,240,224,16,120,248,248,248,248,31,31,31,15,15,63,127,0,231,129,0,0,129
120 DATA129,129,0,248,248,248,240,240,252,254,0,12,12,24,47,8,15,82,36,48,48,24,244,16
125 DATA240,74,36,28,8,28,42,8,20,20,54,12,76,40,47,40,159,82,36``````

I normally just use the WordPress “preformatted text” box, but it did not like this listing. Hopefully this shows up.

Until next time…

# Porting 10 PRINT RACER by 8-Bit Show And Tell to the CoCo

YouTube decided to show me a video by 8-Bit Show And Tell. It is a BASIC driving game called “10 PRINT RACER” for the Commodore PET. For those that don’t know, “10 PRINT” is a one line Commodore BASIC program that generates a maze by randomly printing slash and backslash PETASCII characters.

`10 PRINT CHR\$(205.5+RND(1)); : GOTO 10`

There is even a book about it (which you can also download free). See the official site:

https://10print.org

I actually ported this to the CoCo years ago:

`10 PRINT CHR\$(47+(RND(2)-1)*45); : GOTO 10`

…but using the ASCII “/” and “\” characters just doesn’t have the same effect:

But I digress…

## 10 PRINT RACER

The game, 10 PRINT RACER, was based on this maze program. You drive a car through a passage in the middle of a random maze. The video demonstrates the game and then walks through the code, line by line.

I was impressed with his awareness of speeding up BASIC, such as using a FOR/NEXT loop with STEP 0 to create an infinite loop that is faster than using a GOTO. He also removes unnecessary spaces and combines lines together for faster execution. Heck, he even knows about using a period as a faster way to make zero!

## My PET experience

I’ve actually written programs for the PET. My high school had some, and I wrote a banner printing program for my typing teacher. She’d already written PRINT statements for each large letter based on needlepoint patterns, but there wasn’t enough memory in the PET to load them at the same time.

I solved this problem by having a main program input the message to print, then POKEing it to screen memory along with a “which character are we printing” counter. If the character to print was not in the current program, it would load and run the one that contained it. Those programs would then PEEK that screen memory to see what character it was supposed to print next.

A klunky solution, but it worked. (And in case you wondered why I used screen memory… I did not have a PET memory map, so I didn’t know where I could store the message data. I knew I could find screen memory by printing something on the screen and then PEEKing through memory until I found it. Once I located where the screen was stored, I used that for temporary memory. Funny enough, I did the same thing years later for my *ALLRAM* BBS when I needed a safe spot to temporarily load and execute PCLEAR 0 code.)

But I digress… Again.

## From Commodore PET to Radio Shack CoCo

Inspired by the video, I decided to port the game over to Color BASIC. This involved a few things:

1. Screen Size: The PET screen is 40×25, so I had to scale everything down to fit on the CoCo’s 32×16 screen.
2. PETASCII: The game uses two special characters which are not part of the standard ASCII that the CoCo has. I substituted with a forward slash (“/”) and a back slash (“\”). It doesn’t look as maze-like as the PET version, but it is the same general idea. There is also a PETASCII character that you print to clear the screen. I replaced that with CLS.
3. Input: Commodore uses GET instead of INKEY\$. I changed “GET A\$” to “A\$=INKEY\$”.
4. Memory Map: The game uses POKE and PEEK to put the racer on the screen, and check to see if it hit something. I had to change the PET memory location to be 1024, the start of the CoCo screen. I was surprised to hear him say the Commodore 64’s screen also starts at 1024.
5. Spaces: Commodore BASIC has the SPC() keyword which prints that many spaces. Color BASIC has TAB() but it moves to columns, so it couldn’t be used. I created an S\$ of 32 spaces using STRING\$() and then used MID\$() to get just the number of them I needed. This is likely much slower than if I had SPC().
6. Controls: The PET has a numeric keyboard, so the PET version used 4 for left, and 6 for right. The CoCo has arrow keys, so I changed it to use the left and right arrow keys. It now looks for CHR\$(8) for left and CHR\$(9) for right. Parsing CHR\$ is slower than the original which looked for “4” and “6”.
7. Random Differences: I thought I was going to have to change the random numbers. The Commodore version of RND would return a value from 0 to 1. You would then multiply the result by a number (X) which gave you a number from 0 to X. On the CoCo, doing RND(X) would return 1 to X. But, I realized RND(0) on the CoCo would do the same thing, so I ended up not changing it.
8. Key Repeat: The Commodore has key repeat and a small typeahead buffer. At the end of the PET code there was a POKE to clear out that buffer so it wouldn’t instantly restart the game if key presses were still in the buffer. I removed that POKE since the CoCo has no such buffer.

Here is what I came up with:

And here is the code:

```0 ' 10 PRINT RACER
1 ' BY WWW.8BITSHOWANDTELL.COM
2 '
3 ' PORTED FROM PET TO COCO
4 ' BY SUBETHASOFTWARE.COM
5 R\$="":CLS:PRINT"INIT:";:FORX=1TO75:M\$=CHR\$(47+45*(RND(2)-1)):R\$=R\$+M\$:PRINTM\$;:NEXT
6 S\$=STRING\$(32," ")
10 CLS:C=16:R=10:W=12:D=0:S=1024
20 L=0:FORZ=0TO1STEP0:X=RND(.)*10
30 IFX<4THENR=R-1:IFR<1THENR=1
40 IFX>5THENR=R+1:IFR+W>29THENR=29-W
50 RN=RND(.)*28+1:PRINTMID\$(R\$,RN,R);MID\$(S\$,1,W);MID\$(R\$,RN,31-R-W)
60 D=D+1:L=L+1:IFL>49THENL=0:W=W-1:IFW<3THENW=3
70 IFD<16THENNEXT
75 A\$=INKEY\$:IFA\$=CHR\$(8)THENC=C-1
80 IFA\$=CHR\$(9)THENC=C+1
90 P=PEEK(S+C):IFP<>96THEN200
100 POKES+C,106:NEXT
200 PRINTTAB(13)"CRASH!":IFD>H THENH=D
205 PRINTTAB(6)"SCORE:"D"  HIGH:"H
210 FORX=1TO2000:NEXT:A\$=INKEY\$
220 A\$=INKEY\$:IFA\$=""THEN220
230 GOTO10```

I tried to keep the code as close to the original as I could, so there are some more optimizations that we could do on the CoCo. For instance:

• Instead of using “RND(0)*10” for a value of 0-9, it might be faster to do RND(10) and adjust the IF/THEN to look for 1-10 instead of 0-9. This would save the overhead of doing the multiplication.
• If Extended BASIC can be used, then most constants can be changed to HEX values and they will be slightly faster. (Thought after seeing some code from Jim Gerrie recently, it may still be faster to parse some single digits as decimals over their HEX version. More on this in a future article.)
• Line 30 and 40 could be combined using ELSE, saving time each time the value is less than 5. Currently, if X is 1, it processes line 40 and then goes to line 50 which checks X again. Using ELSE would at least omit that step in that condition.
• The screen position variable (S) gets the car position (C) added to it each time it is POKEd or PEEKed. To save that math, the position of the car could be initialized as S+C and the two “+C”s in the code could be removed.
• There is a special IF in line 70 that is used to initially draw the screen before letting the car drive on it. Once the screen is drawn, it still checks this IF every time through. Time could be saved by drawing the initial screen outside of the main loop and then not needing to check that again.

What else do you see that might help speed things up? Please leave your comments, or take this code and see what you can do with it.

## PET emulator online

If you never got the pleasure of using one of these early Commodore Business Machines, I found a PET emulator that runs from a web browser:

https://www.masswerk.at/pet/

You can use that to type in the original Commodore “10 PRINT” program and see it run it all its glory:

Until next time…

# VIC-20 Super Expander and the CHUG logo

My first computer was a Commodore VIC-20. I used it to do TV titles for my dad’s fishing videos (he shot and edited video that would run at trade shows and such). I can’t find the tape of those VIC-20 graphics, but I did find this:

This was my version of the CHUG (Commodore Houston User’s Group) logo, done on the VIC-20 Super Expander cartridge. That cartridge added 3K of extra RAM, and had a ROM that gave new commands to do things like draw lines, play music, etc.

I also found a few other things, but I don’t think I had anything to do with them. (Unless I did the face graphic. That one, and as second version of it I found later, seem very familiar.)

The face one would draw the circles around the eyes, then un-draw them, over and over. Not really “blinking” but…

My quest for recovering my early VIC-20 games continues…

# Commodore Amiga documentary

I just found this Commodore Amiga documentary on HULU and watched it last night. You can find more information on the official website:

For those too young to remember, the Amiga was the most advanced home computer ever sold. It was incredibly ahead of its time, especially compared to any of the competing systems that were sold when it was released in 1985.

Us old timers recall the early days of home computer with systems like the Apple 2, Commodore PET, Atari 400/800, and TRS-80. There were many other systems, like the Timex Sinclair ZX81, Texas Instruments TI99, VIC-20 and then the massively popular Commodore 64 (and later less successful 128). Thanks to the internet, I have learned about dozens of other competing systems that I never even heard of back then.

The next generation of computers were things like the 1984 Apple Macintosh and the Atari ST. The Commodore Amiga blew everything out of the water. It had multitasking and amazing color graphics (back when a PC produced only 4 awful colors on a “high resolution” screen). It had 4-channel STEREO digital sound. It was just amazing.

I recall seeing an Atari ST in a shop in Houston, and really wanting one, but it was just too expensive. Sure, my CoCo setup ended up costing way more as I added more and more components, but I could do all of that gradually. The entry level cost of an Atari ST (or Amiga) and the required monitor was simply out of my price range.

But I had Commodore 64 friends that moved on to the Amiga, and I remember getting to see one of the first time (probably in late 1987). The bouncing ball demo brought tears to my eye. I had simply never seen anything like that on a home computer screen.

This documentary gives some of the background of the creation of the Amiga, and how it ended up at Commodore (and almost ended up at Atari).

It’s a fascinating look at what was truly an amazing piece of hardware.

The movie is streaming on HULU if you have a subscription, and can be rented or bought on many other services. I recommend it, though I wish it were about 10-15 minutes longer so it could give a more complete timeline of the various models that came out and why they were created (especially things like the CDTV and CD32).

Enjoy…

# Commodore VIC-20: My first computer.

My very first computer was a Commodore VIC-20. At the time, I think I was interested in a new video game system like an Intellivision. My dad suggested that, for about the same money, I could get a computer instead that would do more than just play games. (Second generation game systems like Intellivison or ColecoVision were around \$200.)

My desired to get a home computer was also inspired by a guy I met in one of my 7th grade classes. My new friend, Jimmy J., had shared a book on BASIC computer programming with me. We would go down to a local Radio Shack and type in programs on their TRS-80 Model 3s.

My dad began researching options, and I did the same. I ended up choosing something called a VIC-20. I was disappointed when my dad told me he had chosen a different machine – something he called the Commodore. When I realized we were talking about the same machine, it seemed like the perfect choice.

The VIC-20 marketing campaign was “Why buy just a video game?” and “A real computer for the price of a toy.” This may have actually been what got my dad thinking about a home computer in the first place. It was described as “the wonder computer of the 1980s for under \$300” and “the first honest-to-goodness full color computer you can buy for only \$299.95”, or so claimed launch spokesman William “Captain Kirk” Shatner.

A TV commercial for it parodied the Intellivison and the Atari VCS ads with Shatner “beaming down” between the two saying “move over for my friend VIC”. How could you go wrong with the computer that the Captain of the U.S.S. Enterprise liked?

I received my new VIC-20 sometime in 1982. It was likely for my birthday in August.

I remember hooking it up to a small color TV I had, and staying up all night going through the manual and learning how to program “CBM BASIC V2” which had a whopping 3583 bytes of memory available. Since I had no way to save any programs I typed in, I had to leave the computer on all the time else I would lose all my work. The Commodore Dataset (their expensive and proprietary cassette player)  was about \$75 at the time, and that was the first add-on I wanted. I still remember the problems I had with it, and that we had to exchange it at the store a few times (all with the same problem) until we figured out you just couldn’t use it on one side of the TV. There was too much electrical interference apparently.

## Custom Programs Limited

My friend Jimmy also got his first computer around this time – a Timex Sinclair. Another friend of ours, whose name I forget, had access to TRS-80s at school. Somehow we got the idea that we could offer to create custom programs for people, and thus the idea of “Custom Programs Limited” was created.

Jimmy suggested we change it to “Unlimited” so the initials would be C.P.U. At the time, I don’t think I even knew the term “central processing unit.” And thus was born CPU Software.

I remember we came up with an idea for a horse racing game, and each of us created a version of it for our systems: VIC-20, TRS-80 and Timex Sinclair. I do not think we ever did much after that. We probably did not realize how big home computing would become. Had we seriously pursued this venture, maybe we could have all ended up rich and living on a private island somewhere.

I did write a series of games for the VIC-20, including one that was published in a newsletter called the VIC-NIC NEWS. I believe I was in the process of having some of my video games distributed through a cassette magazine called VIXEN (renamed to FOX 20 after their first issue), but I do not recall what happened with that. I know one of the programs they considered (Factory TNT, a graphically updated version of the one VIC-NIC published) they rejected after seeing my first version already published elsewhere.

I have created a special page listing more details about my VIC-20 programs.

## Life After VIC

I think I only used the VIC for about a year. I had started frequenting a local Radio Shack store while my grandmother shopped next door. I was learning about their TRS-80 Color Computer. It wasn’t nearly as colorful as the VIC, but it had a better BASIC and much more RAM. I made friends with the workers there and they would let me hang out on Saturdays, writing programs or using their TRS-80 Model III and modem to dial in to local Houston bulletin board systems (BBS). I remember they would sometimes save off programs I wrote to cassette to use to demo the machine to other customers.

The salesman I interacted with most there was a man named Don Burr. He had a CoCo himself, and I remember the time he called me to tell me they had just gotten Extended Color BASIC in. He said I needed to come by and see all the new graphics and sound commands it had. When I did, seeing the ability to easily draw a LINE, CIRCLE or PLAY a musical note was magic. Everything on the VIC was done using POKE commands. (I did have the Super Expander cartridge that added similar commands to the VIC, but they were very slow and no one could run any programs you wrote unless they had the cartridge as well.)

Don was able to hook me up with a “CoCo” (expanded to 64K) for \$300, and I moved on from the VIC. As part of the deal of getting me a new computer, I had to give all my old VIC hardware and software to my dad. I don’t know what he did with it after that. After that, until recently, I pretty much never looked back. Only with the discovery of my old VIC-20 games am I starting to understand how much I actually did with that machine.

Good times.

Up next: Dissecting some of my very first programs. Will I even remember how they work?