World Geography is an educational quiz program that tests knowledge of countries, islands, continents, oceans, and seas by flashing their locations on a world map displayed using ZX81 block graphics. The program operates in two modes: a review mode (option 1) that names each location while highlighting it, and an identify mode (option 2) that prompts the player to type the name from memory. A machine code routine stored in REM line 1 handles smooth scrolling of the map display, accessed via USR calls to calculated addresses based on the DFILE pointer at address 16396/16397. Coordinates for each of the 19 countries/islands or 17 geographic features are packed as two-byte entries in a string array P$, with screen positions encoded as raw character codes including values above 128 that are sign-extended by subtracting 256 to give signed offsets.
Program Analysis
Program Structure
The program is divided into several logical phases:
- Initialisation (lines 1–40): A machine code routine is embedded in REM line 1. Key system addresses are computed:
DF(display file address),GET(a custom keypress-reading routine offset), andM(the fixed address 16540 for the map scroll routine). - Mode selection (lines 100–210): The player chooses Review (1) or Identify (2), then chooses Countries/Islands (A) or Continents/Oceans/Seas (B).
- Data loading (lines 1000–1110 and 2000–2100): Two parallel string arrays,
N$(names) andP$(map positions), are built from packed string literalsA$using fixed-stride slicing. - Quiz loop (lines 5000–5520): Items are presented in random non-repeating order. The map is scrolled to the correct position, the location is flashed, and in Identify mode the player’s typed answer is checked.
Machine Code Usage
REM line 1 contains a substantial Z80 machine code payload. It is invoked in three distinct ways:
USR GET— reads the current keypress and stores it inG$; returns 0 (false) if no key is pressed, enabling the polling loops at lines 112 and 200.USR M(address 16540) — scrolls the map one step; called in loops at lines 5012–5014, 5080–5100, and 5130–5134 to pan horizontally and vertically.USR 16875at line 5140 — performs a separate map operation (likely resetting or returning a status value used by the flash routine).
The address GET is dynamically computed as DF - 289, tying the routine’s entry point to the current display file location. This is a common ZX81 technique to make code position-independent relative to the BASIC/display file boundary.
Coordinate Encoding
Map positions are stored in P$(A) as two raw bytes. The first byte (accessed via CODE P$(D)) encodes the horizontal offset; the second byte (CODE P$(D,2)) encodes the vertical offset Y. Values above 128 are treated as negative by subtracting 256 at line 5065, giving a signed range of approximately −128 to +127. This compact two-byte encoding avoids the overhead of storing integer variables for each location.
Data Packing
Names and coordinates are stored in long string literals A$ and sliced into fixed-length arrays using a stride loop. For countries/islands, LN=17 (name length) and NN=19 (count); for geographic features, LN=18 and NN=17. The slice expression N$(A)=A$(1+LN*(A-1) TO ) relies on ZX81 string-array assignment truncating to the declared field width, neatly packing each name. CHR$ calls are used for characters that cannot be typed directly in the source editor.
Randomisation and Non-Repeating Order
A tracking array T$(NN) is used at lines 5016–5034 to avoid repeating items within a round. Each element starts as a null character (code 0); when an item is shown, T$(D) is set to "1". The test IF CODE T$(D) THEN GOTO 5030 re-draws a random index until an unseen one is found. When CT=NN the round restarts, re-dimensioning T$ implicitly resets it (via GOTO 5000 which re-executes DIM T$).
Map Flashing Technique
Lines 5190–5240 implement a flash effect at the map location. The display file address B is computed from DF, the row offset A (derived from Y), and a column of 33 characters per row. The character at B is read into F; a “complement” value C is computed as either 23 or 23+128 depending on whether the original character has bit 7 set (i.e., is already inverse). The cell is then toggled between C and F fifteen times in a short delay loop, producing a visible flash.
Scrolling Control
The POKE sequence at lines 5000–5004 initialises the scroll state. POKE 16522 at lines 5070 and 5120 sets the scroll direction: value 34 = right, 36 = left (or similar encoding). The number of scroll steps is computed from the difference between the current and target coordinates, with wrap-around logic handling the case where going the other way around the map is shorter (the B>0 AND B<42 OR B<-42 condition at line 5120).
Notable BASIC Idioms
IF USR M THEN REM— calls machine code but discards any return value; theREMacts as a no-op target. TheIFcondition is always evaluated, ensuring the USR call executes every iteration.FOR A=1 TO ABS(...)with empty body — used as a delay loop and also as a counted scroll loop, with the loop variable serving double duty.LET G$=G$( TO USR GET)at line 5260 — uses the machine code return value as a string slice length to extract exactly the typed portion of the padded answer string.- Lines 5010–5014 call
USR Mfour times per iteration over eight iterations (32 total) — likely performing an initial map setup or centering scroll before the quiz begins.
Possible Anomalies
- Line 5180 computes
B=DF+412+33*A*(Y<1 OR Y>26): the multiplication by a boolean condition means that whenYis out of range 1–26,Bjumps by 33×A, which could point outside valid display memory. This may be intentional (off-map items skip the flash) or a latent boundary issue. - The coordinate data in
P$is built from raw character codes embedded in string literals, some viaCHR$and some as literal block-graphic escape sequences. The mixing of methods makes the data difficult to audit without running the code. - REM line 2 contains what appears to be a garbled BASIC listing artifact — its tokens do not form valid statements and are likely the residue of a previously different line or an encoding artifact from the file format.
Content
Source Code
1 REM 3C5B5163 0 03B1A213E6F327A4132C6413E6732874132D341C93E67327A4132C6413E6F32874132D341ED5B C403A8A40CB4F282CCB473A894020 FFE1AC83C2121 019 1F7 2EDB0185BFE 0C83D2117 319545D 121 0ED42 1F7 2EDB81845 6 0CB473A8840201C3CFE5520 1AF32884013626B233E18 E1FEDB0232313133D20F518233DFEFF20 23E543288402117 319545D2B3E18 E1FEDB82B2B1B1B3D20F518 3328940ED4B8840 43A8A40FE2220 43E17804711C3 92A C40AFED521155 0C578D61AC138 53C47CD8B401910FDE5 93A8A40CB4F282FE52A C4023CB4720 411F7 219EBE1 6203E56 CB920 2E1E5AFED6FEB77CB5F28 4CBFECB9EEBED67231310E4C1C9C1ED4B8840CB4720 D3E1F5F19811E55BB38 3ED5237E52A C402330 31E1F19EBE148 61818 F3E19B920 ACD8B40D5114D 8ED52D1AFED6FEB77CB5F28 4CBFECB9EEBED67D51155 019E31E2119D1EB C10D3C9
2 REM M$5 DIM INKEY$6-RNDLN 0)777 FAST E£RND)7 ;SGN ' 3 GOSUB %K7:4 GOSUB %KTAN
4 REM *** :%W%O%R%L%D% %G%E%O%G%R%A%P%H%Y: *** BY SHAWN BYRNE
5 RAND
7 SLOW
10 LET DF=PEEK 16396+256*PEEK 16397
20 LET GET=DF-289
30 LET M=16540
40 LET M$=" "
100 PRINT "DO YOU WANT TO ";TAB 2;"%1-REVIEW";TAB 2;"%2-IDENTIFY";AT 4,2;"PRESS 1 OR 2";AT 4,0;
110 LET G$=" "
112 IF NOT USR GET THEN GOTO 112
113 REM 1,2
120 PRINT AT 4,2;" "
130 LET O$=G$
190 PRINT AT 9,0;"CHOOSE";TAB 2;"%A-COUNTRIES AND ISLANDS";TAB 2;"%B-CONTINENTS, OCEANS, AND SEAS";AT 13,2;"PRESS A OR B";AT 13,0;
200 IF NOT USR GET THEN GOTO 200
202 REM A,B
210 CLS
220 LET C$=G$
240 IF C$="B" THEN GOTO 2000
1000 LET LN=17
1002 LET NN=19
1016 DIM N$(NN,LN)
1018 LET A$="FRANCE .'ITALY : BRITISH ISLES $CANADA .'MEXICO .'NORWAY .'SPAIN : INDIA : SAUDI ARABIA £GRENADA :'FALKLAND ISLANDS(GREENLAND ,,JAPAN : CUBA . NEWFOUNDLAND £NEW ZEALAND "+CHR$ 11+"HAWAII .'ICELAND :'INDONESIA ,,"
1020 FOR A=1 TO NN
1030 LET N$(A)=A$(1+LN*(A-1) TO )
1040 NEXT A
1060 DIM P$(NN,2)
1070 LET A$=",. 1.'; '' ' ' $0 RETURN ;.'H$9"+CHR$ 11+CHR$ 11+"?£8( SAVE W.'.'$£. "+CHR$ 69+"2"+CHR$ 72+":+ CLEAR S<"
1080 FOR A=1 TO NN
1090 LET P$(A)=A$(2*A-1 TO )
1100 NEXT A
1110 GOTO 5000
2000 LET LN=18
2002 LET NN=17
2016 DIM N$(NN,LN)
2018 LET A$="NORTH AMERICA $SOUTH AMERICA $AFRICA .'EUROPE .'ASIA . AUSTRALIA ,,PACIFIC OCEAN $ATLANTIC OCEAN :INDIAN OCEAN £ARCTIC OCEAN £MEDITERRANEAN SEA)GREAT LAKES "+CHR$ 11+"GULF OF MEXICO :RED SEA :'HUDSON BAY ~~BERING STRAIT $PERSIAN GULF £"
2020 FOR A=1 TO NN
2030 LET N$(A)=A$(1+LN*(A-1) TO )
2040 NEXT A
2060 DIM P$(NN,2)
2070 LET A$=CHR$ 84+".'"+CHR$ 11+",2<2''M''V,"+CHR$ 77+">:?H-"+CHR$ 72+" PLOT 2##: : . £8$: "+CHR$ 71+" CLEAR B"+CHR$ 11
2080 FOR A=1 TO NN
2090 LET P$(A)=A$(2*A-1 TO )
2100 NEXT A
5000 POKE 16520,0
5002 POKE 16521,0
5004 POKE 16522,36
5010 FOR A=1 TO 8
5012 IF USR M OR USR M OR USR M OR USR M THEN REM
5014 NEXT A
5016 DIM T$(NN)
5018 LET CT=0
5030 LET D=INT (RND*NN)+1
5032 IF CODE T$(D) THEN GOTO 5030
5034 LET T$(D)="1"
5040 LET L$=N$(D, TO CODE N$(D,LN))
5060 LET Y=CODE P$(D,2)
5065 IF Y>128 THEN LET Y=Y-256
5070 POKE 16522,34+(Y<PEEK 16521)
5080 FOR A=1 TO ABS (Y-PEEK 16521)
5090 IF USR M THEN REM
5100 NEXT A
5110 LET B=PEEK 16520-CODE P$(D)
5120 POKE 16522,36-3*(B>0 AND B<42 OR B<-42)
5130 FOR A=1 TO ABS (85*(ABS B>42)-ABS B)
5132 IF USR M THEN REM
5134 NEXT A
5140 LET A=USR 16875
5160 PRINT AT 1,1;
5165 IF O$="1" THEN PRINT L$
5170 LET A=Y-26*(Y>26)
5180 LET B=DF+412+33*A*(Y<1 OR Y>26)
5190 LET F=PEEK B
5200 LET C=23+128*(F>127)
5210 FOR A=1 TO 15
5220 POKE B,C
5225 FOR D=1 TO 2
5226 NEXT D
5230 POKE B,F
5240 NEXT A
5245 IF O$="1" THEN GOTO 5500
5250 LET G$=L$+" "
5260 LET G$=G$( TO USR GET)
5262 REM A-Z,
5270 IF L$<>G$ THEN GOTO 5300
5280 LET A=INT (RND*3)*6+1
5282 PRINT AT 2,1;"RIGHT.GREAT.SUPER."(A TO A+5)
5290 FOR A=1 TO 12
5292 NEXT A
5295 GOTO 5500
5300 PRINT AT 2,1;"NO, THIS IS ";L$;"."
5310 FOR A=1 TO 35
5312 NEXT A
5500 LET CT=CT+1
5502 IF CT=NN THEN GOTO 5000
5510 PRINT AT 1,1;M$
5520 GOTO 5030
9998 SAVE "GE%O"
9999 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.


