This program is a bowling average tracker for a team. It maintains a season’s worth of scores for multiple players across multiple weeks, storing three games per week per player in a three-dimensional array S(PLAYERS,WEEKS,3). The menu-driven interface uses inverse-video characters throughout for highlighted display, and navigation is handled by reading INKEY$ keycodes (29–32 correspond to ZX81 digit characters 1–4) to branch via GOTO VAL Y$*1000. Player statistics including high game, high series, and a rounded average are calculated on demand, with an optional COPY command to print the display. Data can be saved to tape under a user-supplied filename.
Program Analysis
Program Structure
The program is organized as a menu-driven application with five functional modules, each beginning at a round-thousand line number. The main menu loop lives at lines 100–250, and each menu option jumps to its module via GOTO VAL Y$*1000. All modules return to the main menu at line 100 when finished.
| Line range | Module | Function |
|---|---|---|
| 100–250 | Main menu | Display options, read keypress, dispatch |
| 1000–1260 | Initialize | Set up season dimensions and player names |
| 2000–2250 | Enter scores | Input three games per player per week |
| 3000–3420 | Display player data | Show high game, high series, average |
| 4000–4920 | Edit data | Change scores or player name |
| 5000–5050 | Save to tape | SAVE under user-supplied filename |
| 9997–9999 | Bootstrap | Initial SAVE of the program itself, then GO TO 1 |
Data Storage
Three arrays are allocated dynamically after the user supplies season parameters. The core score store is a three-dimensional numeric array S(PLAYERS,WEEKS,3), holding all three games for every player and every week. Player names are held in the string array P$(PLAYERS,32), and weekly series totals in T(WEEKS). The variable R1, initialized to 0 at line 10 and incremented at line 2010, serves as the current-week counter and is tested at lines 3000 and 2020 as a guard against accessing uninitialized data.
Menu Dispatch Idiom
The main menu reads a single keypress into Y$ at line 200. Line 220 validates it by checking CODE Y$ against the range 29–32, which are the ZX81 internal codes for the digit characters “1” through “4” (not ASCII). The dispatch at line 250 uses GOTO VAL Y$*1000: VAL Y$ converts the character to its numeric value (1–4), multiplied by 1000 to reach the correct module entry point. Option “5” (save) is listed on the menu but the code range check excludes code 33 (“5”), so saving can only be reached if the validation is relaxed — this is a latent bug: the guard at line 220 allows codes 29–32 only, excluding the “5” option shown on screen.
Player Name Matching
Both the display (line 3040) and edit (line 4050) modules search for a player by comparing the user’s input N$ against a leading substring of each stored name: IF N$=P$(A, TO LEN N$). This allows partial-name lookup, so entering just the first few letters is sufficient to identify a player.
Statistics Calculation
The display module (lines 3130–3340) makes a single pass through all recorded weeks for the selected player. It tracks high single game (HIGAME), high three-game series (HISERIES), total pins (TPINS), and total games played (TGAMES). The average is computed as TPINS/TGAMES and rounded to two decimal places using the expression INT(100*AVERAGE+.05)/100 at line 3330, which implements standard rounding by adding half a unit before truncating.
Notable Techniques
- FAST/SLOW bracketing: Computationally intensive sections (screen build, array allocation) are wrapped in
FAST/SLOWpairs to suppress display flicker during processing while still accepting input in SLOW mode. - PAUSE 40000 as a display hold: Used after showing statistics and series totals, giving the user time to read before the program continues. The value 40000 is close to the maximum (65535 would be the absolute limit) and provides a very long wait.
- Optional COPY at line 3410: After the statistics pause, pressing “Z” triggers a
COPYto print the screen contents, allowing a paper record of a player’s data. - VAL Y$*1000 dispatch: A compact idiom avoiding a chain of IF statements for menu routing.
- Bootstrap lines 9997–9999: Line 9998 saves the program under the name “BOWLIN
%G” (the%Grenders as inverse “G” on screen), and line 9999GOTO 1— since line 1 does not exist, this is the well-known technique of jumping to a non-existent line, which in practice falls through to the next available line (line 10), effectively auto-starting after the save.
Content
Source Code
0 % % % %B%O%W%L%I%N%G% % % % %W%R%I%T%T%E%N% % %B%Y% % % %G%E%N%E% %B%U%Z%A% %
10 LET R1=0
100 FAST
110 CLS
120 PRINT AT 1,7;"% %B%O%W%L%I%N%G% %A%V%E%R%A%G%E% "
130 PRINT AT 4,0;"% %T%O% %I%N%I%T%I%A%L%I%Z%E% ";TAB 31;"%1"
140 PRINT AT 6,0;"% %T%O% %E%N%T%E%R% %S%C%O%R%E%S% ";TAB 31;"%2"
150 PRINT AT 8,0;"% %T%O% %D%I%S%P%L%A%Y% %P%L%A%Y%E%R% %D%A%T%A% ";TAB 31;"%3"
160 PRINT AT 10,0;"% %T%O% %E%D%I%T% %D%A%T%A% ";TAB 31;"%4"
170 PRINT AT 12,0;"% %T%O% %S%A%V%E% %O%N% %T%A%P%E% ";TAB 31;"%5"
190 SLOW
200 LET Y$=INKEY$
210 PRINT AT 21,4;"ENTER ONE OF ABOVE ::";AT 21,4;"%E%N%T%E%R% %O%N%E% %O%F% %A%B%O%V%E% %:%:"
220 IF CODE Y$<29 OR CODE Y$>32 THEN GOTO 200
230 FAST
240 CLS
250 GOTO VAL Y$*1000
\n1000 PRINT "HOW MANY WEEKS IS THE SEASON? ";
\n1010 SLOW
\n1020 INPUT WEEKS
\n1030 PRINT WEEKS
\n1040 PRINT ,,"HOW MANY PLAYERS ON THE TEAM? ";
\n1050 INPUT PLAYERS
\n1060 PRINT PLAYERS
\n1100 DIM S(PLAYERS,WEEKS,3)
\n1110 DIM P$(PLAYERS,32)
\n1120 DIM T(WEEKS)
\n1190 CLS
\n1200 FOR N=1 TO PLAYERS
\n1210 PRINT "NAME OF PLAYER NO.";N
\n1220 INPUT P$(N)
\n1230 PRINT P$(N)
\n1240 PRINT
\n1250 NEXT N
\n1260 GOTO 100
\n2000 SLOW
\n2010 LET R1=R1+1
\n2020 IF R1=WEEKS THEN GOTO 2500
\n2100 FOR N=1 TO PLAYERS
\n2110 CLS
\n2120 PRINT "SCORE FOR WEEK NO.";R1;" FOR"
\n2130 PRINT P$(N)
\n2140 FOR I=1 TO 3
\n2150 PRINT "GAME NO.";I;
\n2160 INPUT S(N,R1,I)
\n2170 PRINT TAB 29;S(N,R1,I)
\n2180 PRINT
\n2190 NEXT I
\n2200 LET T(R1)=S(N,R1,1)+S(N,R1,2)+S(N,R1,3)
\n2210 PRINT "SERIES =";TAB 29;T(R1)
\n2220 PAUSE 40000
\n2230 CLS
\n2240 NEXT N
\n2250 GOTO 100
\n3000 IF R1=0 THEN GOTO 100
\n3010 PRINT AT 1,2;"% %W%H%A%T% %I%S% %T%H%E% %P%L%A%Y%E%R\:.%S% %N%A%M%E% "
\n3015 SLOW
\n3020 INPUT N$
\n3025 FAST
\n3030 FOR A=1 TO PLAYERS
\n3040 IF N$=P$(A, TO LEN N$) THEN GOTO 3100
\n3050 NEXT A
\n3060 PRINT ,,N$;" NOT IN FILE."
\n3070 PAUSE 40000
\n3080 GOTO 100
\n3100 CLS
\n3110 PRINT "BOWLING DATA FOR :::",P$(A)
\n3120 FAST
\n3130 LET HIGAME=0
\n3135 LET TPINS=0
\n3136 LET TGAMES=0
\n3140 LET HISERIES=0
\n3150 FOR B=1 TO R1
\n3160 LET SERIES=0
\n3170 FOR C=1 TO 3
\n3175 LET TGAMES=TGAMES+1
\n3180 LET GAME=S(A,B,C)
\n3185 LET TPINS=TPINS+GAME
\n3190 IF GAME>HIGAME THEN LET HIGAME=GAME
\n3200 LET SERIES=SERIES+GAME
\n3210 NEXT C
\n3220 IF SERIES>HISERIES THEN LET HISERIES=SERIES
\n3230 NEXT B
\n3300 PRINT ,,"% %H%I%G%H% %G%A%M%E% %=% ",HIGAME
\n3310 PRINT ,,"% %H%I%G%H% %S%E%R%I%E%S% %=",HISERIES
\n3320 LET AVERAGE=TPINS/TGAMES
\n3330 LET AVERAGE=INT (100*AVERAGE+.05)/100
\n3340 PRINT ,,"% %A%V%E%R%A%G%E% %=% ",AVERAGE
\n3400 PAUSE 40000
\n3410 IF INKEY$="Z" THEN COPY
\n3420 GOTO 100
\n4000 PRINT ,,"% %W%H%A%T% %I%S% %T%H%E% %P%L%A%Y%E%R%S% %N%A%M%E%?% "
\n4010 SLOW
\n4020 INPUT N$
\n4030 FAST
\n4040 FOR A=1 TO PLAYERS
\n4050 IF N$=P$(A, TO LEN N$) THEN GOTO 4100
\n4060 NEXT A
\n4070 GOTO 3060
\n4100 CLS
\n4110 PRINT ,,P$(A)
\n4120 PRINT ,,"% %C%H%A%N%G%E% %N%A%M%E%?% "
\n4130 PAUSE 40000
\n4140 IF INKEY$="Y" THEN GOTO 4900
\n4150 CLS
\n4160 PRINT ,,"WHAT WEEK?"
\n4170 SLOW
\n4180 INPUT WW
\n4190 FAST
\n4220 PRINT
\n4230 FOR N=1 TO 3
\n4240 PRINT N,S(A,WW,N)
\n4250 NEXT N
\n4260 PRINT ,,"WHICH GAME (1, 2,3 OR 0 TO EXIT)DO YOU WANT TO CHANGE?"
\n4265 SLOW
\n4270 LET W$=INKEY$
\n4271 IF CODE W$<28 OR CODE W$>31 THEN GOTO 4270
\n4272 IF W$="0" THEN GOTO 100
\n4275 FAST
\n4276 LET WG=VAL W$
\n4280 IF WG>3 OR WG<1 THEN GOTO 4270
\n4290 PRINT ,,"NEW GAME TOTAL?"
\n4295 SLOW
\n4300 INPUT NG
\n4305 FAST
\n4310 IF NG<0 OR NG>300 THEN GOTO 4295
\n4320 LET S(A,WW,WG)=NG
\n4330 GOTO 100
\n4900 PRINT ,,"WHAT IS THE NEW NAME?"
\n4905 SLOW
\n4910 INPUT P$(A)
\n4920 GOTO 100
\n5000 PRINT ,,"ENTER THE FILE NAME, PEPARE THE RECORDER AND PRESS ENTER :::"
\n5010 SLOW
\n5020 INPUT F$
\n5030 FAST
\n5040 SAVE F$
\n5050 GOTO 100
\n9997 STOP
\n9998 SAVE "BOWLIN%G"
\n9999 GOTO 1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
