See Also: part 1, part 2, part 3, part 4 and part 5.
ASCII character data to 8-bit ASCII HEX data.
Let’s jump right in and write the program that writes the DATA statements for this maze.
It should generate a string that will start with a line number, the keyword “DATA”, and then add 2-digit hex values to it until it reaches that magic 250 character limit. When that happens, we write it out to cassette or disk, and start a new line. (Of course, this could also be adjusted to make each line 31 characters or less, to fit nicely on the CoCo’s screen. That’s the magic of computer generated code — you can easily make it change the output rather than having to do it by hand.)
I also want to make it get as many bytes as possible on the line, so I’ll start with single digit line numbers, and increment by 1. “1DATA” in ASCII gives me four extra bytes than “1000 DATA” and, when they get tokenized (either by loading from tape/disk in ASCII, or typing them in) they will take up the same amount of room since line numbers are all stored as two byte values in the program code. The result can then be RENUMbered to start at whatever line is needed for the final program.
Here is my very slow, very large version:
10 CLEAR 500 20 ' MAX OUTPUT LINE LENGTH 30 INPUT "MAX LINE LENGTH";MX 40 IF MX=0 OR MX>250 THEN MX=250 50 ' GET/SET DEVICE NUMBER 60 DV=0 70 PRINT "OUTPUT TO D)ISK, P)RINTER" 80 INPUT "S)CREEN OR T)APE";A$ 90 IF A$="D" THEN DV=1 ELSE IF A$="P" THEN DV=-2 ELSE IF A$="S" THEN DV=0 ELSE IF A$="T" THEN DV=-1 ELSE 70 100 ' CREATE OUTPUT FILE 110 OPEN "O",#DV,"MAZEDATA.BAS" 120 ' LINE NUMBER/RESET STRING 130 LN=1:LN$="" 140 ' READ LINE OF MAZE DATA 150 READ A$:IF A$="" THEN 470 160 PRINT A$ 170 ' START AT FIRST CHARACTER 180 CH=1 190 ' INIT BIT VALUE 200 BT=128 210 ' RESET OUTPUT VALUE 220 V=0 230 ' IF X, ADD 1 (SET BIT) 240 IF MID$(A$,CH,1)="X" THEN V=V+BT 250 PRINT MID$(A$,CH,1); 260 ' SHIFT BIT LEFT 270 BT=INT(BT/2) 280 ' IF MORE BITS, DO NEXT CH 290 IF BT>0 THEN CH=CH+1:GOTO 240 300 ' CREATE 2-DIGIT HEX VALUE 310 HX$=HEX$(V):IF V<16 THEN HX$="0"+HX$ 320 PRINT ,HX$;CH 330 ' START LINE IF NEEDED 340 ' TRIM FIRST CHAR 350 IF LN$="" THEN LN$=STR$(LN)+"DATA":LN$=MID$(LN$,2) 360 ' ADD HEX VALUE 370 LN$=LN$+HX$ 380 'IF LINE FULL, WRITE IT OUT 390 IF LEN(LN$)>=MX-2 THEN PRINT #DV,LN$:LN$="":LN=LN+1 400 ' GO TO NEXT CH 410 CH=CH+1 420 ' IF PAST END, NEW LINE 430 IF CH>LEN(A$) THEN 150 440 ' OTHERWISE, NEXT BYTE 450 GOTO 200 460 ' WRITE ANY REMAINING DATA 470 PRINT #DV,LN$ 480 CLOSE #DV 490 END 1000 DATA "XXXXXXXXXXXXXXXXXXXXXXXXXXXX" 1010 DATA "X XX X" 1020 DATA "X XXXX XXXXX XX XXXXX XXXX X" 1030 DATA "X XXXX XXXXX XX XXXXX XXXX X" 1040 DATA "X XXXX XXXXX XX XXXXX XXXX X" 1050 DATA "X X" 1060 DATA "X XXXX XX XXXXXXXX XX XXXX X" 1070 DATA "X XXXX XX XXXXXXXX XX XXXX X" 1080 DATA "X XX XX XX X" 1090 DATA "XXXXXX XXXXX XX XXXXX XXXXXX" 1100 DATA " X XXXXX XX XXXXX X " 1110 DATA " X XX XX X " 1120 DATA " X XX XXXXXXXX XX X " 1130 DATA "XXXXXX XX X X XX XXXXXX" 1140 DATA " X X " 1150 DATA "XXXXXX XX X X XX XXXXXX" 1160 DATA " X XX XXXXXXXX XX X " 1170 DATA " X XX XX X " 1180 DATA " X XX XXXXXXXX XX X " 1190 DATA "XXXXXX XX XXXXXXXX XX XXXXXX" 1200 DATA "X XX X" 1210 DATA "X XXXX XXXXX XX XXXXX XXXX X" 1220 DATA "X XXXX XXXXX XX XXXXX XXXX X" 1230 DATA "X XX XX X" 1240 DATA "XXX XX XX XXXXXXXX XX XX XXX" 1250 DATA "XXX XX XX XXXXXXXX XX XX XXX" 1260 DATA "X XX XX XX X" 1270 DATA "X XXXXXXXXXX XX XXXXXXXXXX X" 1280 DATA "X XXXXXXXXXX XX XXXXXXXXXX X" 1290 DATA "X X" 1300 DATA "XXXXXXXXXXXXXXXXXXXXXXXXXXXX" 1310 DATA ""
Let’s walk through the code…
- Line 10 – We need more than the default 200 bytes of string space.
- Lines 20-40 – Just for fun, I decided to let the user choose how long the output lines will be. 32 would give DATA statements that fit on the screen, or maybe 80 for a printer. 250 is the largest allowed.
- Lines 50-90 – Just to be fancy, the user can choose Disk, Printer, Screen or Tape output. When writing this, I learned you can still use OPEN “O”,#-2,”FILE” even on the printer or screen! The filename is ignored and no error is generated. Very cool.
- Lines 100-110 – Create the output file.
- Lines 120-130 – LN is the initial line number for the DATA statements, and LN$ will be the buffer for the line we are creating.
- Lines 140-160 – Read a line of MAZE DATA and display it. (This program is slow, so I thought some output would be fun to look at.)
- Lines 170-180 – CH will be the current character of the line we are checking to be an “X” or not.
- Lines 190-200 – BT is the bit value. For 8-bits, we start with the high bit, which is a value of 128. Unlike my previous example, I think this might be a simpler approach for making the value as we scan 8 characters.
- Lines 210-220 – V will be the output value (8 characters turned in to a number).
- Lines 230-250 – If the current character is “X”, add the BT value to V. We then print the character that is being processed.
- Lines 260-270 – To get to the next bit value, we divide by 2. 128 becomes 64, 64 becomes 32, etc.
- Lines 280-290 – As long as BT>0, we have more bits to do so we can move to the next CH character of the line. GOTO 240 resumes checking the character.
- Lines 300-320 – If out of bits, we make a HEX$ out of V. If it is a value less than 16 (0-15 would be 0-F in hex), we add a leading zero to make it always two characters. We then print that to the screen.
- Lines 330-350 – If LN$ is empty, we need to start it with a line number and “DATA”. When using STR$(x) to turn a number into a string, a leading space will be added. This means 1 becomes ” 1″. If this was negative, that would be used for the minus sign — i.e., -1 would be “-1”. Since we know our number will be positive, we can just get rid of the first character. Using a trick I recently learned about, MID$() will give the right side of a string starting with a position if you leave out the third parameter (length). Thus, instead of RIGHT$(LN$,LEN(LN$)-1), I can do MID$(LN$,2) to give me everything from character 2 on. Wish I knew that in the 80s! (Hat tip to Robin at 8-Bit Show and Tell since I think that is where I learned this.)
- Lines 360-370 – We add the HX$ to the end of our LN$ (which is either the one we just started, or one that is slowly growing as we keep adding values).
- Lines 380-390 – If the LN$ reaches our max (minus 2, since we just added a 2 character hex value), we print it out to the selected device, then reset LN$ and increment our line number.
- Lines 400-410 – Move to the next CH character position.
- Lines 420-430 – If CH is past the end of the length of our A$ data, go to line 150 to read the next maze DATA.
- Lines 440-450 – If there’s still more characters in the line, go back to 150 and get the next one.
- Lines 460-480 – If done, we need to output whatever is left. The earlier output only did that when the line reached max size. This takes care of the final line that is less than that. We then close the file. (Or, if this is printer or screen, this doesn’t do anything.)
Running this using a max of 250 produces this in the file:
Our maze data converts to just two hex values more than what would fit on one line of BASIC. So close! To make it look prettier (but take up more program space) we could have done it with shorter lines:
1DATAFFFFFFF080060010BDF6FBD0BDF6FBD0BD 2DATAF6FBD080000010BDBFDBD0BDBFDBD08186 3DATA1810FDF6FBF005F6FA0005801A0005BFDA 4DATA00FDA05BF000204000FDA05BF005BFDA00 5DATA05801A0005BFDA00FDBFDBF080060010BD 6DATAF6FBD0BDF6FBD08C000310EDBFDB70EDBF 7DATADB7081861810BFF6FFD0BFF6FFD0800000 8DATA10FFFFFFF0
But whatever style you choose, you can then CLOAD/LOAD this ASCII BASIC program and RENUM it to 1000 or wherever you want it to go.
And now that we have our 8-bits maze DATA, we need to write code to read, parse, and display it.
Until next time…