Category Archives: Commodore

Let’s write Lights Out in BASIC – part 7

See also: part 1, part 2, part 3, part 4, part 5, part 6 and part 7.

Code cleanup in aisle 4.

Let me begin this installment by presenting the current Lights Out code with some renumbering done and a few minor improvements.

0 REM LITESOUT-P7.BAS

10 REM SETUP
20 DIM L(9,9)

100 REM START NEW GAME
110 GOSUB 5000
120 REM INITIALIZE GRID
130 MV=0
140 GOSUB 4000
150 REM SHOW GRID
160 GOSUB 1000
170 REM CHECK FOR WIN
180 IF LO=0 THEN 300
190 REM INPUT SQUARE
200 GOSUB 2000
210 REM TOGGLE SQUARES
220 GOSUB 3000
230 REM REPEAT
240 MV=MV+1
250 GOTO 150

300 REM GAME WON
310 PRINT "YOU WON IN";MV;"MOVES."
320 INPUT "PLAY AGAIN (Y/N)";Q$
330 IF Q$="Y" THEN 100
340 PRINT "GAME OVER"
350 END

1000 REM SHOW GRID
1010 PRINT "GAME NUMBER:";GN
1020 PRINT " ";
1030 FOR A=1 TO GS
1040 PRINT RIGHT$(STR$(A),2);
1050 NEXT:PRINT
1060 FOR Y=0 TO GS-1
1070 PRINT RIGHT$(STR$(Y+1),2);" ";
1080 FOR X=0 TO GS-1
1090 IF L(X,Y) THEN PRINT "X ";:GOTO 1110
1100 PRINT ". ";
1110 NEXT
1120 PRINT
1130 NEXT
1140 PRINT "MOVES:";MV;"LIGHTS ON:";LO
1150 RETURN

2000 REM INPUT SQUARE
2010 S$=MID$(STR$(GS),2):PRINT "X,Y (1-";S$;",1-";S$;" OR 0,0)";
2020 INPUT X,Y
2030 IF X=0 THEN IF Y=0 THEN 320
2040 IF X<1 OR X>GS OR Y<1 OR Y>GS THEN 2010
2050 X=X-1:Y=Y-1
2060 RETURN

3000 REM TOGGLE SQUARES
3010 L(X,Y)=NOT L(X,Y):LO=LO-(L(X,Y)*2+1)
3020 IF X>0 THEN L(X-1,Y)=NOT L(X-1,Y):LO=LO-(L(X-1,Y)*2+1)
3030 IF X<GS-1 THEN L(X+1,Y)=NOT L(X+1,Y):LO=LO-(L(X+1,Y)*2+1)
3040 IF Y>0 THEN L(X,Y-1)=NOT L(X,Y-1):LO=LO-(L(X,Y-1)*2+1)
3050 IF Y<GS-1 THEN L(X,Y+1)=NOT L(X,Y+1):LO=LO-(L(X,Y+1)*2+1)
3060 RETURN

4000 REM INITIALIZE GRID
4010 INPUT "GRID SIZE (3-10, ENTER=5)";GS
4020 IF GS=0 THEN GS=5
4030 IF GS<3 OR GS>10 THEN 4010
4040 PRINT "INITIALIZING..."
4050 FOR A=1 TO 10*GS
4060 Y=RND(GS)-1
4070 X=RND(GS)-1
4080 GOSUB 3000
4090 NEXT
4100 RETURN

5000 REM SELECT GAME
5010 PRINT "PLAY SPECIFIC GAME # (Y/N)?"
5020 S=S+1:A$=INKEY$:IF A$="" THEN 5020
5030 IF A$="Y" THEN 5070
5040 IF A$="N" THEN A=RND(-S)
5050 GN=RND(65535):A=RND(-GN)
5060 GOTO 5100
5070 INPUT "PLAY GAME (1-65535)";GN
5080 IF GN<1 OR GN>65535 THEN 5060
5090 A=RND(-GN)
5100 RETURN

As I tested this version, I noticed my random grid generator was not very good–at least on a large 10×10 grid. It really needed to do more random light toggling for larger grids. This change would go in this line – maybe just doing a “grid size * X”, like “10*GS” or something. I am still trying things, but for now I made it do more random toggles the larger the grid size is (line 4050).

I also made it so the default grid size was 5 (line 4010).

And I fixed some output where it printed a numeric variable. In Color BASIC, there is an extra space printed before and after printing a number:

PRINT "*";42;"*"
* 42 *

And, technically, it’s not a space before a number — it’s a place for the sign (none if positive, “-” if negative):

PRINT "*";-42;"*"
*-42 *

Since I knew I was only printing a positive number, I just got rid of that leading space, and the one after it. I did this by converting the number to a string using STR$. That will convert it to a string with the first space (a place for the sign) but no space after it:

PRINT "*";STR$(42);"*"
* 42*

Then all I needed to do was trim off that leading space. In the old days, I would have done this by getting the length of the string using LEN$ and then using RIGHT$ to get just the character(s) after that leading space:

N=42
N$=STR$(N)
L=LEN(N$)
PRINT RIGHT$(N$,L-1)

But in recent years, someone commented on this site (I believe) about how you could use MID$ without a size and just specify the starting position in a string, and it would return everything from that position to the end:

N=42
PRINT MID$(STR$(N),2)

Nice! “Wish I knew then what I know now…”

But I digress…

We now have a fairly “feature complete” version of Lights Out that runs in very basic BASIC — it doesn’t even make use of ELSE.

Before I move on to making this look a lot nicer on a CoCo, I thought it might be fun to port it to a VIC-20. I made use of the wonderful CBM prg Studio Windows-based tool that can build BASIC or assembly programs for all kinds of Commodore machines. I just pasted in my source, and then found a few minor things I would need to change to run on the VIC-20’s CBM BASIC.

The first thing I did after pasting the code in to the editor was to convert it all to lowercase. That seems to be how that BASIC works, as SHIFT characters turn in to PETSCII graphics characters.

Now I would be able to build the program.

It would build right away, but not run on the VIC yet until I fix two things that are different between Color BASIC and CBM BASIC:

  • A$=INKEY$ must be changed to GET A$
  • RND(x) must be changed to INT(RND(1)*X)-1 (Doing the random seed using RND(-X) works the same way on the VIC, and could be left alone.)
CoCo:
5020 S=S+1:A$=INKEY$:IF A$="" THEN 5020

VIC:
5020 S=S+1:GET A$:IF A$="" THEN 5020

CoCo:
4060 Y=RND(GS)-1

VIC:
4060 Y=INT(RND(1)*GS)

CoCo:
4070 X=RND(GS)-1

VIC:
4070 X=INT(RND(1)*GS)

After that, I tried to RUN it and ran in to a problem with INPUT:

From testing, it seems that long prompts on INPUT cause issues, possibly related to how the VIC’s full screen editor works. I sent a tweet to 8-Bit Show and Tell to see what he knew, and did a simple workaround by breaking up the prompt and the input on separate screen lines:

4000 rem initialize grid
4010 print "grid size (3-10, enter=5)":input gs

I thought I might have the same issue with the “select square” input, but that prompt does not overlap to the next line so it worked… or so I thought. With the default grid size of 5×5, the prompt looked like:

X,Y (0-5,0-5 OR 0,0)?(space)
*(cursor here)

That seemed to work just fine, but when I did a grid of 10×10, it made the prompt longer, wrapping the “?” of INPUT to the next line:

X,Y (0-10,0-10 OR 0,0)
? *(cursor here)

So I needed to fix that, too. I had already had to break that one up in to a PRINT and an INPUT since I was printing variables in the prompt, so I just took the semicolon off from the end of the PRINT:

2000 rem input square
2010 s$=mid$(str$(gs),2):print "x,y (1-";s$;",1-";s$;" or 0,0)"
2020 input x,y

