Apparently, if you use a composite monitor or TV set on a CoCo 3, you can just put bytes on the 640x192x4 color video mode and they create artifact color. You can get over 200 artifact colors that way with no special tricks other than a palette translation to know what byte value is what color.
Tequila and Tortilla and Tandy
Three things that I imagine intersected, if for no other reason than Tandy being located in Texas…
But what does the CoCo 3 have to do with this?
Stay tuned… (Or go look at Roger Taylor’s project…)
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…


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…

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…
There is no substitute for real hardware.
I make use of emulation regularly. While I do still have my original Radio Shack Color Computers from the 1980s, it is usually more convenient to just load up an emulator. For short experiments in BASIC, or casual game playing, this works just fine. However, emulation is not perfect and sometimes you run in to something that stands out.
Consider this…

…and this…

These purple colors were generated on the XRoar 1.0 emulator when emulating a later-model Color Computer 2 with an updated T1 version of the 6874 VGD video chip.
I had never seen such colors, but since I had never had a T1 CoCo I assumed it was just another odd secret that chip held I was just unfamiliar with.
The first sign that this might be an emulation issue was that the purple only showed up when the emulator was using simulated RF output. In that mode, it tries to replicate the fuzzy appearance of TV output. turn that simulation off and the screen changed to expected orangish reddish alternate color.
While I do not know the details on what caused this, XRoar has been updated to no longer produce these purple colors in this mode.
You can pick up the latest XRoar emulator (that adds support for the Color Computer 3 and MC-10) here:
String space required. No exceptions.
Revisiting my Color BASIC String Theory series… Here is one to ponder…
CLEAR 0 can be used to reserve 0 bytes for string storage. With no string space, we obviously expect something like this to NOT work:
A$="THIS WON'T WORK WITH CLEAR 0"
Indeed, that would give us “?OS ERROR” — Out of string space.
The exception to this rule are “constant strings” that are embedded inside the BASIC program itself. In a YouTube video I recently posted, I demonstrated how constant strings in a program do not use string space:
You can see twenty nine other short Color BASIC videos I posted to YouTube during the month of #SepTandy 2021.
But I digress…
Here are some other things that won’t work without string space, even if, at first glance, it seems like they would:

It seems you can’t SAVE, LOAD or even PRINT a “constant” string if there is no string space.
But why?
Consider this… The same thing happens with string functions such as LEFT$, RIGHT$, MID$ and even INSTR:

Looking at those, and recalling my String Theory article, we know LEFT$, RIGHT$ and MID$ are trying to create a new string. With no string space, there is no way to create it. That must be why they fail. This makes sense.
But INSTR does not create any strings. It merely returns the position where one string appears inside of another, or 0 if the string is not found. (Or 1 if you give it an empty string, which truly does seem like a bug but other flavors Microsoft BASIC behave the same way with their implementations of INSTR. But I digress…)
And SAVE, LOAD and PRINT are similar. They just print something, not create a string.
That does not make sense.
Let’s speculate a bit.
What’s all this, then?
Without consulting the Color BASIC Unravelled disassembly, my guess is that the ROM code for SAVE, LOAD, PRINT, etc. probably expects some register to be pointing to where the string exists in memory (a location pointer in the variable data). This might be code space, in the case of a constant string embedded in a BASIC line, or string space, in the case of a dynamic string.
But when you are entering a command directly in to BASIC, there is no program memory for that command (even though it seems like it could just point to the keyboard input buffer and then make the ROM call). BASIC needs to put that constant string data somewhere before jumping to the ROM call.
That’s weird, and quite possibly unnecessary, but would, at least, make sense.
I am going to add this to my “look this up in the disassembly to see what’s going on” list for future investigation.
In the meantime … I wonder what else won’t work without string space?
Until next time…
The undocumented syntax of Extended Color BASIC
The other night I was experimenting with Extended Color BASIC and the “GET” and “PUT” commands. I knew that the documentation was incorrect about them, and was trying to figure out how they worked. I also wanted to do this without cheating (i.e., doing a quick web search and finding the results of someone who already did this).
I will share the results of this experimentation later, but I wanted to pass along something I was unaware of until last night. I ended up looking at the Extended Color BASIC disassembly to try to find clarification on why something I was seeing was happening. Reading through it revealed a syntax I was unaware of for the following commands:
- CIRCLE
- GET
- LINE
- PAINT
- PUT
Much like the CoCo BASIC “PRINT@” command, the ‘@’ sign is allowed on these commands as well. It does nothing, and is merely skipped:

