This program implements a four-stage sheepdog trials game in which the player maneuvers a sheepdog UDG character to herd three sheep UDGs into a pen. Two UDG characters are defined at startup: a sheep (UDG “a”) and a dog (UDG “b”), loaded via a READ/POKE loop writing 32 bytes into USR “a” and USR “a”+8 through USR “a”+31. The movement engine in the subroutine at line 8000 supports both keyboard (T/Y/U/G/H/V/B/N) and joystick input via the STICK keyword, with collision detection using SCREEN$ to prevent the dog and sheep from walking through obstacles. Stage scoring counts down from 20 based on the number of move cycles elapsed, calculated at line 8020 as a decreasing function of the counter variable nm. Stage four requires all three sheep to occupy a specific rectangular pen region defined by character-cell coordinate bounds, checked at line 1440.
Program Analysis
Program Structure
The program is organized into four main game stages plus shared subroutines. Lines 10–240 handle initialization, UDG setup, and the instruction screen. Lines 250–545 implement Stage One (open field herding). Lines 570–860 cover Stage Two (pond obstacles). Lines 900–1200 handle Stage Three (a maze-like layout). Lines 1250–1600 implement Stage Four (pen herding). Three key subroutines appear at the end of the listing:
7000: A short musical fanfare using BEEP, played between stages.8000: The main movement and AI engine, called repeatedly as the game loop.9000: Stage initialization — reads starting coordinates for the dog and three sheep from DATA statements, places the UDGs, and resets counters.
Stage data is distributed across four DATA lines (9040–9070), one per stage, each containing the dog’s starting x/y and three sheep x/y pairs (eight values total).
UDG Definition
Lines 30–60 define two UDGs by POKEing 32 bytes into memory starting at USR "a". The loop runs a from 0 to 31, reading each byte and writing it to USR "a"+a, thus populating UDG “a” (sheep, 8 bytes) and UDG “b” (sheepdog, 8 bytes) as well as two further UDGs (“c” and “d”, used as obstacle/fence tiles). UDG characters are then referenced throughout PRINT statements using the zmakebas escape sequences \a, \b, \c, and \d.
Movement and Collision Detection (Subroutine 8000)
The movement engine at line 8000 is the heart of the program. It handles both the player-controlled dog and the AI-driven sheep in a single subroutine call per game-loop iteration.
Player input is read at line 8040 into a$. Lines 8050–8060 compute candidate new positions px and py by adding Boolean expressions (which evaluate to 0 or 1 in Sinclair BASIC) for each direction. Both keyboard letters and joystick values via STICK(1,1) (the | keyword) are checked simultaneously in a single expression, supporting the T/Y/U/G/H/V/B/N key layout as an approximated directional pad.
Collision detection uses SCREEN$ to test whether the target cell is a space character. The resolution order is:
- Try moving to
(py, px)— both axes. - If blocked, try sliding along the y-axis only (
(py, x)). - If still blocked, try sliding along the x-axis only (
(y, px)). - If all blocked, stay in place.
The same three-step slide resolution is applied to sheep movement at lines 8180–8215, with an additional random-walk escape (line 8210) that fires with probability 0.99 when all direct paths are blocked, moving the sheep one step in a random direction and retrying.
Sheep AI
Each sheep’s AI is driven by proximity to the dog. At line 8150, the squared distance d = dx*dx + dy*dy is computed. If d > 9 (more than ~3 cells away), the sheep does not move. An extra check at line 8165 prevents movement when d=9 and fewer than three sheep remain active (n<3), which is relevant to Stage Four’s “all sheep remain active until the last one is penned” rule. When within range, the sheep moves one step away from the dog using SGN dx and SGN dy.
Scoring System
A move counter nm is incremented at line 8000 on each call. The stage score ss is calculated at line 8020 as:
a = 20 - INT((nm - 50) / 40)
This gives a maximum of 20 points (for the first 50 moves), declining by 1 for each additional 40 moves, and clamped to 0 at line 8030. The total across four stages gives a maximum possible score of 80, referenced in the end screen at line 1560.
Stage Completion Logic
In Stages One through Three, sheep are removed from the active set when their y-coordinate drops below a threshold (rows 13 or 15 depending on stage), representing the pen at the bottom of the screen. The active count n is decremented by swapping the penned sheep’s data with the last active sheep’s data — a compact array-shrinking technique. In Stage Four, completion requires all three sheep to simultaneously satisfy x(a) > 12 AND x(a) < 17 AND y(a) > 9 AND y(a) < 13 (line 1440), checked by counting qualifying sheep into ct.
Notable Techniques
- The
POKE 23692,255calls (lines 500, 810, 1520) reset the scroll prompt counter, preventing “scroll?” from appearing during rapid PRINT output. - The Stage One field includes a curved fence drawn with
DRAWarc commands (lines 290–320, 380) alongside character-cell obstacles, mixing pixel-level and character-level graphics in the same stage. - Stage Two pond obstacles are drawn as filled circles using a scanline fill loop (lines 640–680): for each radius step
a, the chord half-widthb = INT(SQR(49 - a*a) + 0.5)is computed and a vertical line of height2*bis drawn at bothx+aandx-a. - The Stage Four checkerboard border is generated procedurally at lines 1270–1300 using
a - 3*INT(a/3) = 2as a modulo-3 test to alternate between\cand\dborder tiles. - Line 1350 uses
CHR$(146 + RND)to print either UDG “b” (char 146) or UDG “c” (char 147) randomly as background decoration, thoughRNDreturns a real number so146 + RNDalways truncates to 146 — this is likely a bug intended to randomize between two UDG tiles but effectively always prints the same one.
Bugs and Anomalies
- Line 1540 contains a spelling error: “COMPLEATED” instead of “COMPLETED”.
- The
CHR$(146 + RND)issue noted above always evaluates toCHR$(146)sinceINTis not applied;CHR$(146 + INT(RND*2))was likely intended. - The instruction text at line 216 runs words together without spaces between print-string segments (e.g., “SPACE AT THE BASE OF THE SCREEN.” and “EACH SHEEP BECOMES INACTIVE WHENIN ITS PEN”), indicating the programmer relied on line wrap rather than explicit spaces at string boundaries.
- The loop at line 460 uses
NEXT abut the only exit after the pen check at line 430 isGO TO 480, skipping to line 490 — line 480 does not exist, so penned sheep processing falls through directly to theNEXT aat line 460 via the non-existent line target, which is a deliberate Sinclair BASIC technique rather than a bug.
Content
Source Code
10 PAPER 7: INK 0: FLASH 0: BRIGHT 0: OVER 0: INVERSE 0: BORDER 0: CLS
20 PRINT INVERSE 1;AT 2,13;"SHEEP";AT 4,14;"DOG";AT 6,13;"TRIALS"
30 FOR a=0 TO 31
40 READ b: POKE USR "a"+a,b
50 NEXT a
60 DATA 0,0,127,255,91,17,17,0,0,0,65,254,63,33,33,0,8,28,28,62,62,127,8,28,0,129,255,129,255,129,255,129
65 GO SUB 7000
70 PRINT ''" IN THIS GAME YOU MUST MAKE"
80 PRINT " YOUR SHEEPDOG \b GUIDE THREE"
90 PRINT " SHEEP \a THROUGH A SERIES OF"
100 PRINT " OBSTACLES."
110 PRINT ''"CONTROLS ARE: -"
120 PRINT TAB 12;"T Y U"
130 PRINT 'TAB 12;"G H"
140 PRINT 'TAB 12;"V B N"
150 FOR a=0 TO 2*PI STEP PI/4
160 PLOT 123,28: DRAW 12*COS a,9*SIN a
170 NEXT a
180 PRINT ''"THERE ARE FOUR STAGES TO THE "
190 PRINT "TEST. POINTS ARE LOST FOR TAKING"
200 PRINT "TOO LONG OVER A STAGE.THE SHEEP"
210 PRINT "WILL ONLY MOVE WHEN THE DOG GETS"
215 PRINT "CLOSE TO THEM": PRINT
216 PRINT "IN THE FIRST THREE STAGES YOU MUST CHASE THE SHEEP INTO THE SPACE AT THE BASE OF THE SCREEN."
217 PRINT "EACH SHEEP BECOMES INACTIVE WHENIN ITS PEN": PRINT
218 PRINT "IN STAGE TWO THE BLUE AREAS ARE PONDS WHICH THE SHEEP WILL NOT CROSS,BUT IF THERE ARE GAPS IN THE FENCING BETWEEN THE PONDS, THE SHEEP WILL GO THROUGH THEM.": PRINT
220 PRINT "IN STAGE FOUR ALL THE SHEEP WILLREMAIN ACTIVE UNTIL THE THIRD ONE IS PENNED."
225 DIM x(3): DIM y(3): LET p=0
230 PRINT ''"Press any key to start"
240 PAUSE 0
250 PAPER 4: CLS
260 PRINT ''TAB 8;"\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d"
270 PRINT TAB 8;"\d ooooo \d"
280 FOR a=4 TO 12: PRINT AT a,8;"\d";TAB 23;"\d": NEXT a
290 PLOT 73,110
300 FOR a=1 TO 12
310 DRAW 9,0,-PI+RND-.5
320 NEXT a
330 PRINT AT 7,12;"\c\c \c\c";AT 8,12;"\c\c \c\c"
340 PRINT AT 5,19;"/\"
360 PRINT AT 11,10;"#### ^"
370 PRINT AT 13,8;"\d\d\d\d\d\d\d \d\d\d\d\d\d"
380 PLOT 117,62: DRAW 27,0,1.5*PI
390 GO SUB 9000
400 PRINT AT 18,0;"STAGE SCORE:";ss;" "
410 GO SUB 8000
420 FOR a=1 TO n
430 IF y(a)<=13 THEN GO TO 480
440 LET y(a)=y(n): LET x(a)=x(n): LET n=n-1
450 BEEP .3,0
460 NEXT a
490 IF n>0 THEN GO TO 400
495 FOR a=1 TO 200: NEXT a
500 POKE 23692,255
510 FOR a=1 TO 25: PRINT : NEXT a
520 PRINT ''TAB 6;"STAGE ONE COMPLETED"
530 PRINT ''TAB 11;"SCORE:";ss'''''''''''
540 LET p=ss
545 GO SUB 7000
550 PRINT '" Press any key for stage two"'''
560 IF INKEY$="" THEN GO TO 560
570 CLS
590 PLOT 71,60: DRAW 0,100,-PI: DRAW 115,0: DRAW 0,-100,-PI
600 PLOT 70,60: DRAW 0,100,-PI: DRAW 115,0: DRAW 0,-100,-PI
610 DRAW -33,0: DRAW -20,-40: DRAW -15,0: DRAW -20,40: DRAW -32,0
620 DRAW 0,70
625 INK 1
630 FOR x=80 TO 200 STEP 24
640 FOR a=0 TO 7
650 LET b=INT (SQR (49-a*a)+.5)
660 PLOT x+a,100-b: DRAW 0,2*b
670 PLOT x-a,100-b: DRAW 0,2*b
680 NEXT a
690 NEXT x
700 INK 0
710 FOR a=11 TO 23 STEP 3
720 IF RND<.7 THEN PRINT AT 9,a;"\d"
730 NEXT a
740 GO SUB 9000
745 PRINT AT 20,0;"RUNNING SCORE: ";p'"STAGE SCORE: ";
748 PRINT AT 21,13;ss;" ";
750 GO SUB 8000
760 FOR a=1 TO n
770 IF y(a)<15 THEN GO TO 790
780 LET x(a)=x(n): LET y(a)=y(n): LET n=n-1
785 BEEP .3,0
790 NEXT a
800 IF n>0 THEN GO TO 748
803 GO SUB 7000
805 FOR a=1 TO 200: NEXT a
810 POKE 23692,255
820 FOR a=1 TO 25: PRINT : NEXT a
830 PRINT TAB 6;"STAGE TWO COMPLETED"
840 PRINT ''"SCORE SO FAR: ";ss+p
850 LET p=p+ss
860 PRINT ''"Press any key for stage three"
870 PRINT ''''''''''
880 IF INKEY$="" THEN GO TO 880
900 CLS
910 PRINT ''TAB 6;"\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c"
920 PRINT TAB 6;"\c\c\c\c\c\c\c\c\c \c\c\c"
930 PRINT TAB 6;"\c\c \c\c\c"
940 PRINT TAB 6;"\c \c\c\c \c"
950 PRINT TAB 6;"\c\c \c\c\c\c\c \c\c"
960 PRINT TAB 6;"\c\c\c\c \c\c\c\c\c \c\c"
970 PRINT TAB 6;"\c\c\c\c\c\c\c\c\c\c\c\c\c\c \d"
980 PRINT TAB 6;"\c \c\c\c\c\c\c \d"
990 PRINT TAB 6;"\c \c\c\c \d\d\d"
1000 PRINT TAB 6;"\c\c\c ^^ \d\d"
1010 PRINT TAB 6;"\c\c\c\c ^^ \c\c\c\c\d\d"
1020 PRINT TAB 6;"\c\c\c\c\c \c\c\c\c\c\c\c\d"
1030 PRINT TAB 6;"\c\c\c\c \c\c\c\c\c\c"
1040 PRINT TAB 6;"\c\c\c\c \c\c\c\c\c\c"
1050 PRINT ''"RUNNING SCORE: ";p
1060 PRINT "STAGE SCORE: "
1070 GO SUB 9000
1080 PRINT AT 19,13;ss;" "
1090 GO SUB 8000
1100 FOR a=1 TO n
1110 IF y(a)<15 THEN GO TO 1130
1120 LET y(a)=y(n): LET x(a)=x(n): LET n=n-1
1125 BEEP .3,0
1130 NEXT a
1140 IF n>0 THEN GO TO 1080
1150 GO SUB 7000
1160 FOR a=1 TO 200: NEXT a
1170 CLS
1180 PRINT '''TAB 5;"STAGE THREE COMPLETED"
1190 PRINT ''"SCORE: ";ss+p
1200 LET p=p+ss
1210 PRINT '''"NOW YOU HAVE TO GET THE"
1220 PRINT "SHEEP INTO THEIR PEN"
1230 PRINT ''''"Press any key"
1240 PAUSE 0
1250 CLS
1260 PRINT ''" \c\d\d\d\c\d\d\d\c\d\d\d\c\d\d\d\c\d\d\d\c\d\d\d\c\d\d\d\c"
1270 FOR a=3 TO 16
1280 IF a-3*INT (a/3)=2 THEN PRINT AT a,2;"\c";TAB 30;"\c": GO TO 1300
1290 PRINT AT a,2;"\d";TAB 30;"\d"
1300 NEXT a
1310 PRINT " \c\d\d\d\c\d\d\d\c\d\d\d\c\d\d\d\c\d\d\d\c\d\d\d\c\d\d\d\c"
1320 FOR a=1 TO 20
1330 LET x=RND*25+4: LET y=RND*12+4
1340 PRINT AT y,x;CHR$ (146+RND)
1350 NEXT a
1360 GO SUB 9000
1370 PRINT AT 19,0;"RUNNING SCORE: ";p'"STAGE SCORE:"
1390 PRINT AT 10,13;" ";AT 11,13;" ";AT 12,13;" "
1400 PLOT 104,73: DRAW 0,23: DRAW 31,0: DRAW 0,-23
1405 PRINT AT 20,13;ss;" "
1410 GO SUB 8000
1420 LET ct=0
1430 FOR a=1 TO 3
1440 IF x(a)>12 THEN IF x(a)<17 THEN IF y(a)>9 THEN IF y(a)<13 THEN LET ct=ct+1
1450 NEXT a
1460 IF ct<>3 THEN GO TO 1405
1470 FOR a=1 TO 5
1480 FOR b=7 TO 0 STEP -1
1485 BORDER b
1490 PAUSE 10
1500 NEXT b
1510 NEXT a
1520 POKE 23692,255
1530 FOR a=1 TO 25: PRINT : NEXT a
1535 CLS
1540 PRINT AT 10,10;"YOU HAVE NOW COMPLEATED THE TRIAL"
1550 PRINT ''" YOUR DOG SCORED ": FLASH 1: PRINT AT 15,14;ss+p: FLASH 0: PRINT TAB 8;" POINTS OUT OF"
1560 PRINT TAB 9;"A POSSIBLE 80."
1561 GO SUB 7000
1570 PRINT ''"Do you wish to play again? Y/N"
1580 IF INKEY$="y" OR INKEY$="Y" THEN RUN
1590 IF INKEY$="n" OR INKEY$="N" THEN GO TO 9990
1600 GO TO 1580
7000 FOR a=10 TO 25: BEEP .06,a: NEXT a
7010 FOR a=10 TO 25: BEEP .06,a: NEXT a
7015 FOR a=1 TO 20: NEXT a
7020 FOR a=25 TO 10 STEP -1: BEEP .06,a: NEXT a
7030 RETURN
8000 LET nm=nm+1
8010 LET a=20-INT ((nm-50)/40)
8020 IF a>20 THEN GO TO 8040
8030 LET ss=a: IF ss<0 THEN LET ss=0
8040 LET a$=INKEY$
8050 LET px=x+(a$="u" OR |(1,1)=9 OR a$="h" OR |(1,1)=8 OR a$="n" OR |(1,1)=10)-(a$="t" OR |(1,1)=5 OR a$="g" OR |(1,1)=4 OR a$="v" OR |(1,1)=6)
8060 LET py=y-(a$="t" OR |(1,1)=5 OR a$="y" OR |(1,1)=1 OR a$="u" OR |(1,1)=9)+(a$="v" OR |(1,1)=6 OR a$="b" OR |(1,1)=2 OR a$="n" OR |(1,1)=10)
8070 IF SCREEN$ (py,px)=" " THEN GO TO 8120
8080 IF SCREEN$ (py,x)=" " THEN LET px=x: GO TO 8120
8090 IF SCREEN$ (y,px)=" " THEN LET py=y: GO TO 8120
8100 LET px=x: LET py=y
8120 PRINT AT y,x;" ";AT py,px;"\b"
8130 LET x=px: LET y=py
8140 FOR a=1 TO n
8150 LET dx=x(a)-x: LET dy=y(a)-y: LET d=dx*dx+dy*dy
8160 IF d>9 THEN GO TO 8230
8165 IF d=9 AND n<3 THEN GO TO 8230
8170 LET px=x(a)+SGN dx: LET py=y(a)+SGN dy
8180 IF SCREEN$ (py,px)=" " THEN GO TO 8220
8190 IF SCREEN$ (py,x(a))=" " THEN LET px=x(a): GO TO 8220
8200 IF SCREEN$ (y(a),px)=" " THEN LET py=y(a): GO TO 8220
8210 IF RND>.01 THEN LET px=x(a)+SGN (RND-.5): LET py=y(a)+SGN (RND-.5): GO TO 8180
8215 LET px=x(a): LET py=y(a)
8220 PRINT AT y(a),x(a);" "; INK 7;AT py,px;"\a"
8225 LET x(a)=px: LET y(a)=py
8230 NEXT a
8240 RETURN
9000 LET ss=20: READ x,y: LET nm=0: LET n=3
9010 FOR a=1 TO 3: READ x(a),y(a): PRINT AT y(a),x(a); INK 7;"\a": NEXT a
9020 PRINT AT y,x;"\b"
9030 RETURN
9040 DATA 10,3,12,6,14,4,16,5
9050 DATA 6,12,4,8,6,8,6,9
9060 DATA 8,5,10,4,11,6,14,4
9070 DATA 5,5,18,11,5,14,24,6
9990 CLS : BORDER 1: PAPER 1: INK 6: FLASH 1: PRINT AT 11,0;" LASSIE SAYS GOODBYE ": FLASH 0
9995 STOP
9999 SAVE "sheep dog" LINE 10
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

