--- title: "Brain Terrain" id: 57008 type: "computer_media" slug: "brain-terrain" url: "http://localhost/computer_media/brain-terrain/" markdown_url: "http://localhost/computer_media/brain-terrain.md" published_at: "2024-10-02T07:32:46+00:00" modified_at: "2026-04-03T07:58:44+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/32_BrnTerr.png" excerpt: "Crack a time-travel mystery by decoding memory zones — this adventure hides its clues in a clever delta-encoded string table with a scrolling marquee display." 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/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 56732 title: "Timex Sinclair Public Domain Library Tape 1001" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1001/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/32_BrnTerr.png" - url: "http://localhost/wp-content/uploads/2024/10/brain-terrain.jpeg" caption: "Glowing translucent human brain floating above a fractured alien landscape, time vortex swirling in background, futuristic text scrolling across holographic display panels, cracked terrain revealing pulsing circuit pathways beneath, dramatic low-angle perspective, vivid electric blues and purples against deep black, streaks of neon green and magenta, mysterious hooded figure silhouetted examining the brain, airbrush illustration style, bold saturated colors, ZX Spectrum cassette inlay art, hand-painted commercial art, British home computing aesthetic, circa 1983 --ar 3:4 --raw --v 6 Job ID: 8c8ad707-baaf-42c7-9d17-e32d652ef94a" media_type_tags: "Game" --- # Brain Terrain Brain Terrain is a text-based mystery/adventure game in which the player must identify a missing person’s home year by accessing memory zones labelled with single-letter keys (A, B, C, E, F, M, P, S, T, V). Each zone contains one or more encoded clues stored in a compressed string table; the player cycles through clues displayed with a scrolling marquee effect and ultimately guesses a four-digit year. Clue text is stored compactly in the string `T$` using a delta-encoding scheme where each character’s code is offset relative to the first character of each entry, with comma (CHR$ 26 in this context) as a delimiter. A help feature, unlocked only after a failed guess, reveals the last words heard by the character Mr. Winkler. *** ## Program Analysis ### Program Structure The program is divided into a main loop and three subroutines: 1. **Lines 5–350:** Initialisation — dimensions, string constants, and decompression of the clue table from `T$` into the array `A$`. 2. **Lines 360–860:** Main game loop — title display, zone selection, marquee display, guess handling, and help. 3. **Lines 1000–1130:** Subroutine `GOSUB 1000` — word-wrapping text printer that splits `R$` on `CHR$ 0` boundaries. 4. **Lines 2000–2020:** Subroutine `GOSUB 2000` — centred single-line printer using `TAB`. 5. **Line 3000:**`SAVE` statement (not reached during normal play). ### Delta-Encoded Clue Table All clue text is packed into the single string `T$` (line 180) and decompressed at startup (lines 190–340) into the three-dimensional string array `A$(11,4,22)`. The 11 zones have between 2 and 4 entries each, as specified by `L$="42232232222"`. Each entry is terminated by `CHR$ 26` (used here as a comma/delimiter sentinel — notably *not* a standard ASCII comma). The encoding scheme (lines 280–310) is a character-level delta code: - The first character of each raw entry sets a base value `C = CODE D$(1) - 27`. - Each subsequent character is stored as `N = CODE D$(Z) - C`, then adjusted modulo-36 via the expression `N + 36*((N<28) AND (N+C>27)) + 28*(N<0)` to keep values in a printable range. - The decoded character count is stored in byte 1 of each `A$(X,Y)` entry, so retrieval at line 600 uses `A$(FL,M)(2 TO CODE A$(FL,M,1))`. This encoding reduces the storage footprint of the clue strings and makes casual inspection of the source listing unrevealing. ### Scrolling Marquee Display Lines 430–490 implement a simple horizontally scrolling marquee for the currently selected clue. A padding string `S$` of 32 asterisks (built by doubling `"*"` five times at lines 120–150) and a blank string `B$` of 32 null bytes (CHR$ 0, similarly constructed) are used to pad `Q$` on both sides. The scroll offset `NS` is randomised each iteration (line 444–455): normally 1–3 characters, but after a failed guess (`M=1`) it ranges up to half the display width, creating a faster, more chaotic scroll. The previous line is erased by printing `B$` at row 18 before the new frame. ### Game Logic and Zone Keys Ten letter keys map to memory zones via `V$="ACVEFSBMPT"` (line 160). Pressing one selects a random clue from that zone (`M=INT(RND*VAL L$(FL)+1)`, line 590). Zone 11 is special: it holds the answer year in `A$(11,1)(2 TO 5)` and a hint phrase in `A$(11,2)(2 TO 21)`, but has no key assigned in `V$` — it is only accessed internally. | Key | V$ index | Clue count | | --- | --- | --- | | A | 1 | 4 | | C | 2 | 2 | | V | 3 | 2 | | E | 4 | 3 | | F | 5 | 2 | | S | 6 | 2 | | B | 7 | 3 | | M | 8 | 2 | | P | 9 | 2 | | T | 10 | 2 | ### Word-Wrap Subroutine The subroutine at line 1000 splits long strings stored in `R$` at `CHR$ 0` boundaries (not spaces). It searches backward from position `WL+1` for a null byte, prints the segment before it, then recurses via `GOTO 1000` with the remainder. This means the author must manually insert null bytes into message strings where line breaks are desired — a deliberate authoring convention rather than automatic word wrapping. ### Help Gate and Guess Flow The help key `H` is only advertised and active after the player has made at least one failed guess (`GW=1`, set at line 720). The help screen (lines 760–790) reveals the string stored in zone 11, entry 2 — a contextual hint. After either a failed guess or viewing help, `Q$` and `M` are reset (lines 800–810) and the game loops back to the title. ### Notable Techniques and Observations - The display width constant `WL=32` (line 50) is used throughout, making the layout logic easy to retarget to a different line length. - `E$=CHR$ 11` (line 90) is used in the instructions string as an inline formatting code, suggesting the display routine may interpret it, though no explicit handler is visible — it may simply render as a control character or be incidental. - The `FAST`/`SLOW` pair (lines 10, 350) confines the slow decompression loop to FAST mode, then returns to SLOW for display. - The `SAVE "1003%2"` at line 3000 uses an inverse-2 character in the filename, which on ZX81/TS1000 acts as an auto-run flag causing the program to execute immediately on `LOAD`. - The sentinel value `CHR$ 26` in `T$` (checked at line 250) is unusual — this is not a printable character, so it survives in the string literal without visual ambiguity but could be fragile if the listing is re-entered manually. ## Source Code ``` 5 REM %B%R%A%I%N% %T%E%R%R%A%I%N 10 FAST 20 RAND 30 DIM A$(11,4,22) 40 DIM N(11) 50 LET WL=32 60 LET GW=0 70 LET M=0 80 LET Q$="" 90 LET E$=CHR$ 11 100 LET B$=CHR$ 0 110 LET S$="*" 120 FOR X=1 TO 5 130 LET B$=B$+B$ 140 LET S$=S$+S$ 150 NEXT X 160 LET V$="ACVEFSBMPT" 170 LET L$="42232232222" 180 LET T$="A34L4TN,B4036NNUZS,HXSAB>BS3205Y,J32705Y,R72565,C2VOX$564V2R5,9XSQR 3,I51AA7A,R206,Q2FI54FD,50XX0ZGZOUT,PEHOD64,VSEJPANVNAAJ,WPTB7Q,I516C,F774SO(XA39Y3W,TA4LAFCHA,4MFGNY,EUO3P8X2V,FA5(Q3T(T4C3,HT6C55UO5Y,V0IEHEJC,HAEOAA>UZWWAW,MYE5FG8L,02A7A,D;$$$:6O0ZZ:67S3:$$$;," 190 LET P=1 200 FOR X=1 TO 11 210 FOR Y=1 TO VAL L$(X) 220 LET D$="" 230 LET D$=D$+T$(P) 240 LET P=P+1 250 IF T$(P)<>CHR$ 26 THEN GOTO 230 260 LET P=P+1 270 LET A$(X,Y)=CHR$ (LEN D$) 280 LET C=CODE D$(1)-27 290 FOR Z=2 TO LEN D$ 300 LET N=CODE D$(Z)-C 310 LET A$(X,Y)(Z)=CHR$ (N+36*((N<28) AND (N+C>27))+28*(N<0)) 320 NEXT Z 330 NEXT Y 340 NEXT X 350 SLOW 360 LET R$="THOUGHT RECORDER, MODEL XIV (PATENT PENDING)" 370 GOSUB 1000 380 PRINT 390 LET R$="PRESS A ZONE KEY(A, B, C, E, F, M, P, S, T, OR V)TO ACCESS MEMORY" 400 IF GW=1 THEN LET R$=R$+", "+E$+"H"+E$+" FOR HELP," 410 LET R$=R$+" OR "+E$+"G"+E$+" TO GUESS." 420 GOSUB 1000 430 LET TB=INT ((WL-LEN Q$)/2) 440 LET NS=INT (RND*3+1) 450 IF M=1 THEN LET NS=INT (RND*TB+1) 460 LET N$=S$( TO NS)+Q$+S$( TO NS) 470 PRINT AT 18,0;B$; 480 PRINT AT 18,0; 490 GOSUB 2000 500 LET K$=INKEY$ 510 IF K$="" THEN GOTO 440 520 IF K$="G" THEN GOTO 620 530 IF K$="H" AND GW=1 THEN GOTO 760 540 LET FL=0 550 FOR X=1 TO 10 560 IF V$(X)=K$ THEN LET FL=X 570 NEXT X 580 IF FL=0 THEN GOTO 440 590 LET M=INT (RND*VAL L$(FL)+1) 600 LET Q$=A$(FL,M)(2 TO CODE A$(FL,M,1)) 610 GOTO 430 620 CLS 630 LET N$="SPACE/TIME MACHINE ACTIVE." 640 GOSUB 2000 650 PRINT AT 4,0;"INPUT YEAR." 660 INPUT Y$ 670 IF Y$<>A$(11,1)(2 TO 5) THEN GOTO 720 680 CLS 690 PRINT AT 10,11;"WHOOOOSH." 700 PRINT AT 13,1;"SUBJECT RETURNED HOME SAFELY." 710 STOP 720 LET GW=1 730 CLS 740 PRINT AT 6,1;"FAILURE. INCORRECT TIME FRAME." 750 GOTO 800 760 CLS 770 LET R$="THE LAST WORDS MR.WINKLER HEARD WERE" 780 GOSUB 1000 790 PRINT AT 3,6;A$(11,2)(2 TO 21) 800 LET Q$="" 810 LET M=0 820 PRINT AT 20,2;"(PRESS ANY KEY TO CONTINUE.)" 830 LET K$=INKEY$ 840 IF K$="" THEN GOTO 830 850 CLS 860 GOTO 360 1000 IF LEN R$>WL THEN GOTO 1040 1010 LET N$=R$ 1020 GOSUB 2000 1030 RETURN 1040 LET J=WL+1 1050 FOR I=WL+1 TO 1 STEP -1 1060 IF R$(I)<>CHR$ 0 THEN GOTO 1090 1070 LET J=I 1080 LET I=1 1090 NEXT I 1100 LET N$=R$( TO J-1) 1110 GOSUB 2000 1120 LET R$=R$(J+1 TO LEN R$) 1130 GOTO 1000 2000 PRINT TAB (WL-LEN N$)/2;N$; 2010 IF LEN N$