A note in the Unraveled book says:
It is interesting to note that the “@” symbol does not do anything! It is there to make the command syntax consistent with the “PRINT @” concept and to make it compatible with other versions of Microsoft BASIC.
– Extended Color BASIC Unraveled II
Since this was not documented in the manual (as far as I know), I was not aware of this syntax.
Did you know about this?
There are certainly many undocumented secrets in the Color BASIC ROMs, from the unimplemented Easter egg to things like how the PLAY command plays nonexistent notes. Certainly the author of the Unraveled series discovered these items, and anyone who read those books would have known about it, but I wonder how widespread these oddities were back in the 1980s.
Until next time…
6809 assembly request: make this more better?
Updates:
- 2021-9-17 – Added revisions suggested by William “Lost Wizard” Astle.
Hello, folks who actually know how to program 6809 assembly.
Can you make this more better?

The idea is to look at each byte on the 32-column VDG screen (from 1024 to 1535) and if the high bit is set (>128, thus a semigraphics block character), add 16 to it. That moves it to the next color. If it rolls over, adjust it back to the proper range.
i.e., if the block is 250, and it adds 16, you end up with 10. Setting the high bit again bumps it back to the 128-255 range. Initially, I did this using a compare to #128, then using ADDA of #128. Then I looked up the BIT test. Rather than compare to decide if I need to do something, I just do the OR to set that high bit back. Seems to work. Maybe faster than checking each byte?
Does this make sense?
Please and thank you.
William Astle Updates
William Astle immediately left these comments:
I’d use “BPL” instead of “BITA/BEQ”. (Bit 7 is the sign bit and LD and ST set flags.) Also, I’d do “LDA ,X+” and then if updating the screen, do “STA -1,X”. That removes the need for the “LEAX”.
William Astle
BPL is “Branch if PLus”. When a register value is used to represent values that can be negative (-127 to 128 versus 0 to 255), the high bit is used to indicate negative. I expect BPL is basically “branch if the high bit is not set.”
When I “LDA ,X”, I am loading register A with whatever is pointed to by X. Adding the plus “LDA ,X” will load A then increment X. Since STA allows an offset, so you can do things like “STA 5,X” to start the value in register A 5 locations past wherever X points. Doing a -1 stores it one byte earlier. That eliminates me needing to use “LEAX” to add one to X.
Here is the update:

