Circuit Board Scramble

Date: 1984
Type: Program
Platform(s): TS 2068
Tags: Game

Circuit Board Scramble is a maze-navigation game in which the player guides a character around a circuit board diagram to reach target components such as the voltage regulator, ULA, RAM, ROM, CPU, and edge connector. The program loads machine code from tape at addresses 39694 and 51450, using USR calls throughout to handle joystick input, sound, scoring, and sprite movement. Player position and score are tracked via POKEs and PEEKs into specific machine code data areas around address 40000–40800, with the high score stored at addresses 39800–39802 across sessions using INPUT prompts. The keyboard control option lets the player define four custom keys, whose character codes are POKEd directly into the machine code routine at addresses 39844–39859. A scrolling ticker-tape message at line 3030–3070 is implemented in BASIC by printing successive 8-character substrings of a padded string.


Program Analysis

Program Structure

The program is divided into several functional regions that do not follow a simple top-to-bottom flow. The loader block (lines 8000–8090 in the first group) sets up the screen, loads a splash graphic and a main BASIC/code file, then saves a combined loader. The main game logic occupies lines 1–4660, with high-numbered lines (8000–8640) reserved for diagnostics, error handling, and keyboard configuration. Control flow is driven entirely by GO TO and GO SUB rather than structured loops.

Loading Sequence

On startup the loader displays a progress bar of colored block characters (line 2, using \:: █ graphics in six ink colors), then loads two machine code blocks: “pc” CODE at address 51450 for 14000 bytes, and “code” CODE at 39694 for 5106 bytes. An ON ERR GO TO 8200 at line 37 guards the second load. After loading, a flashing “TURN OFF TAPE PLAYER” notice is shown for about seven seconds (PAUSE 350).

Machine Code Integration

Almost all real-time activity is delegated to machine code via USR calls. The key entry points are:

  • USR 51470 — screen/display refresh (called as c1=USR 51470 or l=USR 51470)
  • USR 39694 — joystick read, returns direction code stored in i
  • USR 39840 — keyboard handler (called when INKEY$<>"")
  • USR 40363 — collision/pickup sound effect
  • USR 40381 — component connection sound/score update
  • USR 40420 — timer encoding helper (packs t or e into a 16-bit POKE pair first)
  • USR 44490, USR 44520 — level-transition effects
  • USR 58420 — transition to circuit-board sub-game

The return value of most USR calls is assigned to a throwaway variable (l, c1, n, c, m) simply to satisfy BASIC’s expression syntax; the real effect is a side effect inside the machine code.

Game Phases

The game has two distinct phases. Phase 1 (lines 995–1080) is a countdown timer maze: the player navigates toward screen position x=14, y=11 while a timer t counts down. Phase 2 (lines 1990–2090 and 1500–1598) is a circuit-board component hunt: a randomly selected target component flashes on screen and the player must reach it. Transition between phases is managed by score thresholds checked at line 2705/2710 and by the co counter reaching 350 (line 2042).

Movement Dispatch

Player movement does not use a conventional IF i=... THEN block. Instead, the joystick/keyboard machine code routine at USR 39694 or USR 39840 appears to directly GO TO one of four handler lines by manipulating the BASIC interpreter’s program counter. The four directional handlers for Phase 1 are at lines 1101, 1141, 1181, and 1221; for Phase 2 at 2101, 2141, 2181, and 2221; for the circuit-board sub-game at 1600, 1640, 1680, and 1720. Each handler updates x or y, checks the cell attribute for the value 59 (INK 3, PAPER 7, BRIGHT 1 — a highlighted tile), prints the appropriate UDG character, erases the previous cell, then jumps back to the main loop.

UDG Characters

Four UDG characters are used for the player sprite, referenced as \a (left-facing), \b (down-facing), \c (right-facing), and \e (up-facing). Their bitmaps are defined by the machine code POKEd at startup — the BASIC listing never calls POKE USR directly in visible lines, implying the UDGs are set up inside the loaded machine code block.

Score and High Score Storage

