Yachtzee

This file is part of and Timex Sinclair Public Domain Library Tape 1006. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000
Tags: Game

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:

  1. Lines 10–110 – Global constants and data: player-name string T$, layout string Z$, display offsets P1, LE, P2, P3, bonus threshold PLUS.
  2. Lines 800–990 – Setup: player-count input, array initialisation, scorecard draw (GOSUB 8000).
  3. Lines 1000–2340 – Main game loop: throw loop (up to 3), option selection, scoring dispatch.
  4. Lines 3000–3160 – Score recording, player cycling, end-of-game winner display with a flashing loop.
  5. Lines 7010–7100 – Winner determination subroutine.
  6. Lines 8010–8120 – Screen draw subroutine (scorecard labels + player headers).
  7. Lines 9010–9110 – Dice-roll subroutine; only dice whose letter appears in A$ are re-rolled.
  8. Lines 9210–9260 – Count-array builder (DIM C(6), tally of each face value).
  9. 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.
  10. Lines 9950–9970CLEAR / SAVE / RUN auto-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 margin
  • P2=5 – per-player column stride
  • P3=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

IndexContents
1–6Upper section (ones through sixes); initialised to -1 (unscored)
7Upper subtotal (accumulates as entries are made)
8Bonus flag (0 = not awarded, 50 = awarded)
9–14Lower section categories (Choice, Full/High Straight, 4-of-a-kind, Little Straight, Big Straight, Yacht)
15Grand 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 9800 to 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)=0 and CT=1 (one face missing, no sixes — i.e. 1–5 straight or full house heuristic).
  • Big Straight (line 9710): awards 30 if C(1)=0 and CT=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…NEXT delay loops and alternates the winner name with a blank to create a flashing effect without PAUSE.
  • RAND at 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 calls GOSUB 7000 but 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 have CT=2. This appears to be a logic error; the intended check was likely CT=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, not CT=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 to P(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 in A$, 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10252 – 10293.

Related Products

Related Articles

Related Content

Image Gallery

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.

People

No people associated with this content.

Scroll to Top