This program implements a top-down golf simulation for one or two players, spanning either a 9-hole or 18-hole course. Each hole is procedurally generated using RND to place fairways, rough, trees, bunkers, water hazards, and the green before computing par and yardage. Ball physics are handled with trigonometric calculations using COS and SIN against a clock-face direction system (0–12), with STEP scaling shots proportionally to hole yardage. Five user-defined graphics (UDGs A–E) are loaded from DATA at startup to represent terrain types and the ball. The program uses ATTR to read screen cell attributes for terrain detection, and ON ERR with RESET provides error recovery throughout.
Program Analysis
Program Structure
The program is organized into several well-separated subroutines and sections:
- Lines 5000–5055: Initialization — UDG setup, course length, player count selection.
- Lines 2005–2055: Hole generation subroutine (called via
GO SUB 2000— note line 2000 does not exist; execution falls through to 2005, a known technique). - Lines 5060–5225: Main game loop — stroke-by-stroke play for each player on each hole.
- Lines 5230–5320: Scorecard display after each hole.
- Lines 5400–5415: End-of-game prompt for replay.
- Lines 7000–7040: Player input subroutine — direction and strength entry with validation.
- Lines 7700–7715: Water hazard handling with penalty stroke.
- Lines 8000–8020: UDG sprite data (5 characters, 8 bytes each).
- Lines 9000–9020: Instructions display subroutine.
- Lines 9900–9990: Error recovery and SAVE routine.
UDG Definitions
Five UDGs are defined at startup in lines 5005–5005 by READing from DATA lines 8000–8020 and POKEing into USR CHR$ I for I=65 to 69 (characters A–E). Their roles as used in PRINT statements are:
| UDG | Escape | Role |
|---|---|---|
| A (65) | \a | Rough terrain |
| B (66) | \b | Trees |
| C (67) | \c | Water hazard |
| D (68) | \d | Hole/flag |
| E (69) | \e | Ball (flashes on-screen) |
Hole Generation
The hole generation subroutine (lines 2005–2055) builds each hole procedurally using a sequence of PRINT AT loops:
- Line 2005: Fills the screen with UDG A (rough) using a loop of 176 iterations printing four characters at a time. The
ON ERR GO TO 2005guards against the scroll prompt at the bottom of the screen. - Line 2010: Draws 3–6 tree clusters with meandering vertical paths using UDG B, sliced with
( TO 4+RND*8)string slicing for variable-width bands. - Line 2015: Prints blank spaces in a grid pattern to represent the fairway (paper color creates the green attribute).
- Line 2020: Draws water hazards using UDG C with string slicing for width variation.
- Line 2025: Draws sand bunkers using blank spaces over multiple rows.
- Lines 2030–2035: Draws the green area and places the hole marker (UDG D).
- Lines 2040–2045: Sets ball starting position (
BX,BY), determines par (3/4/5) and yardage via RND thresholds, then computesSTEPas28/YRDto scale shot distances.
Ball Physics and Movement
Direction is entered as a clock-face value (0–12). The constant V=PI/6 (line 5050) converts this to radians (each hour = 30°). Ball displacement per shot is calculated in lines 5115–5115:
P(P,1) = P(P,1) - ST*COS(D*V)— row movement (north-south)P(P,2) = P(P,2) + ST*SIN(D*V)— column movement (east-west)
The effective shot distance is ST * STEP * 2, where STEP = 28/YRD, so longer holes yield proportionally shorter movement per unit of strength.
Terrain Detection via ATTR
After each shot, line 5150 reads the screen attribute at the new ball position with ATTR(P(P,1), P(P,2)) and stores it in P(P,3). Terrain types are identified by their attribute byte values:
| ATTR value | Terrain | Effect |
|---|---|---|
| 36 | Fairway | Normal shot distance |
| 32 | Rough (UDG A) | Distance reduced by 2–3× |
| 4 | Trees (UDG B) | Random direction bounce, distance ÷4 |
| 48 | Bunker | 60% chance of no movement |
| 41 | Water | Penalty stroke, repositioned at water edge |
| 100 | Green | Normal movement, reported as “ON THE GREEN” |
| 97 | Hole (UDG D) | Holed out — records score |
| 39 | Two-ball overlap | Replaced by other player’s terrain value |
Player Data Array
Each player’s state is stored in row I of the 2D array P(PL,6) defined at line 5050:
| Index | Contents |
|---|---|
| P(I,1) | Current ball row |
| P(I,2) | Current ball column |
| P(I,3) | Current terrain attribute |
| P(I,4) | Cumulative course score vs par |
| P(I,5) | Score for current hole vs par |
| P(I,6) | Penalty stroke count for current hole |
Status Bar Technique
Line 5010 constructs a reusable status bar string B$ using CHR$ 22 (AT), CHR$ 21 (PAPER), and CHR$ 0 to position output at the bottom of the screen, padded with 32 spaces to clear it. This avoids CLS and allows in-place message updates without disrupting the hole display.
Input Validation
Direction and strength inputs in lines 7020–7035 are validated for range (0–12 and 0–100 respectively). A strength of zero (IF NOT ST) returns the player to direction input, allowing shot correction. Values are rounded to two decimal places using INT(X*100+.5)/100, accommodating the program’s note that decimal inputs like 3.25 are valid.
Water Hazard Recovery
Line 7700 handles water landings. The loop at 7705–7710 scans leftward along the ball’s row until it finds a cell whose ATTR is not 41 (water), placing the ball at the water’s edge. A penalty stroke is added to P(P,6), and the terrain check resumes at line 5150.
Error Handling
ON ERR is used in three contexts: line 2005 catches scroll errors during screen fill, line 2042 catches runtime errors during hole play, and lines 9900–9930 form a recovery chain using ON ERR RESET, PAUSE, ON ERR GO TO, and ON ERR CONTINUE to attempt graceful recovery. The final line 9990 loops on SAVE "golf" LINE 5000 as a combined save-and-auto-run operation.
Notable Idioms
- Boolean arithmetic for conditional assignment:
PAR=3+(J>.5)+(J>=.8)andCL=9*(INKEY$="S")+18*(INKEY$="L"). - String slicing for variable-width terrain bands:
"\b\b\b\b\b\b\b\b\b"( TO 4+RND*8). PAUSE 0/INKEY$loops (lines 7010, 9004, etc.) for keypress waiting without INPUT.POKE 23658,8in line 5001 enables CAPS SHIFT + symbol shift behavior, locking out unintended key modes during play.
Potential Anomalies
- Line 5155 handles two balls occupying the same cell (ATTR 39) by substituting the other player’s terrain value — this works for two players but would fail for more.
- The water hazard scan loop at 7710 uses
NEXT Iinside anIFstatement to skip non-water cells, an unusual but valid Spectrum BASIC technique that continues the FOR loop conditionally. - The hole instructions text in line 9010 references “WATER HAZZARD” (misspelled as “hazzard” rather than “hazard”).
- Line 5040 sets
BY=0always, so all players start at column 0 regardless of hole layout. Only the rowBXis randomized.
Content
Source Code
0 REM Spectrum "GOLF"
5 GO TO 5000
2005 BORDER 4: PAPER 4: CLS : PAPER 7: FOR I=1 TO 176: PRINT "\a\a\a\a";: ON ERR GO TO 2005: NEXT I
2010 FOR I=1 TO 3+RND*3: LET K=4+RND*17: FOR L=0 TO 20: LET K=K-2+RND*4: PRINT AT L,K*(K<=31);"\b\b\b\b\b\b\b\b\b"( TO 4+RND*8): NEXT L: NEXT I
2015 FOR I=1 TO 29 STEP 2: LET J=5+RND*5: FOR L=J TO 11+RND*4: PRINT AT L,I;" ": NEXT L: NEXT I
2020 LET I=5+10*RND: LET J=10+10*RND: FOR L=I TO I+2+RND*2: LET J=J-2+RND*4: PRINT AT L,J;"\c\c\c\c\c\c"( TO 6+RND*3): NEXT L
2025 FOR I=1 TO 2+RND*2: LET J=5+RND*10: LET K=21+RND*6: FOR L=J TO J+1+RND*2: LET K=K-1+RND*2: PRINT AT L,K;" "( TO 3+RND*2): NEXT L: NEXT I
2030 LET J=INT (4+RND*14): FOR I=J-2 TO J+2: PRINT AT I,25+RND*2;" ": NEXT I
2035 PRINT AT J,27+RND*3;"\d "
2040 LET BX=5+RND*8: LET BY=0
2042 ON ERR GO TO 9900
2045 LET J=RND: LET PAR=3+(J>.5)+(J>=.8): LET YRD=(170+INT (RND*100))*(PAR=3)+(275+INT (RND*175))*(PAR=4)+(450+INT (RND*125))*(PAR=5): LET STEP=28/YRD
2050 PRINT AT 1,1;"Hole ";H;TAB 10;AT 2,1;"Par ";PAR;TAB 10;AT 3,1;"Yards ";YRD
2055 RETURN
5000 ON ERR GO TO 9900
5001 BORDER 6: PAPER 6: BRIGHT 0: OVER 0: FLASH 0: INK 0: CLS : RANDOMIZE : POKE 23658,8: RESTORE
5005 FOR I=65 TO 69: FOR J=0 TO 7: READ X: POKE USR CHR$ I+J,X: NEXT J: NEXT I
5010 LET B$=CHR$ 22+CHR$ 21+CHR$ 0: LET B$=B$+" "+B$
5015 PRINT '''''''''" Do you need instructions?"''TAB 10;"""Y"" OR ""N"""
5020 IF INKEY$="Y" THEN GO SUB 9000: GO TO 5030
5025 IF INKEY$<>"N" THEN GO TO 5020
5030 CLS : PRINT '''''''"What length of course would you";TAB 10;"like to play?"''TAB 7;"""S"" Short 9 hole."''TAB 7;"""L"" Long 18 hole."
5035 LET CL=9*(INKEY$="S")+18*(INKEY$="L"): IF NOT CL THEN GO TO 5035
5040 CLS : PRINT '''''"WELCOME TO THE TS INTERNATIONAL"''TAB 5;CL;" HOLE GOLF COURSE."'''TAB 7;"How many players?";''TAB 10;"""1"" OR ""2"""
5045 LET PL=1*(INKEY$="1")+2*(INKEY$="2"): IF NOT PL THEN GO TO 5045
5050 DIM P(PL,6): LET V=PI/6
5055 FOR H=1 TO CL: GO SUB 2000
5060 FOR I=1 TO PL: LET P(I,1)=BX: LET P(I,2)=BY: LET P(I,3)=1: LET P(I,6)=0: NEXT I
5065 LET HO=0: FOR S=1 TO 99: FOR P=1 TO PL
5070 IF P(P,3)=97 THEN GO TO 5215
5075 GO SUB 7000: LET ST=ST*STEP*2: LET P$=" "
5080 IF P(P,3)=32 THEN LET ST=ST/(2+RND*2): LET P$="\a"
5085 IF P(P,3)=4 THEN LET P$="\b": IF RND>.6 THEN PRINT B$;"YOUR BALL REBOUNDS FROM A TREE.": LET D=RND*12: LET ST=ST/4: PAUSE 150
5090 IF P(P,3)=48 THEN LET P$=" ": IF RND>.6 THEN PRINT B$;"MISS HIT! You remain in bunker.": LET ST=0: PAUSE 150
5095 IF P(P,3)=36 THEN LET P$=" "
5100 IF P(P,3)=100 THEN LET P$=" "
5105 IF P(P,3)=1 THEN LET P$="T"
5110 PRINT AT P(P,1),P(P,2);P$
5115 LET P(P,1)=P(P,1)-ST*COS (D*V): LET P(P,2)=P(P,2)+ST*SIN (D*V)
5120 IF P(P,1)>=0 AND P(P,1)<=20 AND P(P,2)>=0 AND P(P,2)<=31 THEN GO TO 5150
5125 PRINT B$;"OUT OF BOUNDS... PENALTY STROKE": PAUSE 150: LET P(P,6)=P(P,6)+1
5130 IF P(P,1)<0 THEN LET P(P,1)=0
5135 IF P(P,1)>20 THEN LET P(P,1)=20
5140 IF P(P,2)<0 THEN LET P(P,2)=0
5145 IF P(P,2)>31 THEN LET P(P,2)=31
5150 LET P(P,3)=ATTR (P(P,1),P(P,2))
5155 IF P(P,3)=39 THEN LET P(P,3)=P(1+(P=1),3)
5160 IF P(P,3)=41 THEN GO TO 7700
5165 IF P(P,3)=97 THEN GO TO 5205
5170 PRINT B$;
5175 IF P(P,3)=36 THEN PRINT "ON THE FAIRWAY"
5180 IF P(P,3)=32 THEN PRINT "IN THE ROUGH"
5185 IF P(P,3)=4 THEN PRINT "IN THE TREES..."
5190 IF P(P,3)=48 THEN PRINT "IN A BUNKER."
5195 IF P(P,3)=100 THEN PRINT "ON THE GREEN."
5200 PRINT AT P(P,1),P(P,2);"\e": PAUSE 150: PRINT AT P(P,1),P(P,2);"\e": GO TO 5215
5205 LET P(P,5)=S+P(P,6)-PAR: LET P(P,4)=P(P,4)+P(P,5): LET HO=HO+1
5210 PRINT B$;"Player ";P;" Holed out in ";S+P(P,6): IF S+P(P,6)=1 THEN FOR I=1 TO 30: BEEP .08,10+RND*20: NEXT I: PRINT B$;"YOU BUY THE DRINKS AT THE 19th."
5215 PAUSE 200: NEXT P
5220 IF HO=PL THEN GO TO 5230
5225 NEXT S: REM RESET R&R SOFTWARE
5230 BORDER 4: PAPER 5: CLS : PRINT " SCORE TS 2000 GOLF CARD "
5235 PRINT 'TAB 9+1*(CL=9);CL;" HOLE COURSE"
5240 PRINT '"Hole - ";H;" Par - ";PAR;" Yards - ";YRD
5245 PRINT '"PLAYER";TAB 10;"HOLE";TAB 20;"COURSE": PRINT "\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''"
5250 FOR I=1 TO PL: PRINT '" ";I;TAB 7;
5255 IF NOT P(I,5) THEN PRINT " On";: GO TO 5275
5260 PRINT ABS P(I,5);
5265 IF P(I,5)<0 THEN PRINT " Under";
5270 IF P(I,5)>0 THEN PRINT " Over";
5275 PRINT " Par";TAB 19;
5280 IF NOT P(I,4) THEN PRINT " On";: GO TO 5300
5285 PRINT ABS P(I,4);
5290 IF P(I,4)<0 THEN PRINT " Under";
5295 IF P(I,4)>0 THEN PRINT " Over";
5300 PRINT " Par": NEXT I
5305 IF H=CL THEN GO TO 5400
5310 PRINT B$;" PRESS ENTER TO START NEXT HOLE "
5315 IF INKEY$<>CHR$ 13 THEN GO TO 5315
5320 NEXT H: REM RESET R&R SOFTWARE
5400 PRINT AT 16,2;"Would you like another game?";AT 18,11;"""Y"" OR ""N"""
5405 IF INKEY$="Y" THEN RUN 5000
5410 IF INKEY$="N" THEN PRINT AT 20,7;"Thanks for playing": STOP
5415 GO TO 5405
7000 PRINT B$;" Player ";P;" Press ENTER to play"
7005 PRINT AT P(P,1),P(P,2);"\e"
7010 IF INKEY$<>CHR$ 13 THEN GO TO 7010
7015 PRINT AT P(P,1),P(P,2);"\e"
7020 PRINT B$;"Direction? 0-12": INPUT D: IF D<0 OR D>12 THEN PRINT B$;"INVALID Direction MUST be 0-12": PAUSE 150: GO TO 7020
7025 LET D=INT (D*100+.5)/100
7030 PRINT B$;"Direction= ";D;" Strength? 0-100": INPUT ST: IF NOT ST THEN GO TO 7020
7035 IF ST<0 OR ST>100 THEN PRINT B$;"INVALID Strength MUST be 0-100": PAUSE 150: GO TO 7030
7040 LET ST=INT (ST*100+.5)/100: PRINT B$;"Direction= ";D;" Strength= ";ST: PAUSE 100: RETURN
7700 PRINT B$;"LANDED IN WATER. Penalty Stroke"
7705 FOR I=INT (P(P,2)) TO 0 STEP -1
7710 IF ATTR (P(P,1),I)=41 THEN NEXT I
7715 LET P(P,2)=I: LET P(P,6)=P(P,6)+1: PAUSE 150: GO TO 5150
8000 DATA 0,0,4,0,0,64,0,0
8005 DATA 255,247,227,213,247,227,213,247
8010 DATA 0,96,144,9,102,144,9,6
8015 DATA 12,60,12,4,4,30,37,30
8020 DATA 0,28,62,62,62,28,0,0
9000 BORDER 7: PAPER 7: CLS : LET T$=" TS 2000 PRO-AM GOLF ": PRINT T$''" A GAME FOR 1 OR 2 PLAYERS"
9001 PRINT '" You may play a 9 hole course ORa full 18 hole course. Each holeis generated at RANDOM so no twogames are the same."
9002 PRINT '" When its your turn to play yourball will be set flashing. When ready for move,Press the ENTER key. You must now enter a value (0-12, As on a Clock) to select your DIRECTION. Now give a valuefor STRENGTH of shot (1-100), anentry of ZERO will return you tothe direction input. Decimal inputs ie. 3.25 are allowed."
9003 PRINT B$;"Hit ENTER for more instructions."
9004 IF INKEY$<>CHR$ 13 THEN GO TO 9004
9010 CLS : PRINT T$''"The GREEN = FAIRWAY = ROUGH = \a\a\a BUNKER = ","WATER HAZZARD = \c\c\c TREES = \b"," The HOLE = \d The BALL = \e"
9011 PRINT '"When playing from the ROUGH yourball will not move as far as it will on the FAIRWAY. If you landin a bunker you may not get out first shot. When in the TREES the ball MAY bounce off in any direction. Land in the WATER orgo OUT OF BOUNDS and you incur ONE penalty stroke."
9012 PRINT '" I hope you enjoy your game "''"Press ENTER to start round OR ""P"" to see instructions again."
9014 IF INKEY$="P" THEN GO TO 9000
9015 IF INKEY$<>CHR$ 13 THEN GO TO 9014
9020 RETURN
9900 ON ERR RESET
9910 PAUSE 100
9920 ON ERR GO TO 9900
9930 ON ERR CONTINUE
9990 SAVE "golf" LINE 5000: GO TO 9990
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

