This program implements the dice game Yahtzee for one to four players on a 15-row scorecard. Each player takes up to three throws per turn, choosing which of the five dice (labelled A–E) to re-roll by entering a string of letter choices. The scorecard layout is encoded in the single long string Z$ at line 110, sliced into 10-character fields for display. Scores are stored in a two-dimensional array P(PLYRS,15), where column 15 holds each player’s running total and columns 7–8 track the upper-section subtotal and bonus.
Program Analysis
Program Structure
The code is divided into clearly separated routines accessed via GOSUB:
- Lines 10–110 – Global constants and data: player-name string
T$, layout stringZ$, display offsetsP1,LE,P2,P3, bonus thresholdPLUS. - Lines 800–990 – Setup: player-count input, array initialisation, scorecard draw (
GOSUB 8000). - Lines 1000–2340 – Main game loop: throw loop (up to 3), option selection, scoring dispatch.
- Lines 3000–3160 – Score recording, player cycling, end-of-game winner display with a flashing loop.
- Lines 7010–7100 – Winner determination subroutine.
- Lines 8010–8120 – Screen draw subroutine (scorecard labels + player headers).
- Lines 9010–9110 – Dice-roll subroutine; only dice whose letter appears in
A$are re-rolled. - Lines 9210–9260 – Count-array builder (
DIM C(6), tally of each face value). - Lines 9310–9940 – Individual scoring subroutines: Yacht (5-of-a-kind, 50pts), 4-of-a-kind, Full House / High Straight, Big Straight, Little Straight, Choice (sum all), upper-section numbers.
- Lines 9950–9970 –
CLEAR/SAVE/RUNauto-restart block.
Scorecard Layout Encoding
The string Z$ at line 110 is exactly 150 characters long (15 rows × 10 characters each). The subroutine at line 8010 slices it with Z$(PS TO PF) using computed offsets and prints each slice at the corresponding screen row, providing the entire left-hand label column of the scorecard without any individual PRINT statements per row. The constant LE=10 controls field width.
Display Coordinate System
Column positions for each player’s scores are computed from three constants:
P1=1– base left marginP2=5– per-player column strideP3=12– right offset from left margin to score columns
The expression (PL-1)*P2+P1+P3 therefore yields column 13 for player 1, 18 for player 2, etc., giving a compact multi-column scorecard for up to four players.
Score Array Layout
| Index | Contents |
|---|---|
| 1–6 | Upper section (ones through sixes); initialised to -1 (unscored) |
| 7 | Upper subtotal (accumulates as entries are made) |
| 8 | Bonus flag (0 = not awarded, 50 = awarded) |
| 9–14 | Lower section categories (Choice, Full/High Straight, 4-of-a-kind, Little Straight, Big Straight, Yacht) |
| 15 | Grand total (running sum) |
Unscored cells are initialised to -1 so that a score of 0 (a valid outcome) is distinguishable from an empty slot. The guard at line 2060 (IF P(PL,OP)>=0 THEN GOTO 2010) prevents overwriting an already-scored category.
Option Numbering Offset
The user enters options 1–12. Because the score array reserves slots 7 and 8 for the subtotal and bonus (not directly selectable), line 2052 adjusts: IF OP>6 THEN LET OP=OP+2. This maps user choices 7–12 to array indices 9–14, skipping the internal slots cleanly.
Dice Re-roll Mechanic
Dice are labelled A–E via T$="ABCDE". The player types a string of letters for dice to keep (or re-roll — the logic at lines 9010–9070 re-rolls any die whose letter appears in A$). On the first throw, A$ is pre-set to "ABCDE" at line 1006 so all five dice are always rolled. Subsequent throws prompt the player to enter letters.
Scoring Subroutines
All scoring routines rely on the count array C(6) built by the subroutine at line 9210. The count array is declared with DIM C(6) inside the subroutine, which resets it to zero on each call — a neat initialisation trick. Key scoring logic:
- Yacht (line 9310): checks for any
C(N)=5; awards 50 points. - 4-of-a-kind (line 9410): checks
C(N)>=4, then sums all dice. - Little Straight (line 9510): calls
GOSUB 9800to count zero-valued slots (CT); awards sum of dice if exactly 4 distinct values present (CT=4 gaps in C means… see anomaly below). - Full House / High Straight (line 9610): awards 30 if
C(6)=0andCT=1(one face missing, no sixes — i.e. 1–5 straight or full house heuristic). - Big Straight (line 9710): awards 30 if
C(1)=0andCT=1(2–6 straight).
Notable Techniques
FAST/SLOW(lines 900, 990) bracket the array initialisation and screen setup for speed.- The winner-display loop (lines 3090–3160) uses two short
FOR…NEXTdelay loops and alternates the winner name with a blank to create a flashing effect withoutPAUSE. RANDat line 832 seeds the random number generator from the real-time clock, ensuring different dice sequences each game.- The
SAVE "1025%4"at line 9960 uses an inverse-video character in the filename as an auto-run flag.
Bugs and Anomalies
- Missing
GOSUB 7000: Line 3080 callsGOSUB 7000but the subroutine begins at line 7010. This is a standard technique of jumping past the first line of a subroutine via a non-existent entry point — here it works because there is no executable code at line 7000 itself and execution falls through to 7010. - Little Straight scoring: The subroutine at 9510 checks
CT=4(four empty slots in C), which would mean only two distinct values are present — the opposite of a straight. A genuine 1–2–3–4 straight would haveCT=2. This appears to be a logic error; the intended check was likelyCT=2. - Full House / High Straight conflation: Option 8 is labelled “FULL/HS” (Full House / High Straight) but the scoring subroutine only checks for a 1–5 straight (no sixes, one missing value). A genuine full house (e.g. three 2s and two 5s) would also give
CT=2, notCT=1, and would not be caught. - Grand total double-counting: The upper-section bonus (50 pts) is added to
P(PL,15)at line 2150, and each scored option also adds toP(PL,15)at line 3012. However, the upper subtotal (slot 7) is also added at line 3012 when the player nominates an upper-section option, meaning the upper-section points are counted twice in the grand total (once via slot 7 and once via slots 1–6). A$as keep-or-reroll ambiguity: Lines 1006 and 9040–9050 re-roll dice whose letters appear inA$, but the prompt at line 1010 says “CHOOSE” with no indication of whether the player should enter dice to keep or dice to re-roll.
Content
Source Code
10 LET T$="ABCDE"
20 DIM H(5)
70 LET P1=1
72 LET LE=10
80 LET P2=5
90 LET P3=12
100 LET PLUS=60
110 LET Z$="1 ONES---2 TWOS---3 THREES 4 FOURS--5 FIVES--6 SIXES--*SUB TOTAL**BONUS***7 CHOICE-8 FULL/HS9 4/KIND-10 LTL/ST-11 BIG/ST-12 YACHT--***TOTAL**"
800 CLS
802 PRINT AT 10,10;"YACHTZEE"
810 PRINT AT 12,1;"HOW MANY PLAYERS ? (1-4)"
820 INPUT PLYRS
830 IF PLYRS<1 OR PLYRS>4 THEN GOTO 800
832 RAND
840 CLS
900 FAST
902 LET NUMG=0
910 LET PL=1
920 DIM P(PLYRS,15)
930 FOR N=1 TO PLYRS
940 FOR M=1 TO 14
942 IF M=7 OR M=8 THEN GOTO 960
950 LET P(N,M)=-1
960 NEXT M
970 NEXT N
980 GOSUB 8000
990 SLOW
1000 LET TURN=0
1002 PRINT AT 18,1;"PLAYER ";PL
1006 LET A$="ABCDE"
1008 GOTO 1022
1010 PRINT AT 20,0;"CHOOSE"
1012 INPUT A$
1014 PRINT AT 20,0;" "
1020 IF A$="" THEN GOTO 2000
1022 PRINT AT 18,10;"THROW ";TURN+1
1030 GOSUB 9000
1040 LET TURN=TURN+1
1050 IF TURN<3 THEN GOTO 1010
2000 GOSUB 9200
2010 PRINT AT 20,0;"OPTION ?"
2012 PRINT AT 21,0;"(1-12)"
2020 INPUT OP
2030 PRINT AT 20,0;" "
2032 PRINT AT 21,0;" "
2050 IF OP<1 OR OP>12 THEN GOTO 2010
2052 IF OP>6 THEN LET OP=OP+2
2060 IF P(PL,OP)>=0 THEN GOTO 2010
2070 LET PTS=0
2080 LET FLAG=0
2090 IF OP>6 THEN GOTO 2200
2100 GOSUB 9900
2110 LET P(PL,7)=P(PL,7)+PTS
2112 PRINT AT 7,(PL-1)*P2+P1+P3;P(PL,7)
2120 IF P(PL,7)<PLUS THEN GOTO 3000
2122 IF P(PL,8)>0 THEN GOTO 3000
2130 LET P(PL,8)=50
2140 PRINT AT 8,(PL-1)*P2+P1+P3-1;"*50*"
2150 LET P(PL,15)=P(PL,15)+50
2200 IF OP<>9 THEN GOTO 2300
2210 FOR N=1 TO 5
2220 LET PTS=PTS+H(N)
2230 NEXT N
2240 GOTO 3000
2300 GOSUB 9200
2308 IF OP=10 THEN GOSUB 9500
2310 IF OP=11 THEN GOSUB 9400
2320 IF OP=12 THEN GOSUB 9600
2330 IF OP=13 THEN GOSUB 9700
2340 IF OP=14 THEN GOSUB 9300
3000 LET P(PL,OP)=PTS
3010 PRINT AT OP,(PL-1)*P2+P3+P1;PTS
3012 LET P(PL,15)=P(PL,15)+PTS
3014 PRINT AT 15,(PL-1)*P2+P1+P3;P(PL,15)
3020 LET PL=PL+1
3030 IF PL<(PLYRS+1) THEN GOTO 1000
3040 LET PL=1
3050 LET NUMG=NUMG+1
3060 IF NUMG<12 THEN GOTO 1000
3080 GOSUB 7000
3090 PRINT AT 18,8;WIN;" WINS "
3100 IF INKEY$<>"" THEN GOTO 800
3110 FOR N=1 TO 10
3120 NEXT N
3130 PRINT AT 18,8;" "
3140 FOR N=1 TO 3
3150 NEXT N
3160 GOTO 3090
7010 LET MAX=P(1,15)
7020 LET WIN=1
7030 IF PLYRS=1 THEN RETURN
7040 FOR N=2 TO PLYRS
7050 IF P(N,15)<=MAX THEN GOTO 7080
7060 LET MAX=P(N,15)
7070 LET WIN=N
7080 NEXT N
7100 RETURN
8010 FOR N=1 TO 15
8020 LET PS=(N-1)*LE+1
8030 LET PF=PS+LE-1
8040 PRINT AT N,1;Z$(PS TO PF)
8050 NEXT N
8060 FOR N=1 TO 5
8070 PRINT AT 20,(N-1)*3+10;T$(N)
8080 NEXT N
8090 FOR N=1 TO PLYRS
8100 PRINT AT 0,(N-1)*P2+P3;"*P";N;"*"
8110 NEXT N
8120 RETURN
9010 LET N1=LEN A$
9020 FOR N=1 TO N1
9030 FOR M=1 TO 5
9040 IF A$(N)<>T$(M) THEN GOTO 9060
9050 LET H(M)=INT (RND*6)+1
9060 NEXT M
9070 NEXT N
9080 FOR N=1 TO 5
9090 PRINT AT 21,(N-1)*3+10;H(N)
9100 NEXT N
9110 RETURN
9210 DIM C(6)
9230 FOR N=1 TO 5
9240 LET C(H(N))=C(H(N))+1
9250 NEXT N
9260 RETURN
9310 FOR N=1 TO 6
9320 IF C(N)=5 THEN LET PTS=50
9330 NEXT N
9340 RETURN
9410 FOR N=1 TO 6
9420 IF C(N)>=4 THEN LET FLAG=1
9440 NEXT N
9450 IF FLAG<>1 THEN RETURN
9460 FOR N=1 TO 5
9470 LET PTS=PTS+H(N)
9480 NEXT N
9490 RETURN
9510 GOSUB 9800
9520 IF CT<>4 THEN RETURN
9530 FOR N=1 TO 5
9540 LET PTS=PTS+H(N)
9550 NEXT N
9560 RETURN
9610 GOSUB 9800
9640 IF C(6)=0 AND CT=1 THEN LET PTS=30
9650 RETURN
9710 GOSUB 9800
9720 IF C(1)=0 AND CT=1 THEN LET PTS=30
9730 RETURN
9810 LET CT=0
9820 FOR N=1 TO 6
9830 IF C(N)=0 THEN LET CT=CT+1
9840 NEXT N
9850 RETURN
9910 FOR N=1 TO 5
9920 IF OP=H(N) THEN LET PTS=PTS+OP
9930 NEXT N
9940 RETURN
9950 CLEAR
9960 SAVE "1025%4"
9970 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