The live score is maintained in machine code memory: address pair 40418/40419 holds the current score as a 16-bit little-endian value, read via PEEK 40418+256*PEEK 40419. The high score is stored at 39801/39800 (note reversed byte order for the high score vs. score) and the associated level at 39802. On game start the player is prompted to enter the previous high score, which is split into low and high bytes and POKEd manually (line 43).

Difficulty and Timer

Lines 131–136 map the chosen difficulty level (0–5) to a starting timer value t ranging from 550 to 800. At line 3500, each time the player completes 350 component connections (co>349), the timer is reduced by 50 to a minimum of 450, increasing difficulty progressively. The level value is also POKEd into a range of machine code addresses (40301 to 40391, step 9) at lines 100–120.

Scrolling Message Ticker

When a random component task is assigned (r < 10, line 2044), a subroutine at line 3000 builds a long string a$ describing the target. Lines 3030–3070 pad it with spaces and scroll it across 8 columns at row 8 by printing successive substrings a$(w TO w+7) with a PAUSE 10 between each, a clean software ticker-tape effect entirely in BASIC.

Keyboard Configuration

Lines 8600–8635 allow the player to define custom keys for all four directions. Each key’s CODE value is POKEd directly into the machine code at hardcoded addresses: left=39844, down=39849, up=39854, right=39859. This means the machine code reads key codes from RAM rather than having them compiled in, providing a simple but effective remapping mechanism.

Error Handling

Lines 8200–8230 implement a retry loop for tape-load errors using ON ERR: on error the system is reset via ON ERR RESET, pauses briefly, then re-arms the error trap and resumes with ON ERR CONTINUE. This guards the potentially unreliable tape load of “code” at line 37.

Anomalies and Notes

  • Line 1340 uses GO TO 1320, but line 1320 does not exist in the listing; this creates a tight busy-wait loop that effectively polls INKEY$ at lines 1330/1334 until a key is pressed, which is an intentional (if undocumented) technique.
  • Line 2700 is targeted by GO TO 2700 at lines 1075 and 1596, but the listing shows line 2705 as the first line in that region — line 2700 does not appear, so execution falls through to 2705, which is the intended behavior.
  • The diagnostic block at the second set of lines 8000–8030 (which conflicts with the loader’s 8000–8090 line numbers) prints raw PEEK values for addresses 30390–30460 and then STOPs — this appears to be a debugging fragment left in the listing.
  • The 16-bit score is stored with the low byte at 40418 and high byte at 40419, but the high score uses reversed addressing (low byte at 39801, high byte at 39800), an asymmetry that would cause the high score display to be byte-swapped relative to the live score if both exceed 255.

Content

Appears On

Related Products

Have fun and learn about computer components at the same time. Run the friendly bug through the circuit board maze...

Related Articles

Related Content

Image Gallery

