This program is an interactive quiz-creation and quiz-taking tool that allows a teacher or user to author quizzes of three types: multiple choice, true/false, or direct answer. All question text, answers, explanations, and multiple-choice options are packed sequentially into a single large string array A$(10505,4) using a pointer table stored in the numeric array A(A+1,D), a compact storage technique that avoids wasting memory on fixed-length string slots. Six POKE statements at lines 283–288 directly manipulate memory at a calculated address (derived via PEEK 16400/16401) to set up what appears to be a machine-code or system-variable patch. The quiz engine supports optional wrong-answer explanations, inverse-video prompts built from the B$ banner string, and a final percentage score display; results can be saved to tape under the filename “QUIZ-64K”.
Program Analysis
Program Structure
The program divides cleanly into three phases: configuration (lines 10–270), question authoring (lines 280–760), and quiz playback (lines 770–1260). During configuration the user selects quiz type, number of questions, whether wrong answers should be explained, and (for multiple choice) the maximum number of choices. Authoring collects questions, answers, explanations, and choices one at a time. Playback presents each question, accepts input, scores it, and finally reports a percentage grade.
Packed String Storage
Rather than declaring a 2-D string array with fixed-length rows (which wastes memory), the program stores all text in a single flat string array A$(10505,4) and maintains a pointer table in numeric array A(A+1,D). Each row F of A holds character offsets into A$:
A(F,1)— start of question textA(F,2)— start of answer textA(F,3)— start of explanation textA(F,4)onward — start of each multiple-choice option
Slices are written with A$(A(F,n) TO A(F,n)+H)=E$ and read back with A$(A(C,n) TO A(C,n+1)-1). The sentinel value A(F+1,1)=A(F,D) (line 750) chains each question’s last offset to the next question’s start, making the whole array self-indexing.
Memory Manipulation (POKEs)
Lines 282–288 perform direct memory writes after computing a base address from the system variable at addresses 16400–16401:
L = PEEK 16400 + 256*PEEK 16401
The six bytes written starting at L+1 are:
| Offset | Value | Decimal |
|---|---|---|
| L+1 | 41 | 0x29 — INC HL (Z80) |
| L+2 | 164 | 0xA4 — AND H |
| L+3 | 1 | 0x01 — LD BC,nn (first byte) |
| L+4 | 38 | 0x26 — LD H,n (or low byte of BC) |
| L+5 | 164 | 0xA4 — AND H |
| L+6 | 0 | 0x00 — NOP |
The exact intent is unclear without knowing the system variable pointed to, but this is a known technique for patching the ZX81/TS1000 BASIC interpreter or I/O routines at run time to extend available memory or modify behaviour before the large DIM statements at lines 280–281 consume RAM.
Quiz Type Logic
The variable C$ encodes quiz type: "1" = multiple choice, "2" = true/false, "3" = direct answer. Branching is handled throughout with inline IF C$="x" THEN … guards rather than a structured subroutine, keeping the code flat but repetitive. For multiple choice, the correct-answer byte is overwritten in A$ at line 735 with CHR$(C+28), encoding the choice number as a low ASCII code to allow a single-character comparison at answer time (line 955).
Input Validation Idiom
Throughout the program, user input is validated by checking CODE of the first character against expected ranges. For example:
- Line 70:
IF CODE C$<=28 OR CODE C$>=32 THEN GOTO 40— accepts only characters with codes 29, 30, or 31 (digits “1”, “2”, “3” on the ZX81 character set). - Line 140: accepts codes 28 or 29 only (“0” or “1”).
- Lines 270, 380, 490, etc.: similar range checks.
This avoids the overhead of string comparison for single-character inputs and is a common ZX81 BASIC idiom.
Banner String B$
Line 30 builds a reusable prompt banner B$ consisting of a long row of block-graphic characters followed by the inverse-video text ENTER ANSWER. It is printed at the bottom of most input screens as a consistent UI element. At line 950 only the first 32 characters of B$ are printed (B$( TO 32)), omitting the text portion when only a visual divider is needed.
Score and Save
The score accumulator S is reset to 0 at line 1200 (after display) so the quiz can be repeated without restarting. If the user opts to save, line 1230 executes SAVE "QUIZ-64K" which saves the entire program including the populated data arrays, allowing the completed quiz to be reloaded and retaken. Line 1250 (SAVE "1018%9") and line 1260 (RUN) appear to be a secondary save/restart block that would only be reached by a direct GO TO 1250; they are unreachable in normal flow.
Notable Bugs and Anomalies
- Line 530:
IF CODE D$<=28 OR CODE D$>=3 THEN GOTO 600— the conditionCODE D$>=3is always true for any printable character, so the explanation-entry block (lines 540–590) is never reached. The intended condition was probablyCODE D$>=30(mirroring line 140), meaning “skip if D$≠’1′”. - Line 400/410:
A(F,2)=A(F,1)+HandA$(A(F,1) TO A(F,1)+H)=E$— the slice written is H+1 characters wide (inclusive both ends), butA(F,2)is set toA(F,1)+H, so when reading back at line 940 the sliceA$(A(C,1) TO A(C,2)-1)is only H characters. This off-by-one means the last character of each stored string is effectively ignored during playback. - Line 250:
LET E=42022is a hard-coded constant labelled as “total character input”; it bears no computed relationship toA(number of questions) but is used to display an “average characters per question” figure, so this is cosmetic only. - Line 170: serves as a re-entry point for the choices-count screen; jumping here from line 215 on invalid input is correct, but it also re-runs
CLSand skips re-printing the number-of-questions prompt, which could confuse a user who enters 10 or more choices.
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=42022
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)
281 DIM A$(10505,4)
282 LET L=PEEK 16400+256*PEEK 16401
283 POKE L+1,41
284 POKE L+2,164
285 POKE L+3,1
286 POKE L+4,38
287 POKE L+5,164
288 POKE L+6,0
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-64K"
\n1240 GOTO 830
\n1250 SAVE "1018%9"
\n1260 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