Now I had what appeared to be a working version of the game for VIC-20. BUT, it would need some work to reformat the prompts to fit on a 22-column screen, versus the 32- column CoCo screen. For anyone who wants to work on that, here is the VIC-20 version with the lines in bold that have changes from the CoCo version:

0 rem litesout-p7.bas

10 rem setup
20 dim l(9,9)

100 rem start new game
110 gosub 5000
120 rem initialize grid
130 mv=0
140 gosub 4000
150 rem show grid
160 gosub 1000
170 rem check for win
180 if lo=0 then 300
190 rem input square
200 gosub 2000
210 rem toggle squares
220 gosub 3000
230 rem repeat
240 mv=mv+1
250 goto 150

300 rem game won
310 print "you won in";mv;"moves."
320 input "play again (y/n)";q$
330 if q$="y" then 100
340 print "game over"
350 end

1000 rem show grid
1010 print "game number:";gn
1020 print " ";
1030 for a=1 to gs
1040 print right$(str$(a),2);
1050 next:print
1060 for y=0 to gs-1
1070 print right$(str$(y+1),2);" ";
1080 for x=0 to gs-1
1090 if l(x,y) then print "x ";:goto 1110
1100 print ". ";
1110 next
1120 print
1130 next
1140 print "moves:";mv;"lights on:";lo
1150 return

2000 rem input square
2010 s$=mid$(str$(gs),2):print "x,y (1-";s$;",1-";s$;" or 0,0)"
2020 input x,y
2030 if x=0 then if y=0 then 320
2040 if x<1 or x>gs or y<1 or y>gs then 2010
2050 x=x-1:y=y-1
2060 return

3000 rem toggle squares
3010 l(x,y)=not l(x,y):lo=lo-(l(x,y)*2+1)
3020 if x>0 then l(x-1,y)=not l(x-1,y):lo=lo-(l(x-1,y)*2+1)
3030 if x<gs-1 then l(x+1,y)=not l(x+1,y):lo=lo-(l(x+1,y)*2+1)
3040 if y>0 then l(x,y-1)=not l(x,y-1):lo=lo-(l(x,y-1)*2+1)
3050 if y<gs-1 then l(x,y+1)=not l(x,y+1):lo=lo-(l(x,y+1)*2+1)
3060 return

4000 rem initialize grid
4010 print "grid size (3-10, enter=5)":input gs
4020 if gs=0 then gs=5
4030 if gs<3 or gs>10 then 4010
4040 print "initializing..."
4050 for a=1 to 10*gs
4060 y=int(rnd(1)*gs)
4070 x=int(rnd(1)*gs)
4080 gosub 3000
4090 next
4100 return

5000 rem select game
5010 print "play specific game # (y/n)?"
5020 rem s=s+1:a$=inkey$:if a$="" then 5020
5021 s=s+1:get a$:if a$="" then 5020
5030 if a$="y" then 5070
5040 if a$="n" then a=rnd(-s)
5050 gn=rnd(65535):a=rnd(-gn)
5051 rem gn=int(rnd(1)*65535)-1:a=rnd(-gn)
5060 goto 5100
5070 input "play game (1-65535)";gn
5080 if gn<1 or gn>65535 then 5060
5090 a=rnd(-gn)
5100 return

The more I look at this code, the more optimizations I want to make to it.

But for now, that is a version for CoCo, and a version for Commodore. It should be easy to port to other flavors of BASIC. Let me know if you port it to something.

Now that I know how to write the game, the next goal will be to make it look a lot better on the CoCo (and maybe VIC-20 as well, if I feel ambitious).

But I think I need a brake from Lights Out for a bit…

Until then…

Dissecting my VIC-20 Eggs game

The story so far…

In 1982 (possibly 1981?), I received my first computer, a Commodore VIC-20.

I taught myself BASIC and ended up sending in a simple game to a newsletter called VIC-NIC News.

Recently, someone sent me a scan of my program submission, ending a quest I had been on for almost a decade.

Here is that article from VIC-NIC News #6 (Volume 2, Number 4) from July/August 1983:

I thought it would be fun to walk through the program and see what it does…

0 rem 2024/2/11 fixed joystick

I added this line when I “fixed” the joystick routine so it could properly read the RIGHT direction. That fix, and the two numbers checked for moving the cup left or right, will be different than the original version published back in 1983.

1 print"{clear}{down*3}      eggs"
2 print"{down*3} by allen huffman"
3 print"{down*2}vic-nic news july 1983"
4 forj=1to5000:next

I believe these lines were added by the VIC-NIC NEWS. The {words} in curly braces are ASCII notation for the Commodore escape codes you could put in PRINT statements. {clear} is the code for clearing the screen, and {down} is the code for moving the cursor down one line. Therefore, that clears the screen then moves down three lines before spacing over to print the game title. The text would print in UPPERCASE and the code appears in UPPERCASE on an actual VIC-20. These lines just print a simple title screen, then wait for a few seconds before starting the game.

5 poke36879,8:printchr$(147)

Heh. I remember joking that everything on the VIC-20 used the POKE command, and sure enough, the very first thing I do in my program was a POKE. I consulted a useful VIC-20 memory map document to find this:

900F     36879    Screen and border color register
                   bits 4-7 select background color
                   bits 0-2 select border color
                   bit 3 selects inverted or normal mode

The value of 8 is bit 3 , so I was leaving “normal” mode on and setting background and border colors to 0. I don’t recall what this does, so I tried it in the VICE VIC-20 emulator and see it makes the screen black with blue text:

Checking the PEEK value of 36879 on startup shows it defaults to 27, which is the bit pattern 00101011.

36879    Screen and border color register

7 6 5 4 3 2 1 0
---------------
0 0 1 0 1 0 1 1
| | | | | | | |
| | | | | +-+-+- bits 0-2 select border color
| | | | +------- bit 3 selects inverted or normal mode
+-+-+-+--------- bits 4-7 select background color

Border Color = 011 (3)
Inverted/Normal = 1 (normal?)
Background Color = 0010 (2)

As I searched for information on the colors, I found the wikipedia page for the VIC’s video chip. It lists the 16 colors the VIC-20 could produce as follows:

0 — black
1 — white
2 — red
3 — cyan
4 — purple
5 — green
6 — blue
7 — yellow
8 — orange
9 — light orange
10 — light red
11 — light cyan
12 — light purple
13 — light green
14 — light blue
15 — light yellow

With only three bits for the border color, the border can only use colors 0-7 (black through yellow). The background color uses four bits, so it can be any of the sixteen colors (0-15). I may have known this at the time, but if so, I had forgotten that the border could not be set to match all the possible screen colors.

In my case, setting the background and border to 0 makes it black.

If I had taken the original value (00101011, 27) and just cleared bit 3 (invert/normal, 00100011, 19), I see that it changes the text/foreground to inverted video:

Interesting. So I guess we are seeing inverted video on a black screen with black border? I really don’t know why, and I suspect I just saw that POKE in a magazine and liked it.

The print of CHR$(147) is the escape code that clears the screen. (Yep, there was not even a CLS type command in Commodore BASIC.)

10 b=8130:m=3:sc=0
15 e=int(rnd(1)*20)+7703

Two of these variables deal with locations within screen memory:

1E00-1FFF    7680-8191     Screen memory

B is the memory location of the player’s bucket. This is some spot on the bottom line of the screen. 7680 represents the top left character of the VIC’s 22×23 text screen. If you do the math, that is 506 bytes of memory used to represent the screen. But, screen memory of 7680-8191 is 512 bytes. The actual last visible byte on the screen is 8185. The player’s bucket is at 55 spots earlier, which is two full lines (22 bytes each) and 11 (half way in a 22 line screen). I am not sure why I started the game on the third line UP from the bottom, but I did.

M is how many men are left. Video games were very male-centric in the early days, I guess. Actually, in the early years, I don’t recall ever knowing a single girl that played video games, and do not recall seeing any in the arcades I went to, either.