Source Code

 8000 INK 0
 8010 PAPER 0
 8020 BORDER 0
 8030 PRINT AT 15,0;" "
 8040 CLEAR 39799
 8050 LOAD "zman"SCREEN$ 
 8060 PRINT INK 1;AT 16,9;"\::"
 8070 LOAD "zman"
 8080 PRINT AT 15,0;" "
 8090 SAVE "cb" LINE 8000
    1 GO TO 40
    2 PRINT INK 2;AT 16,10;"\::"; INK 3;AT 16,11;"\::"; INK 4;AT 16,12;"\::"
   13 LOAD "pc"CODE 51450,14000
   16 PRINT INK 5;AT 16,13;"\::"; INK 6;AT 16,14;"\::"; INK 7;AT 16,15;"\::"
   37 LOAD "code"CODE 39694,5106: ON ERR GO TO 8200
   38 PRINT INK 0; PAPER 7; BRIGHT 1; FLASH 1;AT 15,8;"TURN  OFF";AT 16,7;"TAPE PLAYER"
   39 PAUSE 350
   40 LET c1=USR 51470
   42 INPUT "PREVIOUS HIGH SCORE  ";hs
   43 POKE 39801,hs-(INT (hs/256))*256: POKE 39800,INT (hs/256)
   44 INPUT "LEVEL OF PLAY  0 - 5  ";lp
   45 POKE 39802,lp
   48 INK 2
   50 PAPER 7
   56 BORDER 1
   59 CLS 
   60 LET c1=USR 51470
   65 POKE 40418,0: POKE 40419,0
   70 LET e=0
   80 LET score=0
   89 POKE 40403,1
   90 INPUT "INPUT YOUR LEVEL  0 - 5  ";dur
  100 FOR f=40301 TO 40391 STEP 9
  110 POKE f,dur
  120 NEXT f
  131 IF dur=0 THEN LET t=550
  132 IF dur=1 THEN LET t=600
  133 IF dur=2 THEN LET t=650
  134 IF dur=3 THEN LET t=700
  135 IF dur=4 THEN LET t=750
  136 IF dur=5 THEN LET t=800
  141 IF dur>5 OR dur<0 THEN GO TO 90
  150 LET time=t
  160 LET retime=t
  200 INPUT "ENTER   JOYSTICK j   KEYS  k "; LINE m$
  205 IF m$="j" THEN GO TO 250
  208 IF m$="k" THEN GO TO 8600
  210 GO TO 200
  240 REM  1983 by Ken Frink
  250 GO TO 950
  900 LET t=retime
  910 INK 2
  912 PAPER 7
  914 BORDER 1
  916 CLS 
  920 LET l=USR 51470
  930 LET score=0
  940 POKE 40418,0: POKE 40419,0
  950 FOR f=1 TO 200
  960 NEXT f
  970 GO SUB 4500
  995 POKE 40793,0
  997 POKE 40403,1
 1000 LET y=12
 1005 LET x=20
 1010 PRINT AT y-2,x-2;"\c"
 1020 LET t=t-1
 1021 IF t<1 THEN GO TO 1250
 1022 PRINT INK 0;AT 20,18;"\::";t;"\::"
 1025 IF INKEY$<>"" THEN LET l=USR 39840
 1030 IF m$="j" THEN LET i=USR 39694
 1060 PRINT AT 20,4;PEEK 40418+256*PEEK 40419
 1070 IF (PEEK 40418+256*PEEK 40419)-score>=287 THEN POKE 40793,1
 1075 IF x=14 AND y=11 THEN GO TO 2700
 1080 GO TO 1020
 1101 LET x=x-1: IF ATTR (y-2,x-2)=59 THEN LET l=USR 40363
 1105 PRINT AT y-2,x-2;"\a";AT y-2,x-1;" ": GO TO 1020
 1141 LET y=y+1: IF ATTR (y-2,x-2)=59 THEN LET l=USR 40363
 1145 PRINT AT y-2,x-2;"\b";AT y-3,x-2;" ": GO TO 1020
 1181 LET y=y-1: IF ATTR (y-2,x-2)=59 THEN LET l=USR 40363
 1185 PRINT AT y-2,x-2;"\e";AT y-1,x-2;" ": GO TO 1020
 1221 LET x=x+1: IF ATTR (y-2,x-2)=59 THEN LET l=USR 40363
 1225 PRINT AT y-2,x-2;"\c";AT y-2,x-3;" ": GO TO 1020
 1250 FOR f=1 TO 20
 1260 LET c1=USR 51470
 1270 CLS 
 1280 NEXT f
 1282 PRINT AT 5,5;"PREVIOUS HIGH ";PEEK 39801+256*PEEK 39800;AT 6,12;"LEVEL ";PEEK 39802
 1285 PRINT AT 9,5;"YOUR SCORE IS ";PEEK 40418+256*PEEK 40419;AT 10,12;"LEVEL ";dur
 1290 IF PEEK 40418+256*PEEK 40419>PEEK 39801+256*PEEK 39800 THEN POKE 39801,PEEK 40418: POKE 39800,PEEK 40419: POKE 39802,dur: PRINT AT 13,8;"CONGRATULATIONS","     YOU HAVE JUST BECOME","      CHAMP OF THE CHIPS": GO TO 1310
 1310 PRINT AT 17,0;" PRESS THE G KEY FOR ANOTHER GO"
 1315 PRINT AT 19,0;" PRESS THE B KEY TO CHANGE GAME"
 1330 IF INKEY$="g" THEN GO TO 900
 1334 IF INKEY$="b" THEN GO TO 48
 1340 GO TO 1320
 1350 GO TO 900
 1400 REM CIRCUIT BOARD SCRAMBLE \* 1983 BY KEN FRINK      
 1500 PAPER 7
 1510 BORDER 1
 1520 LET l=USR 51470
 1525 GO SUB 4600
 1530 LET y=12: LET x=20
 1535 PRINT AT 20,4;PEEK 40418+256*PEEK 40419
 1540 PRINT AT y-2,x-2;"\c"
 1542 POKE 40793,0
 1545 PRINT INK 2; BRIGHT 1; FLASH 1;AT te-2,as-2;"*"
 1550 LET e=e-1: IF e<1 THEN GO TO 1250
 1560 PRINT INK 0;AT 20,18;"\::";e;"\::"
 1570 IF INKEY$<>"" THEN LET l=USR 39840
 1580 LET i=USR 39694
 1595 IF x=as AND y=te THEN POKE 40793,1
 1596 IF x=14 AND y=11 THEN GO TO 2700
 1598 GO TO 1550
 1600 LET x=x-1: PRINT AT y-2,x-2;"\a";AT y-2,x-1;" ": GO TO 1550
 1640 LET y=y+1: PRINT AT y-2,x-2;"\b";AT y-3,x-2;" ": GO TO 1550
 1680 LET y=y-1: PRINT AT y-2,x-2;"\e";AT y-1,x-2;" ": GO TO 1550
 1720 LET x=x+1: PRINT AT y-2,x-2;"\c";AT y-2,x-3;" ": GO TO 1550
 1990 LET p=1100
 2000 POKE 40426,t-256*INT (t/256): POKE 40427,INT (t/256): LET m=USR 40420: LET t=0
 2001 INK 2
 2002 PAPER 6
 2004 BORDER 3
 2005 LET y=23: LET x=18
 2007 POKE 40403,2
 2010 PRINT INK 2;AT y-2,x-2;"\e"
 2015 POKE 39869,240: POKE 39870,122: POKE 39901,126: POKE 39902,123: POKE 39960,18: POKE 39961,124: POKE 39931,166: POKE 39932,124: POKE 39990,58: POKE 39991,125: POKE 39998,41: POKE 39999,164
 2030 PRINT PAPER 6; FLASH 1;AT 21,15;"\::"
 2040 LET p=p-1: LET e=e-1: LET r=INT (RND*1500)
 2041 IF p<1 THEN GO TO 1250
 2042 IF co>349 THEN GO TO 3500
 2044 IF r<10 THEN GO SUB 3000
 2050 IF INKEY$<>"" THEN LET l=USR 39840
 2060 IF m$="j" THEN LET i=USR 39694
 2080 PRINT INK 0; PAPER 7; BRIGHT 1;AT 13,13;PEEK 40418+256*PEEK 40419
 2085 IF y=23 AND x=17 THEN GO TO 2500
 2090 GO TO 2040
 2101 LET x=x-1: IF ATTR (y-2,x-2)=52 THEN LET n=USR 40381: LET co=co+1
 2105 PRINT AT y-2,x-2;"\a";AT y-2,x-1;" ": GO TO 2040
 2141 LET y=y+1: IF ATTR (y-2,x-2)=52 THEN LET n=USR 40381: LET co=co+1
 2145 PRINT AT y-2,x-2;"\b";AT y-3,x-2;" ": GO TO 2040
 2181 LET y=y-1: IF ATTR (y-2,x-2)=52 THEN LET n=USR 40381: LET co=co+1
 2185 PRINT AT y-2,x-2;"\e";AT y-1,x-2;" ": GO TO 2040
 2221 LET x=x+1: IF ATTR (y-2,x-2)=52 THEN LET n=USR 40381: LET co=co+1
 2225 PRINT AT y-2,x-2;"\c";AT y-2,x-3;" ": GO TO 2040
 2500 LET c=USR 44520
 2530 GO TO 1500
 2705 IF (PEEK 40418+256*PEEK 40419)-score>289 THEN LET c=USR 44490: GO TO 2730
 2710 IF (PEEK 40418+256*PEEK 40419)-score<288 THEN LET c=USR 58420: LET co=0: GO TO 1990
 2730 POKE 40426,e-256*INT (e/256): POKE 40427,INT (e/256): LET m=USR 40420: LET e=0
 2740 GO TO 2001
 3000 LET b$="***  GO TO CIRCUIT BOARD AND CHECK "
 3001 IF r=0 THEN LET a$=b$+"VOLTAGE REGULATOR  ***": LET as=33: LET te=18
 3002 IF r=1 THEN LET a$=b$+"UNCOMMITTED LOGIC ARRAY  ***": LET as=14: LET te=3
 3003 IF r=2 THEN LET a$=b$+"32 K RANDOM ACCESS MEMORY  ***": LET as=2: LET te=23
 3004 IF r=3 THEN LET a$=b$+"READ ONLY MEMORY  ***": LET as=29: LET te=3
 3005 IF r=4 THEN LET a$=b$+"CENTRAL PROCESSOR UNIT  ***": LET as=25: LET te=3
 3006 IF r=5 THEN LET a$=b$+"TV MODULATOR  ***": LET as=2: LET te=2
 3007 IF r=6 THEN LET a$=b$+"LOUDSPEAKER  ***": LET as=33: LET te=23
 3008 IF r=7 THEN LET a$=b$+"9 VOLT INPUT  ***": LET as=33: LET te=5
 3009 IF r=8 THEN LET a$=b$+"EDGE CONNECTOR  ***": LET as=31: LET te=2
 3010 IF r=9 THEN LET a$=b$+"CASSETTE INPUT  ***": LET as=9: LET te=2
 3015 PRINT PAPER 7;AT 13,12;"        "
 3020 PRINT INK 2; PAPER 7; BRIGHT 1; FLASH 1;AT 13,14;p
 3030 LET a$="         "+a$+"         "
 3040 LET e=150: LET b=LEN (a$)-8
 3050 FOR w=1 TO b
 3060 PRINT INK 2; PAPER 7; BRIGHT 1;AT 8,12;a$(w TO w+7): PAUSE 10
 3070 NEXT w
 3075 PRINT PAPER 7;AT 13,12;"        "
 3080 RETURN 
 3500 LET t=time-50
 3505 LET time=t
 3510 IF t<450 THEN LET t=450
 3520 LET c1=USR 51470
 3530 LET score=PEEK 40418+256*PEEK 40419
 3540 INK 2
 3550 PAPER 7
 3555 BORDER 1
 3557 GO SUB 4500
 3560 GO TO 995
 4500 POKE 39869,252: POKE 39870,110
 4510 POKE 39901,190: POKE 39902,111
 4520 POKE 39960,67: POKE 39961,112
 4530 POKE 39931,200: POKE 39932,112
 4540 POKE 39990,77: POKE 39991,113
 4550 POKE 39998,129: POKE 39999,159
 4560 RETURN 
 4600 POKE 39869,94: POKE 39870,118
 4610 POKE 39901,185: POKE 39902,118
 4620 POKE 39960,9: POKE 39961,119
 4630 POKE 39931,89: POKE 39932,119
 4640 POKE 39990,169: POKE 39991,119
 4650 POKE 39998,129: POKE 39999,159
 4660 RETURN 
 8000 FOR f=30390 TO 30460
 8010 PRINT f;"  ";PEEK f
 8020 NEXT f
 8030 STOP 
 8200 ON ERR RESET 
 8210 PAUSE 100
 8220 ON ERR GO TO 8200
 8230 ON ERR CONTINUE 
 8400 IF INKEY$<>"" THEN LET i=USR 39840
 8500 DIM s(2)
 8510 DIM d(11,14)
 8530 STOP 
 8600 INPUT "KEY FOR UP MOTION  ";U$
 8605 POKE 39854,CODE U$
 8610 INPUT "KEY FOR DOWN MOTION  ";D$
 8615 POKE 39849,CODE D$
 8620 INPUT "KEY FOR LEFT MOTION  ";L$
 8625 POKE 39844,CODE L$
 8630 INPUT "KEY FOR RIGHT MOTION  ";R$
 8635 POKE 39859,CODE R$
 8640 GO TO 250

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top