This is a quiz-authoring and quiz-taking program published in Syntax Quarterly (Spring 1983), written by Dale F. Lipinski. It allows the user to build a quiz with up to three formats — multiple choice (up to 9 options), true/false, or direct answer — storing all text in a single packed string array A$ with offset pointers held in a 2D numeric array A(). Memory is carefully budgeted before entry begins: line 230 uses PEEK on system variables 16386/16387 (RAMTOP) and 16412/16413 (E_LINE) to calculate available character storage E, which is then reported as total and per-question averages. The program also supports optional wrong-answer explanations, records a running score, and offers to SAVE the completed quiz back to tape at the end.
Program Analysis
Program Structure
The program divides into three broad phases: configuration (lines 10–280), quiz entry (lines 290–760), and quiz delivery (lines 770–1240). A final block at lines 1250–1270 handles the auto-run SAVE of the shell program.
- Configuration (10–280): Collects quiz type (
C$), number of questions (A), explanation flag (D$), and number of choices (Bfor multiple choice). Computes available string spaceEvia PEEK, then dimensions both arrays. - Quiz Entry (290–760): For each question, stores question text, answer, optional explanation, and (for multiple choice) each lettered choice into the packed string
A$, recording segment offsets in the numeric arrayA(). - Quiz Delivery (770–1240): Prompts for title and player name, then loops through all questions, checks answers, updates score
S, and optionally displays explanations for wrong answers.
Memory Management via PEEK
Line 230 is the most technically notable line in the program:
LET E=(PEEK 16386-PEEK 16412+256*(PEEK 16387-PEEK 16413)-50)-1300-(D*(A+1)*5)
This calculates free RAM by subtracting the E_LINE pointer (16412/16413, the current end of BASIC workspace) from RAMTOP (16386/16387), then subtracts an overhead estimate of 1300 bytes plus the space the two arrays will themselves occupy (D*(A+1)*5 bytes, since each numeric array element takes 5 bytes). The result E is used to dimension A$ at line 299, ensuring the string buffer fits in available memory. This is a practical, if fragile, approach — the constants 50 and 1300 are empirical guesses at interpreter overhead.
Packed String / Pointer Array Idiom
All text (questions, answers, explanations, choices) is stored in a single string A$ dimensioned to E characters. Segment boundaries are tracked in a 2D numeric array A(A+1, D) where each row corresponds to one question and each column holds a character offset:
| Column | Meaning |
|---|---|
A(F,1) | Start of question text |
A(F,2) | Start of answer |
A(F,3) | Start of explanation |
A(F,4) … A(F,D) | Start of each multiple-choice option |
A(F+1,1) | End marker (= A(F,D)) |
Retrieval during the quiz phase slices A$ with expressions like A$(A(C,1) TO A(C,2)-1). This is an efficient, if error-prone, manual memory management technique for a BASIC environment lacking dynamic data structures.
Answer Encoding for Multiple Choice
Line 705 prepends each choice with CHR$ (C+28), mapping choice numbers 1–9 to ZX81 character codes 29–37 (the inverse-video digits 1–9). Line 735 then checks whether the stored answer text matches the current choice text; if so, it overwrites the first byte of the answer field with that same encoded character. At quiz time (line 955), for multiple-choice mode, K$ is set to just this single encoded byte, so comparison at line 1020 (K$=F$) works correctly without the user knowing about the encoding.
Input Validation Pattern
Throughout the program, single-character inputs are validated by testing CODE against known ZX81 character codes. For example:
- Line 70:
IF CODE C$<=28 OR CODE C$>=32 THEN GOTO 40— accepts only codes 29, 30, 31 (inverse “1”, “2”, “3”). - Line 140:
IF CODE D$<=27 OR CODE D$>=30— accepts codes 28 or 29 (inverse “0” or “1”). - Line 270:
IF CODE E$<=27 OR CODE E$>=29— accepts only code 28 (inverse “0”).
This relies on ZX81’s keyboard INPUT returning inverse-video digit characters rather than plain ASCII, a platform-specific behavior hobbyists exploited for simple menu selection.
Notable Idiom: B$ as a Reusable Prompt Banner
Line 30 defines B$ as a long string of block-graphic characters (▀ tiles) followed by the inverse-video text “ENTER ANSWER”. This is PRINTed at the bottom of most input screens as a visual prompt bar. Slicing B$( TO 32) at line 950 prints only the graphic portion, omitting the text label where it would be inappropriate.
Bugs and Anomalies
- Line 530 condition is always false:
IF CODE D$<=28 OR CODE D$>=3— sinceCODE D$is always ≥ 3 for any non-empty string, this condition is always true and execution never falls through to line 540 (the explanation-entry block). The explanation feature is therefore broken;H$retains whatever value was set at line 160 (a single space). The correct test was probably>=30(matching the validation at line 140). - Line 410/420/520/620/730 off-by-one: Segments are stored as
A$(A(F,1) TO A(F,1)+H)whereH=LEN E$, which copiesH+1characters (an extra trailing character bleeds into the next segment). This is compensated for at retrieval time by the-1in slice end indices, but it wastes one byte per segment. - Line 1170 comma after TAB 0:
PRINT "QUIZ IS COMPLETE. THANK YOU",J$;TAB 0,,...— the comma afterTAB 0produces an extra blank line, which is cosmetic rather than functional. - Line 1220 loops to 830 instead of 40: After a wrong answer at the save prompt, execution returns to line 830 (ask for player name) rather than restarting the whole quiz setup, meaning a second run reuses the existing
A()andA$()data correctly but skips re-dimensioning.
FAST Mode
Line 20 invokes FAST mode for the entire program, suppressing the display refresh and significantly speeding up string operations during quiz entry. This is appropriate given the volume of string slicing and array writes performed during the authoring phase.
Content
Source Code
1 REM %Q%U%I%Z% % % % % % % % % % % % % % % % % % %
2 REM %D%A%L%E% %F%.% %L%I%P%I%N%S%K%I% % % % % % %
3 REM %S%Y%N%T%A%X% %Q%U%A%R%T%E%R%L%Y% % % % % % %
4 REM %S%P%R%I%N%G% %1%9%8%3% % % % % % % % % % % %
10 LET S=0
20 FAST
30 LET B$="\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''% %E%N%T%E%R% %A%N%S%W%E%R% "
40 CLS
50 PRINT "WHAT TYPE OF QUIZ DO YOU WISH TOHAVE?",,"1 = MULTIPLE CHOICE","2 = TRUE OR FALSE","3 = DIRECT ANSWER",B$
60 INPUT C$
70 IF CODE C$<=28 OR CODE C$>=32 THEN GOTO 40
80 CLS
90 PRINT "HOW MANY QUESTIONS DO YOU WISH TO ASK?",,B$
100 INPUT A
110 CLS
120 PRINT "DO YOU WISH TO EXPLAIN THE","ANSWER IF IT IS WRONG?","1 = YES",,"0 = NO",,B$
130 INPUT D$
140 IF CODE D$<=27 OR CODE D$>=30 THEN GOTO 110
160 IF D$="0" THEN LET H$=" "
170 CLS
180 LET D=4
190 IF C$="2" OR C$="3" THEN GOTO 230
200 PRINT "WHAT IS THE MAXIMUM NUMBER OF","CHOICES PER QUESTION?","LIMIT OF 9",,B$
210 INPUT B
215 IF B>=10 THEN GOTO 170
220 LET D=B+4
230 LET E=(PEEK 16386-PEEK 16412+256*(PEEK 16387-PEEK 16413)-50)-1300-(D*(A+1)*5)
240 CLS
250 PRINT "YOU WILL HAVE ";A;" QUESTIONS","WITH A TOTAL CHARACTER INPUT OF",E;TAB 0;"AN AVERAGE OF ";E/A,"CHARACTERS PER QUESTION";TAB 0;"IF THIS IS OKAY ENTER 0","IF NOT ENTER 1",,B$
260 INPUT E$
270 IF CODE E$<=27 OR CODE E$>=29 THEN GOTO 40
280 DIM A(A+1,D)
290 DIM A$(E)
300 LET A(1,1)=1
320 FOR F=1 TO A
330 CLS
340 PRINT "WHAT IS QUESTION NUMBER ";F;"?",B$
350 INPUT E$
360 PRINT E$;TAB 0;"INPUT 0 IF THIS IS CORRECT","INPUT 1 IF NOT CORRECT",B$
370 INPUT F$
380 IF CODE F$<=27 OR CODE F$>=29 THEN GOTO 330
390 LET H=LEN E$
400 LET A(F,2)=A(F,1)+H
410 LET A$(A(F,1) TO A(F,1)+H)=E$
420 CLS
430 PRINT "WHAT IS THE ANSWER?"
440 IF C$="2" THEN PRINT "1 = TRUE",,"0 = FALSE"
450 PRINT B$
460 INPUT E$
465 CLS
470 PRINT E$;TAB 0;"INPUT 0 IF THIS IS CORRECT","INPUT 1 IF NOT CORRECT",B$
475 IF C$="2" AND E$="1" THEN PRINT AT 0,0;"1 = TRUE"
477 IF C$="2" AND E$="0" THEN PRINT AT 0,0;"0 = FALSE"
480 INPUT F$
490 IF CODE F$<=27 OR CODE F$>=29 THEN GOTO 420
495 IF C$="1" THEN LET E$=" = "+E$
500 LET H=LEN E$
510 LET A(F,3)=A(F,2)+H
520 LET A$(A(F,2) TO A(F,2)+H)=E$
530 IF CODE D$<=28 OR CODE D$>=3 THEN GOTO 600
540 CLS
550 PRINT "WHAT IS THE EXPLANATION","NO EXPLANATION INPUT A SPACE",B$
560 INPUT H$
565 CLS
570 PRINT H$;TAB 0;"INPUT 0 IF THIS IS CORRECT","INPUT 1 IF NOT CORRECT",B$
580 INPUT F$
590 IF CODE F$<=27 OR CODE F$>=29 THEN GOTO 540
600 LET H=LEN H$
610 LET A(F,4)=A(F,3)+H
620 LET A$(A(F,3) TO A(F,3)+H)=H$
630 IF CODE C$<=28 OR CODE C$>=30 THEN GOTO 750
640 FOR C=1 TO B
650 CLS
660 PRINT "WHAT IS THE NUMBER ";C;" CHOICE?","FOR NO CHOICE INPUT A SPACE",B$
670 INPUT E$
675 CLS
680 PRINT C;" = ";E$;TAB 0;"INPUT 0 IF THIS IS CORRECT","INPUT 1 IF NOT CORRECT",B$
690 INPUT F$
700 IF CODE F$<=27 OR CODE F$>=29 THEN GOTO 650
705 LET E$=CHR$ (C+28)+" = "+E$
710 LET H=LEN E$
720 LET A(F,4+C)=A(F,3+C)+H
730 LET A$(A(F,3+C) TO A(F,3+C)+H)=E$
735 IF A$(A(F,2)+1 TO A(F,3)-1)=E$(2 TO ) THEN LET A$(A(F,2) TO A(F,2))=CHR$ (C+28)
740 NEXT C
750 LET A(F+1,1)=A(F,D)
760 NEXT F
770 CLS
780 PRINT "WHAT IS THE TITLE OF THE QUIZ?",B$
790 INPUT I$
795 CLS
800 PRINT I$;TAB 0;"INPUT 0 IF THIS IS CORRECT","INPUT 1 IF NOT CORRECT",B$
810 INPUT F$
820 IF CODE F$<=27 OR CODE F$>=29 THEN GOTO 770
830 CLS
840 PRINT "WHAT IS YOUR NAME PLEASE?",B$
850 INPUT J$
860 CLS
870 PRINT "THANK YOU ";J$;TAB 0;"GET READY FOR YOUR QUIZ"
880 PAUSE 400
890 CLS
900 PRINT TAB 10;"% %Z%X%-%8%1% %Q%U%I%Z% ";TAB 0;I$;TAB 0;"TAKEN BY ";J$
910 PAUSE 400
920 FOR C=1 TO A
930 CLS
940 LET E$=A$(A(C,1) TO A(C,2)-1)
945 LET K$=A$(A(C,2) TO A(C,3)-1)
950 PRINT "QUESTION NUMBER ";C;TAB 0;E$;TAB 0;B$( TO 32)
955 IF C$="1" THEN LET K$=A$(A(C,2) TO A(C,2))
960 IF C$="1" THEN FOR I=4 TO D-1
970 IF C$="1" THEN PRINT A$(A(C,I) TO A(C,I+1)-1)
980 IF C$="1" THEN NEXT I
990 IF C$="2" THEN PRINT "1 = TRUE",,"0 = FALSE"
\n1000 PRINT B$
\n1010 INPUT F$
\n1020 IF K$=F$ THEN PRINT "% %V%E%R%Y% %G%O%O%D% %T%H%A%T% %I%S% %C%O%R%R%E%C%T% "
\n1030 IF K$=F$ THEN PAUSE 400
\n1040 IF K$=F$ THEN LET S=S+1
\n1050 IF K$=F$ THEN GOTO 1150
\n1060 PRINT "% %I% %A%M% %S%O%R%R%Y% %T%H%A%T% %I%S% %N%O%T% %C%O%R%R%E%C%T% "
\n1070 PAUSE 400
\n1080 CLS
\n1090 PRINT "THE CORRECT ANSWER IS";TAB 0;A$(A(C,2) TO A(C,3)-1)
\n1100 IF C$="2" AND K$="1" THEN PRINT AT 1,0;"1 = TRUE"
\n1110 IF C$="2" AND K$="0" THEN PRINT AT 1,0;"0 = FALSE"
\n1120 PRINT A$(A(C,3) TO A(C,4)-1)
\n1130 PRINT "PRESS % %E%N%T%E%R% TO CONTINUE",B$
\n1140 INPUT E$
\n1150 NEXT C
\n1160 CLS
\n1170 PRINT "QUIZ IS COMPLETE. THANK YOU",J$;TAB 0,,"YOUR SCORE IS ";S;" % %C%O%R%R%E%C%T% ","OUT OF A POSSIBLE ";A;" QUESTIONS.";TAB 0;"YOUR GRADE AVERAGE IS ",S/A*100;" PER CENT"
\n1180 PAUSE 400
\n1190 PRINT AT 15,0;"DO YOU WISH TO SAVE THIS PROGRAM1 = NO",,"0 = YES",,B$
\n1200 LET S=0
\n1210 INPUT F$
\n1220 IF CODE F$<=27 OR CODE F$>=29 THEN GOTO 830
\n1230 SAVE "QUIZ"
\n1240 GOTO 830
\n1250 CLEAR
\n1260 SAVE "1002%0"
\n1270 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