SC is the score, which starts at 0.

E is the memory location of the falling egg. It starts at 7703 (the second byte of the second line) and then adds a random value of 0-19to it. This means I left out the left and right column of the screen for some reason. Looking at how I designed my later Factory TNT game, where the game had a border on the left and right and also a few lines at the bottom of conveyor belt graphics…

VIC-20 Factory TNT.


…it makes me wonder if I was already planning something like that for Eggs, but left it out to make the program smaller and easier to type in from a newsletter. (Above, you see I start the cup in Factory TNT 5 lines up, instead of 3 like Eggs, but it also limits the falling bombs under the spigots not using the left and right side of the screen. Curious.)

20 printchr$(19);chr$(5);"score:";sc

CHR$(19) homes the cursor to the top left. This would be like doing “PRINT@0,;” on the CoCo. The “SCORE:” is then printed with the current value.

25 pokeb,21:pokee,81

The character of 21 (a letter “U”) is POKEd to the player location, and a character 81 (filled circle) is POKEd to the falling egg location.

30 poke37154,127
35 j=(not((peek(37152)and128)/8+(peek(37137)and60)/4))+32
40 poke37154,255

This code, which I must have gotten from some magazine, is the joystick code. The code in the original article used incorrect memory locations, and was unable to read the “right” direction. I must not have known why, and just changed the published version to use UP and DOWN to move left and right (or, maybe it worked for me, but VIC-NIC NEWS couldn’t get it to work due to a typo and changed the directions?). Either way, memory location 37152 contains the “right” joystick switch, and 37137 contains the “up, down, left and fire” switches. The bits in one of these gets used for different things, to the POKEs to 37154 are used to toggle one of the bytes from joystick mode to keyboard mode. When you do that POKE, part of the keyboard stops working, so it has to be POKEd back at the end.

Because of how this works — if you BREAK the program at the wrong time, during those lines when it is POKEd to joystick, you won’t be able to type all the characters on the keyboard. A frustrating issue ;-)

45 ifj=0then80
50 pokeb,32
55 ifj=4thenb=b-1
60 ifj=16thenb=b+1

The joystick line basically takes the 4-bits (up, down, left and fire) from one memory location and the 1-bit (right) from the other location and combines them in to one byte. Because the bits read “1” when NOT pressed, and “0” when pressed, the code also inverts the results so “1” now means ON.

This IF statements check for directions. J=0 means nothing is pressed, so skip the rest. J=4 means the left button is pressed, so decrement the bucket location by one (moving it one to the left). J=16 means the right button is pressed, so increment the bucket location by one (moving it to the right).

65 ifb=8120thenb=b+1
70 ifb=8141thenb=b-1

These two checks make sure the bucket did not move too far left or right. B=8120 checks to see if the new position is in the first column. If so, too far, so move it back to the right one place. B=8141 is checking for the right column and if it is there, it moves it back left one. With am minor change, I could have made it so you could “wrap around” the screen, where if you moved to the right it would reset the position to the left, and vise versa. That might be an interesting update or option. (Allowing you to quickly “warp” from the left side of the screen to the right to catch an egg you might have otherwise missed.)

Hmm, thinking about this, maybe I shortened the number of rows that the egg drops so ensure you always had less time to move and catch it, increasing the challenge?

75 pokeb,21
80 pokee,32
85 e=e+22
90 pokee,81

At line 75, the player’s basket location has been updated so we POKE the “U” character (21) back on the screen. We then POKE a space (32) to where the egg is, erasing it. The Egg location is incremented by 22, moving it down to the next line, then the Egg character (81) is POKEd back to that new location.

95 ife=>8120ande=bthen110
100 ife=>8120ande<>bthen115
105 goto25

Much like how the basket is checked against the left and right column of the screen, some checks for the falling egg location are done here. If the egg location is at or greater than 8120 (first character of three lines from the bottom of the screen) then it is checked to see if it is the same position of the basket (the player caught the egg).

I’d have to benchmark this and see if that “e>=8120” even needs to be there. If that condition is not true, it would just skip quickly to the end of the line and move on. I’m expecting the overhead of checking “e=b” is less (no long number to parse) so it would probably be faster to just always check “e=b”. If the egg was caught, GOTO 110 happens to increment the score.

There is another check for >=8120 and then “e<>b” skipping to another line. This is poorly coded. If the check for “bottom” line was needed, something like this might be better:

IF E>8120 THEN xxx
IF E=B THEN 110 (player caught it)
...else, player did not, handle here
xxx continue on...

Something like that would simplify the logic, speed it up, and reduce the program size. But hey, I was just learning BASIC.

After this, if the egg did not reach the bottom and get caught or not caught, it goes back up to line 25 to continue the program loop.

110 sc=sc+10:pokee,32:goto15

This is where we go when the player catches an egg. Score is incremented by 10, the egg is erased by POKEing a space there, and then we go to line 15 where a new egg position will be created and the process will start over.

115 m=m-1:pokee,32
120 ifm=0then135
125 goto15

115 is where we end up if the egg reaches the bottom and the player did NOT catch it. The “men left” variable will be decremented, and the egg erased.

If M gets to 0, then game over, which is handled at line 135.

Otherwise, we go back to line 15 to make a new falling egg and continue.

135 fort=1to5:printchr$(17):next
140 fort=1to6:printchr$(32);:next
145 printchr$(158);"game over"
150 print"{down*2}play again? y/n"
155 geta$:ifa$="y"thenrun
160 ifa$="n"thenend
165 goto155

CHR$(17) is the escape code to move the cursor down one line, so the first line moves down five lines.

CHR$(32) is a space, so the second line prints six spaces over.

CHR$(158) sets the text color to yellow, it seems, and prints “GAME OVER”.

Then, for some reason, I don’t use the CHR$(17) to move down, and instead use the embedded screen code. This makes me wonder if I did this, or if it was changed by the VIC-NIC NEWSLETTER folks.

My choice of looking for “Y” or “N” is interesting. This works, and is short, but it is not how I would do it today. If GET A$ catches a “Y” we just RUN to start everything over. If it is an “N” we just END and stop right there. Otherwise we go back and check again.

This is kinda clever, since I would have thought of writing it like:

xxx GET A$:IF A$="" THEN xxx
IF A$="Y" THEN RUN
IF A$="N" THEN END
GOTO xxx

…and that would be larger. Was I smarter then?

And that, my friends, is my first published program. I do not know how close this code is to what became Factory TNT (it would have been trivial to rewrite from scratch) but I can definitely see similarities — it is effectively the same program, just with more graphics, sound and such added in the Factory TNT version.

And now I guess that is all I can possibly write about this program.

Until next time, that is…

My 1983 VIC-20 Eggs game has a typo in the joystick routine

Down the VIC-20 joystick rabbit hole I go…

In my recently-recovered “first program I ever had published,” I noticed that the joystick was not working. I was testing on VICE (the Versatile Commodore Emulator) on a Mac. The code that I had to read the joystick was clearly something I found in a magazine or somewhere because I have no idea what it does:

30 POKE37154,127
35 J=(NOT((PEEK(37151)AND128)/8+(PEEK(37151)AND60)/4))+32
40 POKE37154,255

I suspected maybe a typo was introduced when VIC-NIC NEWS typed in my program to print it out for publication. I did some searching to see how you were supposed to read the VIC-20 joystick. I was surprised that the Commodore VIC-20 manual didn’t offer any code to do this.

I found an Atari Magazine page that simply said you used two PEEKs:

The VIC is designed to handle only one joystick, and it takes two bytes to control that joystick. In the VIC, location 37137 is PEEKed to read the joystick for the up, down, left, and fire button movements. Location 37152 is PEEKed to detect movements to the right.

To see just how easy it is to detect movement on the joystick, plug in your joystick, type in one of the following short programs, and then RUN. The programs simply PEEK the joystick control bytes, and then PRINT that reading to the screen.

