--- title: "Yachtzee" id: 57499 type: "computer_media" slug: "yachtzee" url: "http://localhost/computer_media/yachtzee/" markdown_url: "http://localhost/computer_media/yachtzee.md" published_at: "2024-10-05T21:06:18+00:00" modified_at: "2026-04-03T07:58:27+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/254_Yatz.png" excerpt: "A full multiplayer Yahtzee implementation with up to four players, three-throw turns, and a 12-category scorecard packed into a single layout string." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 56737 title: "Timex Sinclair Public Domain Library Tape 1006" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1006/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/254_Yatz.png" media_type_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–9970** – `CLEAR` / `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 | 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 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. ## 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)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 ```