References
References I used:
Color BASIC Attract Screen – part 4
See also: part 1, part 2, part 3, part 4, unrelated, part 5 and part 6.
Beyond removing some spaces and a REM statement, here is the smallest I have been able to get my “attract” program:
10 ' ATTRACT4.BAS
20 FOR I=0 TO 3:READ L(I),LD(I),CL(I),CD(I):NEXT:Z=143:CLS 0:PRINT @268,"ATTRACT!";
30 Z=Z+16:IF Z>255 THEN Z=143
40 FOR I=0 TO 3:POKE L(I),Z:L(I)=L(I)+LD(I):FOR C=0 TO 3:IF L(I)=CL(C) THEN LD(I)=CD(C)
50 NEXT:NEXT:GOTO 30
60 DATA 1024,1,1024,1,1047,1,1055,32,1535,-1,1535,-1,1512,-1,1504,-32
(We could reduce it by one line by sticking the DATA statement on the end of line 50, now that I look at it.)
Let’s rewind and look at the original, which used individual variables for each of the moving color blocks:
10 ' ATTRACT.BAS
20 A=1024:B=A+23:C=1535:D=C-23:Z=143
30 AD=1:BD=1:CD=-1:DD=-1
40 CLS 0:PRINT @268,"ATTRACT!";
50 POKE A,Z:POKE B,Z:POKE C,Z:POKE D,Z
60 Z=Z+16:IF Z>255 THEN Z=143
70 A=A+AD
80 IF A=1055 THEN AD=32
90 IF A=1535 THEN AD=-1
100 IF A=1504 THEN AD=-32
110 IF A=1024 THEN AD=1
120 '
130 B=B+BD
140 IF B=1055 THEN BD=32
150 IF B=1535 THEN BD=-1
160 IF B=1504 THEN BD=-32
170 IF B=1024 THEN BD=1
180 '
190 C=C+CD
200 IF C=1055 THEN CD=32
210 IF C=1535 THEN CD=-1
220 IF C=1504 THEN CD=-32
230 IF C=1024 THEN CD=1
240 '
250 D=D+DD
260 IF D=1055 THEN DD=32
270 IF D=1535 THEN DD=-1
280 IF D=1504 THEN DD=-32
290 IF D=1024 THEN DD=1
300 GOTO 50
This was then converted to us an array:
10 ' ATTRACT2.BAS
20 L(0)=1024:L(1)=1024+23:L(2)=1535:L(3)=1535-23
30 Z=143
40 CL(0)=1024:CD(0)=1
50 CL(1)=1055:CD(1)=32
60 CL(2)=1535:CD(2)=-1
70 CL(3)=1504:CD(3)=-32
80 CLS 0:PRINT @268,"ATTRACT!";
90 LD(0)=1:LD(1)=1:LD(2)=-1:LD(3)=-1
100 FOR I=0 TO 3:POKE L(I),Z:NEXT
110 Z=Z+16:IF Z>255 THEN Z=143
120 FOR I=0 TO 3:L(I)=L(I)+LD(I):NEXT
130 FOR L=0 TO 3
140 FOR C=0 TO 3
150 IF L(L)=CL(C) THEN LD(L)=CD(C)
160 NEXT
170 NEXT
180 GOTO 100
And then it was converted to use READ/DATA instead of hard-coding values:
10 ' ATTRACT3.BAS
20 FOR I=0 TO 3
30 READ L(I),LD(I),CL(I),CD(I)
40 NEXT
50 Z=143
60 CLS 0:PRINT @268,"ATTRACT!";
70 Z=Z+16:IF Z>255 THEN Z=143
80 FOR I=0 TO 3
90 POKE L(I),Z
100 L(I)=L(I)+LD(I)
110 FOR C=0 TO 3
120 IF L(I)=CL(C) THEN LD(I)=CD(C)
130 NEXT
140 NEXT
150 GOTO 70
160 ' L,LD,CL,CD
170 DATA 1024,1,1024,1
180 DATA 1047,1,1055,32
190 DATA 1535,-1,1535,-1
200 DATA 1512,-1,1504,-32
Shuffling code around is fun.
But it’s still really slow.
10 PRINT “FASTER”
There are other ways to do similar effects, such as with strings. We could make a string that contained a repeating series of the color block characters, like this:
FOR I=0 TO 7:B$=B$+CHR$(143+16*I):NEXT
Then we could duplicate that 8-character string a few times until we had a string that was twice the length of the 32 column screen:
B$=B$+B$+B$+B$+B$+B$+B$+B$
Then we could make the entire thing move by printing the MID$ of it, like this:
FOR I=1 TO 32 PRINT@0,MID$(B$,33-I,32); PRINT@480,MID$(B$,I,31); NEXT
We print one section @0 for the top line, and the other @480 for the bottom line. Unfortunately, using PRINT instead of POKE means if we ever print on the bottom right location, the screen would scroll, so the bottom right block has to be left un-printed (thus, printing 31 characters for the bottom line instead of the full 32). This bothers me so apparently I do have O.C.D. Maybe we can fix that later.
But, it gives the advantage of scrolling ALL the blocks, and is super fast. Check it out:
10 ' ATTRACT5.BAS
20 CLS 0:PRINT @268,"ATTRACT!";
30 FOR I=0 TO 7:B$=B$+CHR$(143+16*I):NEXT
40 B$=B$+B$+B$+B$+B$+B$+B$+B$
50 FOR I=1 TO 32
60 PRINT@0,MID$(B$,33-I,32);
70 PRINT@480,MID$(B$,I,31);
80 NEXT:GOTO 50
That’s not bad, but only gives the top and bottom rows (minus that bottom right location). But, it’s fast!