For the VIC-20:

10 PRINT PEEK(37137), PEEK(37152) : GOTO 10
– Atari Magazine, issue 42

Curious. My code was not using either of those addresses. Either my code or this magazine had a typo.

I tried those two PEEKs in VICE and noticed only the fire button was making the values change. This matched the VICE joystick display also showing only the fire button working.

I then thought the joystick I was using (a USB joystick that came with my TheVIC20) might have an issue. I tested it using a joystick test program, and it appeared to read all directions correctly.

A bit of more searching and I found that the Mac version of VICE has has an issue with joysticks not working since sometime in 2022:

https://sourceforge.net/p/vice-emu/bugs/1785

Even if my code was correct (to be determined), I would not be able to test it on the Mac version of VICE.

I then tried running Eggs from the Windows version of VICE and was able to see the joystick work — but, it was using UP and DOWN to move the cup left and right. Odd. I know I must have intended for it to use left and right, because my typed instructions clearly stated:

“Use joystick to move the cup left and right to catch falling eggs.”

– Eggs instructions.

While technically it didn’t say “move the joystick left or right,” I think it would have been a very odd choice for me to use “up” to mean left, and “down” to mean right, in a game like this.

This led me back to suspecting a typo in my joystick code. I went back to those two PEEKs from Atari magazine and tested them on the Windows version of VICE. This time, it seemed to change for all directions other than right. It gave values for Up, Up-Left, Left, Left-Down and Down, as well as the button. Clearly, this code was wrong (or maybe the Windows version of VICE also had an issue).

I decided to figure out where my joystick code came from. I searched for this code:

J=(NOT((PEEK(37151)AND128)/8+(PEEK(37151)AND60)/4))+32

…and archive.org actually had a single match! It was found in Issue #8 of The TORPET (Toronto Pet) on page 31. This Commodore PET publication had a section about the then-new VIC-20. For fun, here is the entirety of their VIC-20 section:

VIC NOTES
by John O’Hare

As of Mid October, 15,000 VIC’s have been sold in Japan, 15,000 more in the U.S., and, though not yet available in Europe, orders are accumulating fast. -JS

If you really want a color PET, Commodore suggests you consider buying a VIC as a peripheral for your PET! Seriously, it uses Upgrade BASIC V2, is cassette compatible, and has excellent color compared to Apple, and Atari. -JS

Some VIC POKE locations are:

51 decrements when key hit. 204 cursor on flag.
56 pointer to top of memory. 211 cursor column.
67 holds 1 when key hit. 214 cursor row.
197 value of key depressed. 36865 border position (vertical).
145 flag for left shift key. 36864 border position (horizontal).
245 detects special keys. 36869 pointer to character generator.
240= norm. 255 = 7168.

To read a joystick on a VIC (standard ATARI joystick works), use the following subroutine:

9000 POKE 37154,127
9010 JO= (NOT((PEEK(37152)AND128) /8+( PEEK(37151)AND60)/4)) +32
9020 POKE 37154,255
9030 RETURN

JO Values returned are: 1 = up, 17 = up and rt, 16= right, 18 = down and r t,
2 = down, 6 = down and Ift, 4= left, 5= up and Ift.

VIC GAME REVIEWS

VIC GAMES PAC, $25 from Creative Software. 3 VIC arcade games: VIC Trap, Seawolf, and Bounce Out. Seawolf and Bounce Out are machine language, with very fast action. Very good games, but could be better if they used Hi Res graphics. -JOH

– The TORPET, Issue #8, Page 31

Wow, early days – reporting only 15,000 VIC-20s had been sold at that point!

In my code, I check for the value of 18 to move the bucket left (“ifj=18thenb=b-1”) and a value of 17 to move the bucket right (“ifj=17thenb=b+1”). That matches the values for up and down in this TORPET article! I guess I really did mean for up and down to move left and right.

But I have a theory about this, which I will get to in a moment…

The thing I immediately noticed was this code used two different memory locations, while my program (as listed in VIC-NIC NEWS) used the same memory location twice. I consulted a VIC-20 memory map to see what all the various addresses are for:

  • 37137 – Port A output register: (PA0) Bit 0=Serial CLK IN, (PA1) Bit 1=Serial DATA IN, (PA2) Bit 2=Joy 0, (PA3) Bit 3=Joy 1, (PA4) Bit 4=Joy 2, (PA5) Bit 5 = Lightpen/Fire button, (PA6) Bit 6=Cassette switch sense, (PA7) Bit 7=Serial ATN out
  • 37151 – Port A (Sense cassette switch)
  • 37152 – Port B output register: keyboard column scan, (PB3) Bit 3 =cassette write line, (PB7) Bit 7 =Joy 3
  • 37154 – Data direction register B

The TORPET code looked wrong since one of the locations it was using had nothing to do with the joystick.

The Atari Magazine looked better since it used the two locations that mentioned joystick – 37137 and 37152. 37137 contains three joystick directions (Joy 0-2) plus the button. 37152 contains the final joystick direction (Joy 3). However, running this code doesn’t show anything changing for “right”.

I think the extra POKEs the code I used (and the code in The TORPET used) may explain that. It seems you have to POKE to change the purpose of some of this bits. 37154 is a data direction register for Port B (37152), and before my joystick code I POKE it to 127 which is a binary pattern of 01111111. After doing the joystick PEEK, the code POKEs it to 255, which is 11111111. I am suspecting that that 0 (bit 7) indicates read of whatever is hooked to that bit — which is Joy 3 (PB7). It looks like you turn it to 0, then you can PEEK it, then it gets set back to a 1 after.

I added this to the Atari Magazine code:

5 POKE 37154,127
10 PRINT PEEK(37137), PEEK(37152) : GOTO 10

…and now the second value changes when the joystick is pressed right. Huzzah!

It looks like the first byte reads up, down, left and fire, and the second is right. The POKE is only used to toggle the right bit on and off to do a read. It should get restored after (set back to 1) but in my quick demo, I didn’t bother to do that and I found I could not type certain keys. Aha, that explains “keyboard column scan.” That bit must be used to read a keyboard column, normally, and can be switched to read the joystick instead.

I will have to explore that more, later, but for now I can clearly see an issue with my code. By using only one of those locations, it is never reading the I/O bit that represents the “right” direction.

The code listed in The TORPET is incorrect:

9000 POKE 37154,127
9010 JO= (NOT((PEEK(37152)AND128) /8+( PEEK(37151)AND60)/4)) +32
9020 POKE 37154,255
9030 RETURN

37151 does not have anything to do with the joystick. This code takes the PEEK of that location and ANDs it with 60 (bit pattern 00111100) telling me it is expecting to use four bits. That matches the four joystick bits that are at 37137:

  • Bit 2 – (PA2) Bit 2=Joy 0
  • Bit 3 – (PA3) Bit 3=Joy 1
  • Bit 4 – (PA4) Bit 4=Joy 2
  • Bit 5 – (PA5) Bit 5 = Lightpen/Fire button

I think The TORPET got it wrong, and that second PEEK should be 37137.

The PEEK of 37152 seems okay. It ANDs it with 128 (bit pattern 10000000) which matches looking for that bit for the joystick:

  • Bit 7 – (PB7) Bit 7 =Joy 3

I suspect Atari Magazine just omitted the POKE needed to have the bits come from the joystick port, and The TORPET just had the wrong address listed. Since I had never heard of The TORPET, I expect I got my code from one of the few magazines I had at the time (Family Computing, Compute or Compute’s Gazette).

I changed my code to use 37137, but it still did not work! Now I could only move to the right by pressing Up+Right.

I think it is time to figure out what this code is trying to do.

Figuring out what this code is trying to do

Let’s start with the “correct” TORPET code and dissect what it is doing:

