This is a followup (and correction) to my PUT defined by ASCII strings article. That article, itself, was a followup to my Extended Color BASIC PUT from DATA article. They both discuss a method to use the GET/PUT graphics commands with pre-loaded data to PUT on the screen, rather than having to render/draw something first and then GET it so you could PUT it later.
I post such articles for two main reasons:
- So I can learn from all the much-smarter programmers who leave comments with advice/suggestions/corrections.
- So I can find it again when I’ve forgotten how it worked.
#2 is what led me to my article as I wanted to use the code for another experiment. And that’s when I realized my original PUTDATA.BAS program had a bug: it PUTs the tanks flipped vertically!
The program defined 8×8 characters as ASCII strings. I used a tank with four versions – one for each direction. They looked like this:
580 'TANK UP
590 DATA " XX "
600 DATA " XX "
610 DATA "XX XX XX"
620 DATA "XXXXXXXX"
630 DATA "XXXXXXXX"
640 DATA "XXXXXXXX"
650 DATA "XXXXXXXX"
660 DATA "XX XX"
A routine READs those strings from the DATA statements, then walks through the characters looking for an “X”. If it finds one, it sets a bit in a number variable. At the end of the scan, it now has a byte value which can be loaded into the PUT data.
However, my routine to scan the strings does it backwards and the image is reversed left-to-right:
380 '
390 'READ DATA AND POKE AT L
400 '
410 PRINT
420 'READ STRINGS AND CONVERT
430 'TO BYTES.
440 FOR Z=0 TO 7:V=0
450 READ Z$:PRINT Z$,;
460 FOR BT=1 TO 8
470 'FASTER WAY
480 IF MID$(Z$,BT,1)="X" THEN V=V+BT(BT-1)
490 'SLOW WAY
500 'IF MID$(Z$,BT,1)="X" THEN V=V+2^(BT-1)
510 NEXT:PRINT INT(V);HEX$(V)
520 POKE L+Z,(NOT V)+256:NEXT:RETURN
530 NEXT:PRINT V;HEX$(V):NEXT
540 RETURN
I did not notice this until I tried to use this code for a new experiment, and it was not PUTting what I expected. But for the tanks, being symmetrical, I did not catch it in my original demo. The UP and DOWN tanks looked correct, and I failed to notice my LEFT and RIGHT tanks were reversed.
The bug is from the loop at line 460 that walks through the bits from 1 to 8, and uses that value as the index into the string using MID$. A bit from 1 to 8 is rightmost to leftmost, but on a string, 1 to 8 is leftmost to rightmost. One of them needs to work backwards.
Since I already do some math to calculate the bit (to base-0 counting, 0-7 instead of 1-8), I just made my change there:
470 'FASTER WAY
480 IF MID$(Z$,BT,1)="X" THEN V=V+BT(8-BT)
490 'SLOW WAY
500 'IF MID$(Z$,BT,1)="X" THEN V=V+2^(8-BT)
Now I get the tanks facing the proper directions my test program PUTs them on the screen: UP, DOWN, LEFT then RIGHT.

I have added this code to my GitHub repository in “CoCo Programs” under “basic”:
https://github.com/allenhuffman/CoCo-Programs/tree/main/basic/tank
And here is the full version with the fix:
0 'PUTDATA2.BAS (FIXED BUG)
1 '2026-05-06
2 'SHOWS HOW TO DO IT USING
3 'STRINGS RATHER THAN #S
4 '
10 'TO SPEED UP STR-TO-BYTE
20 DIM BT(7):FOR BT=0 TO 7:BT(BT)=2^BT:NEXT
30 '
40 'VARIABLES USED IN THE
50 'POKE-TO-ARRAY ROUTINE MUST
60 'BE PRE-ALLOCATED OR THEY
70 'WILL CAUSE ARRAY MEM TO
80 'SHIFT WHEN IT GET USED.
90 '
100 DIM L,V,Z,Z$
110 '
120 'EACH ARRAY ENTRY CAN STORE
130 '5 BYTES. AN 8X8 SINGLE
140 'COLOR CHARACTER IS 8, SO
150 'WE NEED TWO ARRAY ENTRIES
160 '(10 BYTES) TO FIT THE 8
170 'BYTE CHARACTER.
180 '
190 DIM TU(1),TD(1),TL(1),TR(1):GOSUB 320
200 '
210 ' TEST PROGRAM
220 '
230 PMODE 4,1:PCLS 1:SCREEN 1,1
240 PUT (0,0)-(7,7),TU
250 PUT (16,0)-(16+7,7),TD
260 PUT (32,0)-(32+7,7),TL
270 PUT (48,0)-(48+7,7),TR
280 GOTO 280
290 '
300 'LOAD SPRITE CHARACTERS
310 '
320 PRINT "LOADING DATA";
330 L=VARPTR(TU(0)):GOSUB 390
340 L=VARPTR(TD(0)):GOSUB 390
350 L=VARPTR(TL(0)):GOSUB 390
360 L=VARPTR(TR(0)):GOSUB 390
370 RETURN
380 '
390 'READ DATA AND POKE AT L
400 '
410 PRINT
420 'READ STRINGS AND CONVERT
430 'TO BYTES.
440 FOR Z=0 TO 7:V=0
450 READ Z$:PRINT Z$,;
460 FOR BT=1 TO 8
470 'FASTER WAY
480 IF MID$(Z$,BT,1)="X" THEN V=V+BT(8-BT)
490 'SLOW WAY
500 'IF MID$(Z$,BT,1)="X" THEN V=V+2^(8-BT)
510 NEXT:PRINT INT(V);HEX$(V)
520 POKE L+Z,(NOT V)+256:NEXT:RETURN
530 NEXT:PRINT V;HEX$(V):NEXT
540 RETURN
550 '
560 '8X8 SPRITE CHARACTERS
570 '
580 'TANK UP
590 DATA " XX "
600 DATA " XX "
610 DATA "XX XX XX"
620 DATA "XXXXXXXX"
630 DATA "XXXXXXXX"
640 DATA "XXXXXXXX"
650 DATA "XXXXXXXX"
660 DATA "XX XX"
670 'TANK DOWN
680 DATA "XX XX"
690 DATA "XXXXXXXX"
700 DATA "XXXXXXXX"
710 DATA "XXXXXXXX"
720 DATA "XXXXXXXX"
730 DATA "XX XX XX"
740 DATA " XX "
750 DATA " XX "
760 'TANK LEFT
770 DATA " XXXXXX"
780 DATA " XXXXXX"
790 DATA " XXXX "
800 DATA "XXXXXXX "
810 DATA "XXXXXXX "
820 DATA " XXXX "
830 DATA " XXXXXX"
840 DATA " XXXXXX"
850 'TANK RIGHT
860 DATA "XXXXXX "
870 DATA "XXXXXX "
880 DATA " XXXX "
890 DATA " XXXXXXX"
900 DATA " XXXXXXX"
910 DATA " XXXX "
920 DATA "XXXXXX "
930 DATA "XXXXXX "
Until next bug … I mean, time. Until next time…