Since the orders of the colors is the same on the top and bottom, we’d really need to reverse the bottom characters to make it look like it’s rotating versus just reversing. Let’s tweak that:
10 ' ATTRACT6.BAS
20 CLS 0:PRINT @268,"ATTRACT!";
30 FOR I=0 TO 7:B$=B$+CHR$(143+16*I)
35 R$=R$+CHR$(255-16*I):NEXT
40 B$=B$+B$+B$+B$+B$+B$+B$+B$
45 R$=R$+R$+R$+R$+R$+R$+R$+R$
50 FOR I=1 TO 32
60 PRINT@0,MID$(B$,33-I,32);
70 PRINT@480,MID$(R$,I,31);
80 NEXT:GOTO 50
That’s a bit better. But getting the sides to work is a bit more work and it will slow things down quite a bit. But let’s try anyway.
Initially, I tried scanning down the sides of the string using MID$, like this:
FOR J=1 TO 14 PRINT@480-32*J,MID$(R$,39-J+I,1); PRINT@31+32*J,MID$(R$,33-J+I,1); NEXT
But that was very, very slow. You could see it “paint” the sides. Each time you use MID$, a new string is created (with data copied from the first string). That’s a bunch of memory shuffling just for one character.
Then I thought, since I can’t get the speed up from a horizontal string being PRINTed, it was probably faster to just use CHR$().
I tried that, and it was still too slow.
Benchmark Digression: POKE vs PRINT
This led me back to an earlier benchmark discussion… Since I cannot get any benefit of using PRINT for a vertical column of characters, I could switch to the faster POKE method. This would also allow me to fill that bottom right character block. My O.C.D. approves.
To prove this to myself, again, I did two quick benchmarks — one using PRINT@ and the other using POKE.
0 ' LRBENCH1.BAS
1 ' 4745
10 C=143+16
20 TIMER=0:FOR A=1 TO 1000
30 FOR P=1024 TO 1535 STEP 32
40 POKEP,C
50 NEXT
60 NEXT:PRINT TIMER
0 ' LRBENCH2.BAS
1 ' 6013
10 C=143+16
20 TIMER=0:FOR A=1 TO 1000
30 FOR P=0 TO 511 STEP 32
40 PRINT@P,CHR$(C);
50 NEXT
60 NEXT:PRINT TIMER
Line 1 has the time that it printed for me in the Xroar emulator.
POKE will be the way.
However, there is still a problem: Math.
It just doesn’t add up…
The CoCo screen is 32×16. There are 8 colors. That means those 8 colors can repeat four times along the top of the screen, and four times along the bottom, leaving only 14 on each side going vertical. 32+32+14+14 is 92, which is not evenly divisible by our 8 colors. If we represent them as numbers, they would look like this:

If you start at the top left corner and go across, repeating 12345678 over and over, you end up back at the top left on 4. We have three colors that won’t fit. This means even if I had a nice fast routine for rotating the colors, they would not be evenly balanced using this format.
However…

…if I leave out the four corners, we get 88, and that divides just fine by our 8 colors!
Thus, the actual O.C.D.-compliant border I want to go for would look like this:

The only problem is … how can this be done fast in BASIC?
To be continued…
Bonus: Show Your Work
Here are the stupid BASIC programs I wrote to make the previous four screens:
0 ' border1.bas
10 CLS:C=113:L=1024
20 ' RIGHT
30 L=1024:D=1:T=31:GOSUB 110
40 ' DOWN
50 L=1087:D=32:T=13:GOSUB 110
60 ' LEFT
70 L=1535:D=-1:T=31:GOSUB 110
80 ' UP
90 L=1472:D=-32:T=13:GOSUB 110
100 GOTO 100
110 ' L=LOC, D=DELTA, T=TIMES
120 POKE L,C
130 C=C+1:IF C>120 THEN C=113
140 IF T=0 THEN RETURN
150 L=L+D:IF L>1023 THEN IF L<1536 THEN 170
160 L=L-D:SOUND 200,1
170 T=T-1:GOTO 120
0 ' border2.bas
10 CLS:C=113:L=1024
20 ' RIGHT
30 L=1025:D=1:T=29:GOSUB 110
40 ' DOWN
50 L=1087:D=32:T=13:GOSUB 110
60 ' LEFT
70 L=1534:D=-1:T=29:GOSUB 110
80 ' UP
90 L=1472:D=-32:T=13:GOSUB 110
100 GOTO 100
110 ' L=LOC, D=DELTA, T=TIMES
120 POKE L,C
130 C=C+1:IF C>120 THEN C=113
140 IF T=0 THEN RETURN
150 L=L+D:IF L>1023 THEN IF L<1536 THEN 170
160 L=L-D:SOUND 200,1
170 T=T-1:GOTO 120
0 ' border3.bas
10 CLS 0:C=143:L=1024
20 ' RIGHT
30 L=1025:D=1:T=29:GOSUB 110
40 ' DOWN
50 L=1087:D=32:T=13:GOSUB 110
60 ' LEFT
70 L=1534:D=-1:T=29:GOSUB 110
80 ' UP
90 L=1472:D=-32:T=13:GOSUB 110
100 GOTO 100
110 ' L=LOC, D=DELTA, T=TIMES
120 POKE L,C
130 C=C+16:IF C>255 THEN C=143
140 IF T=0 THEN RETURN
150 L=L+D:IF L>1023 THEN IF L<1536 THEN 170
160 L=L-D:SOUND 200,1
170 T=T-1:GOTO 120
Color BASIC Attract Screen – part 3
See also: part 1, part 2, part 3, part 4, unrelated, part 5 and part 6.
Previously, I took a target from the attract screen code to talk more on using arrays in BASIC than individual variables. I gave an example of moving ghosts around a screen, and then did modifications to use an array. This let the user select how many ghost they wanted to see randomly display on the screen.
I mentioned that arrays were slower, but allowed flexibility. With that in mind, here is that “wandering ghosts” example turned in to a simple game demo. The player will appear as a yellow block in the top left corner of the screen. The ghosts will randomly appear around the screen as white blocks. The goal is to navigate to the bottom right corner of the screen without hitting a ghost, or being hit by one.
To hopefully make this compatible with the MC-10 computer, it uses the keyboard letters “WASD” — A for left, D for right, W for up and S for down.
You can choose one ghost, and get a single fast moving ghost to avoid. Or you can choose 100 ghosts, and get 100 slow moving ghosts to avoid, making it more like navigating a random maze that slowly moves walls.
Ghost Run in Color BASIC
10 ' ghostrun.bas
15 INPUT "NUMBER OF GHOSTS";G:G=G-1:IF G<0 THEN 15
20 CLS0:DIM G(G):DIM C(G):C=207:B=128:FOR I=0 TO G
30 G(I)=1023+RND(512)
41 NEXT
45 D(0)=1:D(1)=-1:D(2)=-32:D(3)=32
46 PL=1056:PC=159:POKE PL,PC
50 ' DISPLAY GHOSTS
60 FOR I=0 TO G:POKE G(I),C
65 D=INSTR(" DAWS",INKEY$):IF D>1 THEN GOSUB 190
70 ' RANDOM MOVE G(I)
80 NL=G(I)+D(RND(4)-1)
130 IF NL<1024 THEN 170
140 IF NL>1535 THEN 170
150 ' ERASE G(I) AND UPDATE LOCATION
160 POKE G(I),B:POKE NL,C:G(I)=NL
165 IF NL=PL THEN 480
170 NEXT:GOTO 60
180 ' PLAYER MOVED D
190 NL=PL+D(D-2)
200 IF NL<1024 THEN RETURN
210 IF NL>1535 THEN RETURN
220 IF NL=1535 THEN 510
230 IF PEEK(NL)=C THEN 530
240 POKE PL,B:POKE NL,PC:PL=NL
250 RETURN
470 GOTO 60
480 ' GHOST GOT PLAYER
490 PRINT "WE GOT YA!"
500 END
510 PRINT "YOU MADE IT!"
520 END
530 PRINT "YOU HIT A GHOST!"
540 END
To reduce instant death, I made the ghosts spawn no higher than one line below the player. But, with a small amount of faster ghosts, something could spawn then randomly move towards the player quickly. It’s surprisingly challenging (or frustrating).
To make the game responsive to the player, as the code it updating the position of the ghost, the player can move. For example, if drawing 100 ghosts, the player can move as each ghost being drawn. I found this much more fun than doing a turn-by-turn game like the old 1976 CHASE game (also known as Robots for Unix, Daleks for Mac, and a zillion spinoffs in the 70s and 80s). Check out the first published listing Creative Computing 1976 or the wikipedia entry for more details.
But I, as I say, digress.
Maybe we can revisit this in future installments of this series.
Until then, here is another size optimization of the attract screen code, this time removing all the hard-coded array initializations and turning them in to DATA statements loaded by the READ command:
10 ' ATTRACT3.BAS
20 FOR I=0 TO 3
30 READ L(I),LD(I),CL(I),CD(I)
40 NEXT
50 Z=143
60 CLS 0:PRINT @268,"ATTRACT!";
70 Z=Z+16:IF Z>255 THEN Z=143
80 FOR I=0 TO 3
90 POKE L(I),Z
100 L(I)=L(I)+LD(I)
110 FOR C=0 TO 3
120 IF L(I)=CL(C) THEN LD(I)=CD(C)
130 NEXT
140 NEXT
150 GOTO 70
160 ' L,LD,CL,CD
170 DATA 1024,1,1024,1
180 DATA 1047,1,1055,32
190 DATA 1535,-1,1535,-1
200 DATA 1512,-1,1504,-32
We have no changed the original 30 line version in to a 20 line version… but that is actually two lines longer than the previous one due to adding some extra lines for DATA and READ. But, if we were dealing with 50 objects instead of just 4, we’d likely be quite ahead at this point.
Next time, we’ll try to reduce this even further by packing lines together.
To be continued…
Color BASIC Attract Screen – part 2
See also: part 1, part 2, part 3, part 4, unrelated, part 5 and part 6.
In part 1, I showed a simple but slow way to recreate a classic CoCo game startup screen with color blocks moving around the screen. I recall many early CoCo games had startup screens similar to this, though fancier. The assembly language games would rotate all the blocks around the screen, rather than just moving four blocks like my BASIC demo does. For instance, Steve Bjork‘s port of Clowns and Balloons:

You can check it out in videos on YouTube, or play it in a web browser via the wonderful JS Mocha CoCo emulator.
My BASIC attract screen does not attempt to recreate that one, but is more of an homage to the style of attract screens we had in those early years.
My initial version clocked in at about 30 lines, and I suggested ways to make it smaller, such as using arrays to store screen locations rather than individual variables. Arrays make things smaller, but are slower. i.e., if you wanted to track four ghosts on the screen for a Pac-Man game, you could have variables like G1, G2, G3 and G4 and then have a block of code that handled each one individually. Or, you could have an array such as DIM G(3) and access the four ghost locations using G(0), G(1), G(2) and G(3). This allows handling the ghosts in a FOR/NEXT loop instead of four individual blocks of code using separate variables.
Here is a verbose example of randomly moving around four “ghosts”:
10 ' WANDERING.BAS 20 CLS0 30 G1=1024:G2=1055:G3=1504:G4=1535 40 C1=191:C2=239:C3=223:C4=255 50 ' DISPLAY GHOSTS 60 POKE G1,C1:POKE G2,C2:POKE G3,C3:POKE G4,C4 70 ' RANDOM MOVE G1 80 ON RND(4) GOTO 90,100,110,120 90 NL=G1+1:GOTO 130 100 NL=G1-1:GOTO 130 110 NL=G1-32:GOTO 130 120 NL=G1+32 130 IF NL<1024 THEN 180 140 IF NL>1535 THEN 180 150 ' ERASE G1 AND UPDATE LOCATION 160 POKE G1,128:POKE NL,C1:G1=NL 170 ' RANDOM MOVE G2 180 ON RND(4) GOTO 190,200,210,220 190 NL=G2+1:GOTO 230 200 NL=G2-1:GOTO 230 210 NL=G2-32:GOTO 230 220 NL=G2+32 230 IF NL<1024 THEN 280 240 IF NL>1535 THEN 280 250 ' ERASE G2 AND UPDATE LOCATION 260 POKE G2,128:POKE NL,C2:G2=NL 270 ' RANDOM MOVE G3 280 ON RND(4) GOTO 290,300,310,320 290 NL=G3+1:GOTO 330 300 NL=G3-1:GOTO 330 310 NL=G3-32:GOTO 330 320 NL=G3+32 330 IF NL<1024 THEN 380 340 IF NL>1535 THEN 380 350 ' ERASE G4 AND UPDATE LOCATION 360 POKE G3,128:POKE NL,C3:G3=NL 370 ' RANDOM MOVE G4 380 ON RND(4) GOTO 390,400,410,420 390 NL=G4+1:GOTO 430 400 NL=G4-1:GOTO 430 410 NL=G4-32:GOTO 430 420 NL=G4+32 430 IF NL<1024 THEN 470 440 IF NL>1535 THEN 470 450 ' ERASE G4 AND UPDATE LOCATIOn 460 POKE G4,128:POKE NL,C4:G4=NL 470 GOTO 60
And here is that same program, converted to use arrays for the four ghost locations, four ghost colors, and four directions:
10 ' WANDERING2.BAS
20 CLS0
30 G(0)=1024:G(1)=1055:G(2)=1504:G(3)=1535
40 C(0)=191:C(1)=239:C(2)=223:C(3)=255
45 D(0)=1:D(1)=-1:D(2)=-32:D(3)=32
50 ' DISPLAY GHOSTS
60 FOR I=0 TO 3:POKE G(I),C(I)
70 ' RANDOM MOVE G(I)
80 NL=G(I)+D(RND(4)-1)
130 IF NL<1024 THEN 170
140 IF NL>1535 THEN 170
150 ' ERASE G(I) AND UPDATE LOCATION
160 POKE G(I),128:POKE NL,C(I):G(I)=NL
170 NEXT
470 GOTO 60
I tried to keep common line numbers where I could. 47 lines of code down to 15.
And, now that it is an array, it’s easy to make it handle as many ghosts as you want. By adding one more element to the array, and changing the FOR/NEXT loop to count 0-4 instead of 0-3, we get an extra ghost:
10 ' WANDERING3.BAS
20 CLS0
30 G(0)=1024:G(1)=1055:G(2)=1504:G(3)=1535:G(4)=1263
40 C(0)=191:C(1)=239:C(2)=223:C(3)=255:C(4)=143
45 D(0)=1:D(1)=-1:D(2)=-32:D(3)=32
50 ' DISPLAY GHOSTS
60 FOR I=0 TO 4:POKE G(I),C(I)
70 ' RANDOM MOVE G(I)
80 NL=G(I)+D(RND(4)-1)
130 IF NL<1024 THEN 170
140 IF NL>1535 THEN 170
150 ' ERASE G(I) AND UPDATE LOCATION
160 POKE G(I),128:POKE NL,C(I):G(I)=NL
170 NEXT
470 GOTO 60
Arrays are great for reducing code size, and making it so one routine can handle multiple instances of something (locations, colors, etc.).
But, it is slower. Looking up X(3) is slower than looking up X3 since looking up an array has to first look up the variable, and then index in to it to find the entry.
Here is the attract code, converted to use arrays for the block positions and movement directions. As you can see, I’m basically handling the blocks like I did the ghosts above — as objects that can be moved around the screen. Instead of making their movement random, they follow a pattern around the outline of the screen. Instead of having a set color, they just cycle through the seven available non-black VDG colors:
10 ' ATTRACT2.BAS
20 L(0)=1024:L(1)=1024+23:L(2)=1535:L(3)=1535-23
30 Z=143
40 CL(0)=1024:CD(0)=1
50 CL(1)=1055:CD(1)=32
60 CL(2)=1535:CD(2)=-1
70 CL(3)=1504:CD(3)=-32
80 CLS 0:PRINT @268,"ATTRACT!";
90 LD(0)=1:LD(1)=1:LD(2)=-1:LD(3)=-1
100 FOR I=0 TO 3:POKE L(I),Z:NEXT
110 Z=Z+16:IF Z>255 THEN Z=143
120 FOR I=0 TO 3:L(I)=L(I)+LD(I):NEXT
130 FOR L=0 TO 3
140 FOR C=0 TO 3
150 IF L(L)=CL(C) THEN LD(L)=CD(C)
160 NEXT
170 NEXT
180 GOTO 100
30 lines of the originally down to 18 by using arrays.
When time isn’t as important as code size (or convenience), arrays are a great thing.
I have two more iterations of this attract screen to share, so I’ll end with…
To be continue…