J=(NOT((PEEK(37152)AND128) /8+( PEEK(37137)AND60)/4)) +32
  • 37137 – Port A output register: (PA0) Bit 0=Serial CLK IN, (PA1) Bit 1=Serial DATA IN, (PA2) Bit 2=Joy 0, (PA3) Bit 3=Joy 1, (PA4) Bit 4=Joy 2, (PA5) Bit 5 = Lightpen/Fire button, (PA6) Bit 6=Cassette switch sense, (PA7) Bit 7=Serial ATN out
  • 37152 – Port B output register: keyboard column scan, (PB3) Bit 3 =cassette write line, (PB7) Bit 7 =Joy 3

PEEK(37152) uses “AND 128” to get just the high bit (bit 7) of Port B, which is the “right” joystick direction. It will either be 0 (no right) or 128 (right). It then divides by 8 which effectively shifts that bit over three places to the right:

10000000 - 128 (original reading)
00010000 - 16 (after the divide by 8)

PEEK(37137) uses “AND 60” to mask out the four bits in the middle. If they were all “on” (you can’t do that with a normal joystick), it would read 00111100. It then divides by 4 which effectively shifts those bits over two places:

00111100 - 60 (original reading if all joystick inputs were "on")
00001111 - 15 (after the divide by 4)

It adds those two values together, so this code is creating a new value of 5 bits, where those five bits represent the joystick switches for up, down, left, right and fire (00011111). From looking at the bit pattern, this new byte represents the following:

  • Bit 0 – Up
  • Bit 1 – Down
  • Bit 2 – Left
  • Bit 3 – Fire
  • Bit 4 – Right

Next I wondered why the program uses “NOT.” From checking the PEEKs, I see that when a joystick switch is not on, it shows a 1. When it is activated, it shows a 0. The NOT is used to invert that logic:

If no switches are pressed, the value is 31 (00011111). NOT flips the bits, so that value becomes 11100000. (Actually, I think it is represented as 16-bits, so 11111111111000000.) I believe when you use AND/OR/etc. the value is treated as a 16-bit signed value (-32768 to 32767) with the high bit representing negative. There result is the 31 becomes a -32. This explains the “+32” at the end.

The result is a value that is 0 if no switches are pressed. All of this match (dividing, adding, NOTing) does make the routine slow so maybe we’ll play with speeding it up sometime…

Using this newly created bit pattern, the BASIC program could use specific values to represent a direction (up), or two directions at the same time (up+left). My game did not use the fire button, but I think the way you would check that would be to use AND on the JO value to look for that specific bit, that way the rest of the value could be anything (up+fire, up+left+fire, nothing+fire, etc.).

Here is a test program for the “fixed” TORPET code:

10 rem fixed torpet code
20 gosub 9000
30 if jo and 1 then print "up ";
40 if jo and 2 then print "down ";
50 if jo and 4 then print "left ";
60 if jo and 8 then print "fire ";
70 if jo and 16 then print "right";
80 if jo<>0 then print
90 goto 20
9000 poke 37154,127
9010 jo=(not((peek(37152)and128)/8+(peek(37137)and60)/4))+32
9020 poke 37154,255
9030 return

Though, a mystery I Have yet to understand, is why do so many VIC-20 joystick references say you can also use 37152 and 37151? This code also works:

9010 jo=(not((peek(37152)and128)/8+(peek(37151)and60)/4))+32

Anyone know?

Now … why did I use Up and Down in my original Eggs? I think this is because the joystick code I had was broken and never returned a value for right. This was because it was PEEKing the same byte twice instead of the second byte being the one that had the “right” switch! I probably couldn’t get it to work, so I just used UP and DOWN.

Using this “fixed” code, I could now alter my program to work like I originally intended:

0 rem 2024/2/11 fixed joystick
1 print"{clear}{down*3} eggs"
2 print"{down*3} by allen huffman"
3 print"{down*2}vic-nic news july 1983"
4 forj=1to5000:next
5 poke36879,8:printchr$(147)
10 b=8130:m=3:sc=0
15 e=int(rnd(1)*20)+7703
20 printchr$(19);chr$(5);"score:";sc
25 pokeb,21:pokee,81
30 poke37154,127
35 j=(not((peek(37152)and128)/8+(peek(37137)and60)/4))+32
40 poke37154,255
45 ifj=0then80
50 pokeb,32
55 ifj=4thenb=b-1
60 ifj=16thenb=b+1
65 ifb=8120thenb=b+1
70 ifb=8141thenb=b-1
75 pokeb,21
80 pokee,32
85 e=e+22
90 pokee,81
95 ife=>8120ande=bthen110
100 ife=>8120ande<>bthen115
105 goto25
110 sc=sc+10:pokee,32:goto15
115 m=m-1:pokee,32
120 ifm=0then135
125 goto15
135 fort=1to5:printchr$(17):next
140 fort=1to6:printchr$(32);:next
145 printchr$(158);"game over"
150 print"{down*2}play again? y/n"
155 geta$:ifa$="y"thenrun
160 ifa$="n"thenend
165 goto155

And now, while I still wonder why so many VIC articles disagree on how to read the joystick, at least I can move left and right in my 1983 classic VIC-20 game Eggs…

Until next time…

VIC-NIC News located! My first published program!

Updates:

  • 2024-02-10 – Added screen shots, and pasted in the code.

On February 2, 2024, I received an e-mail with the subject: Eggs program

Could this be someone who had a copy of the VIC-NIC News newsletter where my “Eggs” VIC-20 program appeared? The e-mail read:

Hi Allen,

I saw on your website you were looking for a copy of your Eggs program listing that was in The Vic-Nic News magazine.

