--- title: "World Geography" id: 56746 type: "computer_media" slug: "world-geography" url: "http://localhost/computer_media/world-geography/" markdown_url: "http://localhost/computer_media/world-geography.md" published_at: "2024-09-22T23:31:59+00:00" modified_at: "2026-04-03T07:58:54+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/GEO1.jpeg" excerpt: "A two-mode world geography quiz flashes country and ocean locations on a block-graphics map, challenging you to identify them by name using a hidden machine code engine." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" indiv: - name: "Shawn Byrne" slug: "shawn-byrne" taxonomy: "indiv" url: "http://localhost/indiv/shawn-byrne/" genre: - name: "Education" slug: "education" taxonomy: "genre" url: "http://localhost/type/education/" media_type: "Program" programmers: - name: "Shawn Byrne" slug: "shawn-byrne" taxonomy: "indiv" url: "http://localhost/indiv/shawn-byrne/" download_url: "https://archive.org/download/timex-sinclair-software-archive/World%20Geography%20%28198x%29%28S%20Byrne%29%28TS1000%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/09/GEO1.jpeg" - url: "http://localhost/wp-content/uploads/2024/09/GEO2.jpeg" - url: "http://localhost/wp-content/uploads/2024/09/GEO.jpg" media_type_tags: "Education" --- # World Geography 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: 1. **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), and `M` (the fixed address 16540 for the map scroll routine). 2. **Mode selection (lines 100–210):** The player chooses Review (1) or Identify (2), then chooses Countries/Islands (A) or Continents/Oceans/Seas (B). 3. **Data loading (lines 1000–1110 and 2000–2100):** Two parallel string arrays, `N$` (names) and `P$` (map positions), are built from packed string literals `A$` using fixed-stride slicing. 4. **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 in `G$`; 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 16875` at 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; the `REM` acts as a no-op target. The `IF` condition 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 M` four 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 when `Y` is out of range 1–26, `B` jumps 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 via `CHR$` 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. ## Source Code ``` 1 REM 3C5B5163003B1A213E6F327A4132C6413E6732874132D341C93E67327A4132C6413E6F32874132D341ED5BC403A8A40CB4F282CCB473A894020FFE1AC83C21210191F72EDB0185BFE0C83D2117319545D1210ED421F72EDB8184560CB473A8840201C3CFE55201AF32884013626B233E18E1FEDB0232313133D20F518233DFEFF2023E543288402117319545D2B3E18E1FEDB82B2B1B1B3D20F5183328940ED4B884043A8A40FE222043E17804711C392AC40AFED5211550C578D61AC13853C47CD8B401910FDE593A8A40CB4F282FE52AC4023CB4720411F7219EBE16203E56CB9202E1E5AFED6FEB77CB5F284CBFECB9EEBED67231310E4C1C9C1ED4B8840CB4720D3E1F5F19811E55BB383ED5237E52AC40233031E1F19EBE14861818F3E19B920ACD8B40D5114D8ED52D1AFED6FEB77CB5F284CBFECB9EEBED67D51155019E31E2119D1EBC10D3C9 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+(Y0 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 ```