The Hidden Power Of Atari BASIC
This month we're going to look at good old Atari BASIC. For once, though, I'm not going to talk about its problems. Instead, I'm going to tell you about a few of its many virtues. If you've been reading my column since it first appeared in the September 1981 issue of COMPUTE!, then some of this may seem repetitive; but it's time to introduce newcomers to some of this material.
Unfortunately, I am beginning to see more and more poorly written Atari BASIC programs. Generally, what happens is that someone not too well-versed in Atari BASIC attempts to translate a program from another computer's BASIC and botches the job. The last straw, for me, was a recently released book which is full of CAI (Computer Assisted Instruction) programs. All the programs do much the same thing, and all the programs are…well, just a lot of work for so little value.
Now, I'm all for using a computer for drill and practice, even though most of the educational programs which do this are dull and unimaginative (and often overpriced). But even the plainest of CAI programs can at least free up a teacher or parent for 20 or 30 minutes while a student is checking his or her knowledge. And if all you want your CAI program to do is ask questions and wait for a response, then all such programs can be essentially the same. So that's what I'm going to give you this month: a "formula" program for drill and practice.
I also mentioned that we would look at some of the virtues of Atari BASIC, so let's do that first. Among microcomputer BASICs, Atari BASIC is nearly unique in its flexibility in the use of GOTO, GOSUB, and RESTORE. Specifically, each of these statements accept any numeric expression as the line number they reference. Combined with Atari BASICs variable-name flexibility, this means you can code such oddities as:
RESTORE 20000 + 10 * CURRENTROOM
Most Atari BASIC books refer to these capabilities briefly, if at all. But there is some real hidden power here, as we are about to find out. Rather than belabor the point, let's take a look at the accompanying listing and analyze it a step at a time.
Using Variables As Labels
Line 1010 is fairly obvious, so let's start with lines 1060 to 1080. The variables being set here are actually going to be used as labels, the targets of GOTO and GOSUB statements. The only thing you have to be careful of with this method is renumbering—some renumbering utilities warn you when they encounter a variable being used as a label, and some don't.
Now, after setting the DATA pointer in line 1090, we get a line of DATA, assigning the first byte to the variable TYPE$. The action we take next depends on what type of line we got. We use an exclamation point to indicate a screen clear is needed, a colon for an extra blank line, and a period to flag an ordinary text line. In any of these cases, we print the rest of the line and get another one. If the type is an asterisk, the program halts. If the type is a question mark, then it's time for the student to answer.
At this time, let's look at the DATA in lines 10000–10003. The first line begins with an exclamation point, so the screen is cleared and it is printed. Then the colon asks for a blank line before the next line is displayed. Finally, the question mark tells the program to ask for a response. But what's the rest of that funny stuff: 1 =, Y, 0, 10010?
Back at lines 1200–1260, you can see that the digit (a 1 in line 10002) tells the number of possible answers to the question, and the next character indicates the type of answer which is acceptable (the equal sign here asks for an exact match). The program then prompts the user for an answer (the # 16 suppresses the INPUT prompt) and prepares to test its validity. The loop in 1310–1360 checks each valid answer against the user's response.
If an exact answer is needed, even the length of the answer counts. (Example: In line 10002, we have allowed only a single exact answer, the letter Y.) Another flag indicates whether the valid answer can be found somewhere in the user's response line. Line 10012, for example, passes any answer containing the word GRANT (such as MIGRANT WORKERS), so some care is needed in using this type. Finally, if none of the valid answers matches the user's response, the program falls through to lines 1400–1420.
So far, all this has been very straightforward, and it would work on almost any BASIC. Now comes the tricky stuff. Look at line 1320, where we READ numbers into the variables GOSUBLINE and DATALINE. What we're doing is establishing an action to take and a new set of DATA to access if the user's response matches a valid answer. Similarly, in line 1420 we read values to be used if no valid answer is given. Finally, the "magic" of this program is revealed in lines 1510 and 1520.
If we READ a number other than zero for GOSUBLINE, the program actually GOSUBs to that number. And, in any case, we change the DATA pointer to the new DATALINE. If you can't predict what happens if you answer DUCK to the second question (because of the DATA in lines 10012–10014), please type this program and try it out.
Now, the real beauty of this program is that it works with almost any kind of question and answer session. It allows for multiple choice questions (use a format like ?3 = , A, 0, 100, B, 0, 100, C, 0, 200), true/ false, and so on. It provides for special help if needed (via the GOSUBLINEs). And, last but by no means least, it is expandable. You could add many different statement types, question types, or whatever quite easily. And it's all made possible thanks to Atari BASIC.
Multiple Choice Quiz
DL 1000 REM = = = INITIALIZATI ON = = = MF 1010 DIM LINE$ (120), ANS$ (20), TYPE$ (1) IB 1060 INEXACT = 2000 : EXACT = 2 100 NI 1070 MAINLOOP = 1100 : QUESTION = 1200 MC 1080 MATCHED = 1500 CC 1090 RESTORE 10000 : REM where we start PL 1100 REM = = = THE MASTER LOOP = = = FE 1110 READ LINE$ : TYPE$ = LINE$ FJ 1120 IF TYPE$ = "?" THEN GOTO QUESTION DN 1130 IF TYPE$ = "!" THEN PRINT CHR$ (125) DC 1140 IF TYPE$ = ":" THEN PRINT GN 1150 IF TYPE$ ="*" THEN END CE 1160 PRINT LINE$ (2) GB 1170 GOTO MAINLOOP ON 1200 REM = = = PROCESS A QUESTION = = = JI 1210 QCNT = VAL (LINE$ (2, 2) ) DI 1220 TYPE$ = LINE$ (3) PL 1230 POSITION 2, 20 KG 1240 PRINT CHR$ (156); CHR$ (156); DC 1250 PRINT "Your Answer?" ; FL 1260 INPUT # 16, LINE $ DG 1300 REM = = = PROCESS THE ANSWER = = = NF 1310 FOR ANS = 1 TO QCNT CK 1320 READ ANS$, GOSUBLINE, DATALINE BL 1330 IF TYPE$ = "#" THEN GO SUB INEXACT JP 1340 IF TYPE$ ="=" THEN GO SUB EXACT CD 1350 IF MATCH THEN GOTO MATCHED OL 1360 NEXT ANS El 1400 REM = = = ANSWER DOESN'T MATCH = = = JA 1410 REM (read error conditions and fall thru) PJ 1420 READ GOSUBLINE, DATAlINE NO 1500 REM = = = ANSWER MATCH ED = = = FF 1500 IF GOSUBLINE THEN GO SUB GOSUBLINE CD 1520 RESTORE DATALINE GB 1530 GOTO MAINLOOP LD 2000 REM = = = INEXACT MATCH ROUTINE = = = GK 2010 MATCH = 0 : ALEN = LEN (ANS$) GB 2020 SIZE = LEN (LINE$) - ALEN + 1 AL 2030 IF SIZE < 1 THEN RETURN BH 2040 FOR CHAR = 1 TO SIZE GL 2050 IF LINE$ (CHAR, CHAR + ALEN – 1) = ANS $ THEN MATCH = 1: RETURN CF 2060 NEXT CHAR KJ 2070 RETURN BN 2100 REM = = = EXACT MATCH ROUTINE = = = EO 2110 MATCH = (ANS$ = LINE$) KF 2120 RETURN KK 1000 DATA ! READY to try out this program? KP 10001 DATA : (answer Y or N) LJ 10002 DATA ? 1 = , Y, 0, 10010 FL 10003 DATA 0, 10000 PJ 10010 DATA ! A tribute to Groucho Marx: CK 10011 DATA : who is buried in Grant's tomb? MH 10012 DATA ?2 #, GRANT, 0, 10040 HF 10013 DATA DUCK, 10020, 10030 CJ 10014 DATA 10050, 10060 OH 10020 REM Special Sound r Outline KI 10021 FOR FREQ = 120 TO 20 STEP -10 CG 10022 FOR VOLUME = 15 TO 0 STEP -0.5 JK 10023 SOUND 0, FREQ, 10, VOLUME LF 10024 NEXT VOLUME: NEXT FREQ NI 10025 RETURN LB 10030 DATA ! You said the secret word ! LH 10031 DATA :You Win $100. DK 10032 DATA * KL 10040 DATA !Great! you get the consolation PE 10041 DATA .prize of $ 50. DL 10042 DATA * LE 10050 REM raspberry FK 10051 FOR VOLUME = 15 TO 0 STEP -0.25 PK 10052 SOUND 0, 4, 80, VOLUME : NEXT VOLUME NJ 10053 RETURN KM 10060 DATA !Sorry. You lost. DM 10061 DATA *