I went through the issues I have (#1 thru 7) and found the listing in #6. If you still need it, I can scan the page and email it to you or copy it and mail it.

Take care,

(name to be added, pending permission)

– e-mail received on 2/2/2024

I replied back:

“Proof that VIC-NIC NEWS actually existed! I would very much like a scan of that issue. Actually, since this is so difficult to find, would you be willing to scan them all so we could get them uploaded somewhere? Maybe archive.org?

But yes. Please yes. I would very much like that. Very much.”

– my e-mail reply

And today, I received a scan of my Eggs program! I had pretty much given up ever finding a copy.

Thank you thank you thank you!

I recognize my doodles, but had forgotten I sent drawings in. Actually, I believe I sent the program in typed up via a typewriter. The instructions and the “ASCII art” representation of the game screen were typed by me, and the doodles were added. Actually, I did have some kind of thermal printer for my VIC-20, so perhaps I included the program printed out that way (I see it has a few embedded screen control codes in a few PRINT statements). It is very exciting to see this again.

Very, very cool.

I typed it in to CBM prg Studio so I could play it:

1 print"{clear}{down*3}      eggs"
2 print"{down*3} by allen huffman"
3 print"{down*2}vic-nic news july 1983"
4 forj=1to5000:next
5 poke36879,8:printchr$(147)
10 b=8130:m=3:sc=0
15 e=int(rnd(1)*20)+7703
20 printchr$(19);chr$(5);"score:";sc
25 pokeb,21:pokee,81
30 poke37154,127
35 j=(not((peek(37151)and128)/8+(peek(37151)and60)/4))+32
40 poke37154,255
45 ifj=16then80
50 pokeb,32
55 ifj=18thenb=b-1
60 ifj=17thenb=b+1
65 ifb=8120thenb=b+1
70 ifb=8141thenb=b-1
75 pokeb,21
80 pokee,32
85 e=e+22
90 pokee,81
95 ife=>8120ande=bthen110
100 ife=>8120ande<>bthen115
105 goto25
110 sc=sc+10:pokee,32:goto15
115 m=m-1:pokee,32
120 ifm=0then135
125 goto15
135 fort=1to5:printchr$(17):next
140 fort=1to6:printchr$(32);:next
145 printchr$(158);"game over"
150 print"{down*2}play again? y/n"
155 geta$:ifa$="y"thenrun
160 ifa$="n"thenend
165 goto155

There may still be some typos, and I think there may be an issue with the PEEKs used to read the joystick. Currently, the Mac version of the VICE Emulator has a bug an joysticks don’t work (well, the fire button does, but nothing else). I will test it on my TheVIC20 machine soon.

And here it is in all its glory!

Title Screen – I think they made this title screen. I hope I would have centered things better, if I had done it.

Game Play – A “U” for the players “bucket” (B variable), and a ball for the falling “egg” (E variable):

Game Over – And the inevitable game over screen.

To be continued…

My old (and new) VIC-20 stuff is now on Github

Preservation…

https://github.com/allenhuffman/VIC-20

And so is my *ALL RAM* BBS for the CoCo:

https://github.com/allenhuffman/ALL-RAM-BBS

And various BASIC things from other blog posts:

https://github.com/allenhuffman/BASIC

And a Lites Out game from an upcoming blog series:

https://github.com/allenhuffman/Lites-Out

There is even a VIC-20 port of that one:

https://github.com/allenhuffman/VIC-20/tree/main/my%20new%20programs/lites%20out

VIC-20 manual type-in games

(Insert, yet again, my “the VIC-20 was my first computer” story here.)

When I got my VIC-20, that is all I had — just the VIC-20 computer. I did not have the Commodore Datasette (tape recorder). I could not save anything that I typed in. Because of this, I recall leaving my VIC turned on just so I wouldn’t lose the program I had typed in (or was in the process of typing in).

I am not 100% sure which manual came with my early model VIC, but it probably was the “Personal Computing on the VIC-20: a friendly computer guide.” At least, things inside this PDF look familiar.

In the back of the book is a section called “Programs to Try.” It contains listings of three games. In the PDF above, these games where called:

  • Tank Versus UFO by D. Later
  • Killer Comet by Duane Later
  • Rocket Command by Duane Later

But, in the book that came with my VIC-20, I believe at least two of them were called something else: Meteor and Rocket Fighter! I am pretty sure I remember Tank versus UFO being called that in my book.

I recall typing these programs in and fixing either bugs in the listing or, more likely, bugs in my typing ability. Much to my surprise, I found my original VIC-20 tapes several years ago and was able to get “most” of what I had on those tapes loaded in to an emulator. Two of the programs I found were ones I had typed in from the VIC-20 book.

When I went to look up these games, I found many videos on YouTube showing different versions than the ones I had. I originally figured some VIC owners just customized the games and they ended up in a collection somewhere on the Internet.

But now I think there might have been multiple versions of these games released by Commodore. The PDF of the book on archive.org says it is the 5th edition. I am now trying to find out how many editions of this book were published. I would like to see if they contain different versions of these programs.

Here are some differences I found between the ones I typed in from my book, and the ones shown in that 5th edition copy I found online.

Killer Comet (PDF) versus Meteor (mine)

The differences between the two versions are mostly cosmetic:

  • The name: “Meteor” in my book, and “Killer Comet” in the PDF.
  • The “graphics”: A block for the cannon and ball for the bullet in the PDF, versus a letter “A” for the cannon and vertical bar for the bullet in mine.
  • Game messages: “Delta base destroyed” in my book, versus “Moon base destroyed” in the PDF. Strangely enough, the “Killer Comet” prints “Meteor destroyed.” This further makes me think I had an earlier version and Meteor was the original name.
  • Stars on the screen (I may have added those) done through some extra POKEs neat the top of the program:
4 POKE7910,46:POKE8140,46:POKE8170,46:POKE8000,46:POKE7809,46:POKE7715,46:POKE7998,46
5 POKE7812,46:POKE7949,46:POKE8020,46:POKE7777,46:POKE7944,46:POKE8005,46:POKE7793,46
8 POKE8179,1

Thanks to a VIC-20 memory map at zimmers.net, I can see that all of these locations are in screen memory:

7680-8191     Screen memory

The 46 is a period. These POKEs are poking the “stars” in the background. As the meteor goes across the screen, it will erase those stars, so I am not sure if this was part of the original program, or something I had added. I know I had a game I was writing that did a similar thing with stars in the background, but mine got restored so they were not erased by other objects:

If I added those stars, perhaps I also changed the name? But if so, it wouldn’t explain why the Killer “Comet” version still calls it a meteor…

Rocket Command (PDF) versus Rocket Fighter (mine)

Again, these versions are very similar except for a few minor differences:

  • The name: “Rocket Fighter” in my book, versus “Rocket Command” in the PDF.
  • The “graphics”: Different ASCII (er, PETSCII) characters are used for the game playfield. The PDF uses a letter “X”, and mine used a PETSCII graphics character. For the missile, the original used a text up arrow, and mine uses a card clubs character.

Tank versus UFO

If I saved out Tank versus UFO, I couldn’t find it. Or, it might have been damaged on the ancient cassette tapes I found a few years ago and I couldn’t get it to load. I have no idea what differences there might be between the 5th edition version and whatever I typed in.

Why so different?

When I look up these games on YouTube, I see videos several other variations. I expect some where enhancements done by VIC-20 owners, but others look like just slightly updated versions. Did I do the same thing, and modify these programs to change the names?

Doing some web searching, I found this reference:

Modified versions of Tank-v-Ufo (p. 153-156) appear to have been published as Tank-v-Ufo (VIC Games), Tank Attack (Commodore Computing International, 82-11), Ufo-Jagd (Happy Computer, 83-12), Invasion (Commander, 84-02) and Save The City! (Big K, 84-04).

A slightly different version of Rocket Command (p. 158-159) was published in VIC! (Vol 6).

Modified versions of Rocket Command (p. 158-159) appear to have been published as UFO Target (Commodore Computing International, 83-08) and Rocket! (Big K, 84-04).

– http://www.vic20listings.freeolamail.com/book_userguide.html

And none of those match the names of the versions I have! It does “confirm” that Commodore published different versions of at least two of these – Tank Attack (Tank vs. UFO) and Rocket Command (UFO Target).

Tank vs UFO versions

Tank Attack (Commodore Computing International)

Yet the title screen still reads “Tank versus UFO”…

Invasion (Commander … magazine?)

Save the City (Big K)

Yet the title still reads “Tank versus UFO”…

Rocket Command versions

UFO Target (Commodore Computing International)

Rocket Command

I find this version interesting because it has the PETSCII “X” character used for the base, like my version, but still uses the up arrow character like the PDF version.

Rocket (Big K)

Yet the title still reads “Rocket Command”.

It is clear that games based on the type-in programs were certainly appearing in may publications… Did the version I have actually come from a magazine, rather than the VIC-20 manual? (I remember having Family Computing and Compute, which spun off in to Compute’s Gazette, during my VIC-20 days.)

Can anyone shed some light on this? How many editions to this manual were there, and did the program listings change? I did find a 1981 manual that does not say what edition it is, so it might be the first edition — but the program listings have the same names as the 5th edition.

I’d really like to know where I got “Meteor” and “Rocket Fighter” from.

To be continued…

Rocket Fighter program listing

!--------------------------------------------------
!- April 8, 2020 10:01:03 PM
!- Import of :
!- w:\vicconversions\vicrocket\rocket fighter.prg
!- Unexpanded VIC20 / C16 / Plus4
!--------------------------------------------------
2 REM ROCKET FIGHTER
10 VI=9*16^3:OF=38400-7680:PRINT"{clear}"
11 FORA=38400+22TO38400+22*23:POKEA,0:NEXT
15 C=7680+22*20+15
20 POKEVI+15,6+128+64+32+8
30 PRINT"{home}{red}*** rocket fighter ***";
35 PRINT"{space*5}hit any key"
40 PRINT"{down*14}{black}V{left}{down}V{left}{down}V{left}{down}V{left}{down}V{left}{down}V{left}{down}VVVVVVVVVVVVVVVV";
50 PRINT"{up}{left*14}XXXXXXXXXXXXXX"
60 A=7680+22*22+15
70 GETA$:IFA$<>""ANDB=0THENB=1:POKEC+22,32:D=C:C=C-1:K=1:POKE9*16^3+13,128+125:L=16
71 IFK=1THENL=L-1:POKE9*16^3+14,L
72 IFL=0THENK=0:POKE9*16^3+13,0
75 IFC=8121THENPRINT"{home}{down*6} no more rockets !!!":POKE9*16^3+14,0:FORAA=1TO3000:NEXT:RUN
80 IFB=0THEN110
85 POKED,32:D=D-22
90 IFPEEK(D)=60ORPEEK(D)=62THENGOSUB500:GOTO70
100 IFD<7680+88THENB=0:GOTO110
105 POKED,88
110 IFH=0THEN200
115 IFH=0THEN70
120 POKEF,32:F=F+E
125 IFF=ITHENH=0:GOTO70
130 IFPEEK(F)=30THENGOSUB500:GOTO70
140 POKEF,G:GOTO70
200 H=1
205 IFINT(RND(1)*2)=1THENE=-1:F=7702+(INT(RND(1)*10)+6)*22:I=F-22:G=60:GOTO115
210 E=1:F=7680+(INT(RND(1)*10)+6)*22:I=F+22:G=62:GOTO115
500 B=0:H=0
501 SC=SC+10:PRINT"{home}{down*3}{purple}score="SC
502 POKEF+OF,4:POKEF+1+OF,4:POKEF-1+OF,4
503 POKEF+OF+22,4:POKEF-22+OF,4
510 POKEF,102:POKEF+1,42:POKEF-1,42:POKEF+22,42:POKEF-22,42
521 POKE9*16^3+13,128+35
522 FORY=16TO0STEP-1
523 POKE9*16^3+14,Y
524 FORP=1TO10:NEXT:NEXT
530 POKEF,32:POKEF+1,32:POKEF-1,32:POKEF+22,32:POKEF-22,32
531 POKEF+OF,0:POKEF+1+OF,0:POKEF-1+OF,0
532 POKEF+OF+22,0:POKEF-22+OF,0
533 POKE9*16^3+13,0
540 FORGH=FTOF+22*16STEP22
544 II=PEEK(GH):POKEGH,G:FOROO=1TO50:NEXT
546 POKEGH,II:NEXT
800 RETURN
999 GOTO70
1000 POKE9*16^3+13,128+125
1001 FORY=16TO0STEP-1
1005 POKE9*16^3+14,Y
1010 NEXT:POKE9*16^3+13,0
1020 RETURN

Meteor program listing

!--------------------------------------------------
!- April 8, 2020 10:00:20 PM
!- Import of :
!- w:\vicconversions\vicrocket\meteor.prg
!- Unexpanded VIC20 / C16 / Plus4
!--------------------------------------------------
1 C=7680+22*6:DIMB(12):LL=C:POKE9*16^3+15,8
2 PRINT"{yellow}{clear}******* meteor *******":T=0
3 PRINT"{space*5}hit any key"
4 POKE7910,46:POKE8140,46:POKE8170,46:POKE8000,46:POKE7809,46:POKE7715,46:POKE7998,46
5 POKE7812,46:POKE7949,46:POKE8020,46:POKE7777,46:POKE7944,46:POKE8005,46:POKE7793,46
8 POKE8179,1
9 FORA=38444TO38400+505:POKEA,1:NEXT
10 :
20 FORA=1TO12:B(A)=160:NEXT
21 IFW=0THEN25
22 POKE9*16^3+14,U:U=U-2:IFU<=0THENW=0:POKE9*16^3+13,0
25 F=1
26 FORE=0TO44STEP22
27 FORD=C+ETOC+3+E:POKED,32:F=F+1:NEXT:NEXT
28 C=C+1
29 F=1
30 POKE8179,1:FORE=0TO44STEP22
35 FORD=C+ETOC+3+E:POKED,B(F):F=F+1:NEXT:NEXT
36 IFPEEK(8178)=1THENPRINT"{clear}{down*5}delta base destroyed!":GOTO500
40 GETA$:IFA$<>""ANDG=0THENG=1:S=7680+15+22*21
50 IFG=0THEN80
55 POKES,32:S=S-22
60 IFS<7746THENG=0:GOTO21
70 IFPEEK(S)=160THENPOKES,32:G=0:T=T+1:W=1:POKE9*16^3+13,128+000:U=15:GOTO80
71 IFPEEK(S-1)=160THENG=0:POKES-1,32:T=T+1:W=1:POKE9*16^3+13,128+000:U=15:GOTO80
75 POKES,93
80 F=1
81 IFT=12THENPRINT"{clear}{down*5}***meteor destroyed***":FORR=1TO2500:NEXT:LL=LL+44:C=LL:GOTO2
82 FORE=0TO44STEP22
84 FORD=C+ETOC+3+E:IFPEEK(D)=32THENB(F)=32
86 F=F+1:NEXT:NEXT
90 GOTO21
500 POKE9*16^3+13,128+5
505 POKE9*16^3+14,5:FORR=1TO300:NEXT
510 FORA=15TO0STEP-1
511 POKE9*16^3+14,A
520 FORRR=1TO500:NEXT
530 NEXT
540 FORRR=1TO2000:NEXT:RUN

VIC-20 “smooth move” revisited.

This is a quick follow-up to a post I did back in 2020. I had written this at the time, but never completed my experiments to post the results. Here is a video demo of using eight sets of two programmable characters to represent the 8×8 object at each position. This allows smooth horizontal positioning.

5 GOSUB 500:rem poke 36869,255
10 print"{clear}{reverse on}generating frames:"
20 for c=0 to 7:print "{reverse on}";chr$(65+c);chr$(73+c);" -> {reverse off}";chr$(65+c);chr$(73+c):print:next
25 get a$:if a$="" then 25
28 poke 36869,255
30 rem char row
40 for r=0 to 7
50 read v:v1=v
60 l1 = 7168+8+r
70 l2 = 7168+8+(8*8)+r
80 rem character
90 for c=0 to 7
100 poke l1+(c*8),v1
110 v1=v1/2
120 v2=(v and bt(c)-1) * bt(8-c)
130 poke l2+(c*8),v2
140 next
150 next
200 rem smooth move
210 print "{reverse on}move: a/s quit: q"
220 c=0:f=0
230 print chr$(65+f);chr$(73+f);"{left*2}";
240 k=peek(197):if k=64 then 240
250 if k=48 then 380
260 if k=17 then 300
270 if k=41 then 340
280 goto 240
290 rem left
300 if f>0 then f=f-1:goto 230
310 if c>0 then c=c-1:f=7:print" {left*3}";
320 goto 230
330 rem right
340 if f<7 then f=f+1:goto 230
350 if c<20 then c=c+1:f=0:print" ";
360 goto 230
370 rem quit
380 poke 36869,240:poke 198,0
390 end
500 rem initialize
510 for z=0 to 7:bt(z)=2^z:next
520 for z=7168+8 to 7168+8+16*8:poke z,0:next
525 for z=7126+(32*8) to 7168+(32*8)+8:poke z,0:next
530 return
600 rem print bits
610 for bt=0 to 7
620 if v and bt(bt) then print"1";: goto 640
630 print "0";
640 next:return
5000 rem 8x8 object
5010 rem data 60,126,255,255,255,255,126,60
5020 DATA 24,60,126,60,255,126,255,255

Commodore VIC-20 PETSCII on the CoCo

In case you ever wondered what the VIC-20 character set would like like on a CoCo 1…

VIC-20 PETSCII (Uppercase 0-511) on a CoCo
VIC-20 PETSCII (Lowercase 0-511) on a CoCo

It would look like that.

And if you wanted to know what the VIC-20’s 22×23 screen would look like on a CoCo…

VIC-20 20×32 screen displaying PETSCII on a CoCo

That. It would look like that.

When I moved from the VIC-20 to the CoCo, I lost colors and sound, but gained a “huge” screen that was 32 columns wide instead of 22. But I lost horizontal lines (23 down to 16). It felt more usable (wider screen) but smaller.

It wasn’t until I started revisiting the VIC-20 this past year that I realized since each screen block was eight bytes tall, the VIC’s native “resolution” for that 22×23 screen would be 176×184 (22*8 by 23*8). The CoCo’s 256×192 was larger and could fit the VIC-20 screen with room to space (but without the colors).

When I tried to do a quick port of my VIC Sky-Ape-Er game, the different text resolution (22×23 versus 32×16) made all my levels need to be redesigned. It would not be the same game — but the same game engine with different sized levels that resembled the original.

It might be fun to come up with an assembly routine to handle VIC-20 custom characters on a 256×192 graphics screen. It would likely be slower (blitting out 8 bytes instead of printing one byte) than text mode, but I could then port my games over (minus color and sound) much more accurately.

Maybe some day…

Revisiting 10 PRINT RACER

Awhile back I ported 8-Bit Show and Tell‘s “10 PRINT RACER” from Commodore PET to CoCo. I tried to make it a literal port, keeping the code as close as I could to the original. I did, however, mention a few things that could make it faster, taking advantage of things like Extended Color BASIC’s hex values (&H2 is faster to parse than 2, for instance).

The other day, MiaM left a comment on the original article:

It might be faster to use A=ASC(INKEY$) and IF A=4 instead of IF A$=CHR$(4)

– MiaM

Intriguing. The original Commodore version, the direction was read by using GET A$, and I simply converted that over to A$=INKEY$ for Color BASIC. Here is a look at Robin’s Commodore PET original:

1 REM 10 PRINT RACER: 8-BIT SHOW & TELL
5 R$="":PRINT"{CLR}INIT:";:FORX=1TO75:M$=CHR$(205.5+RND(.)):R$=R$+M$:PRINTM$;:NEXT
10 PRINT"{CLR}":C=20:R=13:W=15:D=0:S=32768
20 L=0:FORZ=0TO1STEP0:X=RND(.)*10
30 IFX<4THENR=R-1:IFR<1THENR=1
40 IFX>6THENR=R+1:IFR+W>37THENR=37-W
50 RN=RND(.)*35+1:PRINTMID$(R$,RN,R);SPC(W);MID$(R$,RN,39-R-W)
60 D=D+1:L=L+1:IFL>49THENL=0:W=W-1:IFW<3THENW=3
70 IFD<25THENNEXT
75 GETA$:IFA$="4"THENC=C-1
80 IFA$="6"THENC=C+1
90 P=PEEK(S+C):IFP<>32THEN200
100 POKES+C,42:NEXT
200 PRINTSPC(17)"CRASH!":IFD>HTHENH=D
205 PRINT,"SCORE:"D"  HIGH:"H
210 FORX=1TO2000:NEXT:POKE158,0
220 GETA$:IFA$=""THEN220
230 GOTO10

And here is my Color BASIC conversion:

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

The block of code MiaM refers to is this:

75 GETA$:IFA$="4"THENC=C-1
80 IFA$="6"THENC=C+1

75 A$=INKEY$:IFA$=CHR$(8)THENC=C-1
80 IFA$=CHR$(9)THENC=C+1

On the Commodore PET, without arrow keys, it used “4” and “6” on the numeric keypad for Left and Right. On the CoCo, I changed that to the Left Arrow key and the Right Arrow key.

The Commodore PET has much less work to do looking for A$=”4″ versus A$=CHR$(8) not he CoCo (due to all the parsing). I could have made the CoCo use letter keys like “A” for left and “S” for right to get similar performance.

But what MiaM suggests may be faster. Instead of comparing strings like A$=CHR$(8), the suggestion is to use BASIC’s ASC() keyword to return the numeric value of the character, then compare a numeric value rather than a string compare.

Which is faster? A one character string compare, or ASC() and a number compare?

Let’s find out.

Comparing a String to a String

For this, I dug out my old BENCH.BAS benchmarking code and inserted the first method I wanted to test — the way the Commodore PET did it:

5 DIM TE,TM,B,A,TT
10 FORA=0TO3:TIMER=0:TM=TIMER
20 FORB=0TO1000
30 A$=INKEY$:IF A$="4" THEN REM

70 NEXT
80 TE=TIMER-TM:PRINTA,TE
90 TT=TT+TE:NEXT:PRINTTT/A:END

Comparing A$ to a quoted value in this loop produces 515.

Comparing a String to a CHR$

My conversion changed this to comparing to a CHR$(8) value, like this:

0 REM ascvsstringcompare.BAS
5 DIM TE,TM,B,A,TT
10 FORA=0TO3:TIMER=0:TM=TIMER
20 FORB=0TO1000
30 A$=INKEY$:IF A$="4" THEN REM
30 A$=INKEY$:IF A$=CHR$(8) THEN REM

70 NEXT
80 TE=TIMER-TM:PRINTA,TE
90 TT=TT+TE:NEXT:PRINTTT/A:END

This produces a slower 628. No surprise, due to having to parse CHR$() and the number. I could easily speed up the CoCo port by using quoted characters like “A” for Left and “S” for Right.

But I really wanted to use the arrow keys.

ASC and you shall receive…

The new suggestion is to use ASC. ASC will convert a character to its ASCII value (or PETASCII on a Commodore, I would suppose). For example:

PRINT ASC("A")
65

The cool suggestion was to try using INKEY$ as the parameter inside of ASC(), and skipping the use of a variable entirely. Unfortunately, when I tried it, I received:

?FC ERROR

Function Call error. Because, if no key is pressed, INKEY$ returns nothing, which I suppose would be like trying to do:

PRINT ASC("")

We have been able to use INKEY$ directly in other functions, such as INSTR (looking up a character inside a string), and that works even when passing in “”:

PRINT INSTR("","ABCDE")
0

But ASC() won’t work without a character, at least not in Color BASIC. And, even if we used A$=INKEY$, we can’t pass A$ in to ASC() if it is empty (no key pressed) which means we’d need an extra check like:

30 A$=INKEY$:IF A$<>"" THEN IF ASC(A$)=4 THEN ..

The more parsing, the slower. This produced 539, which isn’t as slow as I expected. It’s slower than doing IF A$=”4″ but faster than IF A$=CHR$(8). Thus, it would be faster in my CoCo port than my original.

This did give me another thing to try. ASC() allows you to pass in a string that contains more than one character, but it only acts upon the first letter. You can do this:

PRINT ASC("ALLEN TRIED THIS")
65

This means I could always pad the return of INKEY$ with another character so it would either be whatever keys he user pressed, or my other character if nothing was pressed. Like this:

30 IF ASC(INKEY$+".")=8 THEN REM

If no key has been pressed, this would try to parse “”+”.”, and give me the ASCII of “.”.

If a key had been pressed, this would parse that character (like “4.” if I pressed a 4).

As I learned when I first stated my benchmarking BASIC series, string manipulation is slow. Very slow. So I expect this to be very slow.

To my surprise, it returns 520! Just a smidge slower than the original IF A$=”4″ string compare! I’m actually quite surprised.

Now, in the actual 10 PRINT RACER game, which is doing lots of string manipulations to generate the game maze, this could end up being much slower if it had to move around other larger strings. But, still worth a shot.

Thank you, MiaM! Neat idea, even if Color BASIC wouldn’t let me do it the cool way you suggested.

Until next time…

Bonus

Numbers verses string compares:

30 IF Z=4 THEN REM

That gives me 350. Even though decimal values are much slower to parse than HEX values, they are still faster than strings.

But, in pure Color BASIC, there is no way to get input from a keypress to a number other than ASC. BUT, you could PEEK some BASIC RAM value that is the key being held down, and do it that way (which is something I have discussed earlier).

Any more ideas?