--- title: "Parchisi" id: 55203 type: "computer_media" slug: "parchisi" url: "http://localhost/computer_media/parchisi/" markdown_url: "http://localhost/computer_media/parchisi.md" published_at: "2024-06-20T11:49:58+00:00" modified_at: "2026-03-30T21:44:37+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/06/Parchisi.png" excerpt: "A fully playable four-player Parcheesi board game with computer opponents, custom pawn graphics, and hex-encoded board paths packed into BASIC strings." 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 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Cedric Bastiaans" slug: "bastiaans-cedric" taxonomy: "indiv" url: "http://localhost/indiv/bastiaans-cedric/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 55220 title: "Long Island Sinclair Timex (LIST) User Group Library Tape #7" type: "computer_media" url: "http://localhost/computer_media/long-island-sinclair-timex-list-user-group-library-tape-7/" media_type: "Program" programmers: - name: "Cedric Bastiaans" slug: "bastiaans-cedric" taxonomy: "indiv" url: "http://localhost/indiv/bastiaans-cedric/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Parchisi%20%28198x%29%28Bastiaans%2C%20Cedric%3B%20Groothedde%2C%20Ferry%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/06/Parchisi.png" - url: "http://localhost/wp-content/uploads/2024/06/Parchisi-2.png" media_type_tags: "Game" --- # Parchisi This program implements a four-player Parcheesi-style board game called “Don’t Be Aggravated,” originally written in Dutch by Ferry Groothedde and translated/adapted by Cedric R. Bastiaans. The game supports zero, one, or two human players competing against computer-controlled opponents, with full rules including entering pawns on a six, capturing, and home-area movement. Board positions are encoded as two-digit hex coordinate pairs packed into strings (b$), allowing compact path representation for each of the four players’ routes around the 11×11 logical grid. Four custom UDG characters (\p, \i, \o, \n) are defined via POKE USR to render the pawn tokens graphically on the board. The computer AI uses a set of subroutines at lines 3000–3560 to evaluate blocking and capturing opportunities depending on the current die value. *** ## Program Analysis ### Program Structure The program is organized into several functional blocks: 1. **Lines 1–5:** REMs, UDG initialization, and variable setup. 2. **Lines 10–50:** Board path encoding, player/pawn initialization, and welcome screen. 3. **Lines 70–180:** Board rendering using PRINT OVER. 4. **Lines 190–290:** Opening dice roll sequence to determine who starts. 5. **Lines 300–590:** Computer move subroutine (auto-play for non-human players). 6. **Lines 880–920:** No-move animation/fallthrough. 7. **Lines 1000–1380:** Human player move subroutine, including input handling and pawn movement logic. 8. **Lines 2000:** Error message for invalid move input. 9. **Lines 3000–3560:** AI helper subroutines checking blocking and capture positions by die value. 10. **Lines 4000–4080:** Entry of a new pawn onto the board on a roll of six. 11. **Lines 5000–5030:** Data initialization for die face display strings and coordinate look-up table. 12. **Lines 6000–6320:** Instructions display and number-of-players selection. 13. **Lines 7000–7040:** Main game loop dispatching turns to each of the four players. 14. **Lines 8000–8540:** Win detection, end-of-game messages, and restart/quit logic. 15. **Lines 9200–9330:** SAVE routine and UDG DATA definitions. ### Board Path Encoding Each player’s route around the board is encoded in `b$(1)` through `b$(4)` as a string of two-digit decimal coordinate pairs packed without delimiters. For example, `b$(2)` begins `" 172737475758595a5b..."` — each pair of characters encodes one board row and one board column as hexadecimal-ish values readable by `VAL`. This allows the program to iterate over path positions with a simple `FOR p=2 TO 80 STEP 2` loop and evaluate `VAL b$(j,p)` and `VAL b$(j,p+1)` for row and column coordinates respectively. Player paths 1, 3, and 4 are derived from player 2’s path by rotating the string slice — `b$(1)` is built from a substring of `b$(2)` offset by 20 positions, then the remaining segment, plus the home stretch. This rotation-by-substring technique avoids duplicating path data and keeps all four routes consistent. ### Board State Array The 11×11 array `a()` tracks the board state. Each cell stores an integer encoding the occupant: | Value | Meaning | | --- | --- | | 0 | Empty | | 1–4 | Human player 4’s pawn number (s array index) | | 5–8 | Computer/player piece (player index + 4) | | 9 | Center/home marker (initialized at a(6,6)=9) | | 11+ | Human player 2’s pawn (t array index + 10) | Pawn positions for the computer players (1 and 3) are stored only in `a()` directly; human players additionally maintain explicit position indices in arrays `s()` (player 4) and `t()` (player 2) that record how far along the path each pawn has traveled. ### Custom UDG Characters Lines 9300–9330 define four UDGs named `\p`, `\i`, `\o`, and `\n` using DATA statements. Line 4 loads them with `FOR f=1 TO 4: READ a$: FOR g=0 TO 7: READ A: POKE USR a$+g,A: NEXT g: NEXT f`. These four characters together form a 2×2 tile representing a pawn token on the board and are printed with color attributes (`PAPER k(j)` and `INK`) to distinguish the four players visually. ### Variable Aliasing for Code Compression The program makes heavy use of small integer variables as aliases to reduce token repetition: - `e=1` — used ubiquitously wherever the literal 1 would appear, saving one byte per use. - `a=10`, `b=11` — used as row/column constants and in arithmetic thresholds. - `j=4` — initially set as the number of players but reused as a loop variable in the main game loop. This is a well-known Sinclair BASIC optimization: assigning frequently used constants to single-letter variables reduces the size of each tokenized line. ### Die Face Display Die faces are rendered as 3-character ASCII art using `d$()` initialized at line 5010 with dot patterns. The `e$()` array at line 5020 stores three-digit strings such as `"525"`, `"153"`, etc., where each digit indexes into `d$()` to select the correct row of the die face for values 1–6. This allows a three-line die face to be printed with a single `FOR p=1 TO 3` loop using `d$(VAL e$(z,p))`. ### Player Turn Dispatch The main loop at line 7000 iterates `j` from 1 to 4. The variable `sp` (set at line 6310 as `CODE s$ - CODE "1"`) encodes how many humans are playing: `sp=-1` means zero humans (computer vs. itself), `sp=0` means one human, `sp=1` means two humans. Turn routing is: - Player 1 (`j=1`) and Player 3 (`j=3`): always GO SUB 3000 (computer AI). - Player 2 (`j=2`): GO SUB 300 (computer) or GO SUB 1000 (human) based on `sp`. - Player 4 (`j=4`): always GO SUB 1000 (human or overridden by sp=-1). ### AI Subroutines (Lines 3000–3560) The computer AI uses a table of subroutines spaced 50 lines apart, dispatched by `GO SUB 2900+100*s` or `GO SUB 2950+100*s` where `s` is the die value. Each subroutine checks a specific board cell to determine whether a capture or block is possible, updating the local variable `v` with the recommended pawn to move. The duplication across lines 3000–3560 — with pairs of subroutines for each die value — reflects the two different home-stretch entry positions for players 2 and 4. ### Key BASIC Idioms - `PAUSE 0` followed by `INKEY$` — standard keypress wait idiom appearing at lines 10, 6055, 6310. - `INPUT ""` — used to flush the keyboard buffer or force a pause at several points. - `AND` used as a conditional multiplier: e.g. `"both " AND sp` at line 8010 prints the word “both” only when `sp` is nonzero. - `GO TO VAL"number"` is not present, but `VAL b$(j,p)` is used to dereference packed coordinate data inline. - `NOT LEN INKEY$` / `LEN INKEY$` pairs for key-down detection loops (lines 210–235, 1060). ### Anomalies and Notable Points - Line 70 uses `PRINT OVER e` (i.e., OVER 1) to draw board path markers as `/\ \/` two-character pairs — the OVER mode allows overlaying without erasing previously drawn content. - Line 550 references `"\p\i"` and `"\o\n"` as UDG character pairs for the 2×2 pawn tile, printed with per-player color attributes set inline. - Lines 8000, 8100, 8200 each begin with `INPUT ""` suggesting they are reached as fall-through targets rather than clean subroutine calls; GO TO jumps from the move subroutines land here directly. - The `d$(5)` row is defined but never referenced, as die values only run 1–6 and `e$()` only uses rows 1–4 of `d$()`. - Lines 6022 and 6024 contain color attribute placeholders mid-string that appear as blank spaces in the listing — these would display colored ink swatches on the actual hardware to illustrate player colors. ## Source Code ``` 1 REM PARCHISI-LIKE GAME 2 REM Written by Ferry Groothedde; authorized translation by CedricBastiaans (only for use by members of the L.I.S.T. group) 3 REM RESET "SINCLAIR GEBRUIKER", a Dutch computer magazine; \* F.Groothedde; \* C.R.Bastiaans 4 FOR f=1 TO 4: READ a$: FOR g=0 TO 7: READ A: POKE USR a$+g,a: NEXT g: NEXT f 5 LET e=1: GO SUB 5000: LET a=10: LET b=11: BRIGHT e: PAPER e: CLS : INK 9: BORDER e: LET u$=" ": FOR p=e TO 6: LET u$(p)=CHR$ 8: NEXT p 10 LET j=4: DIM a(b,b): DIM b$(j,96): LET a(6,6)=9: PRINT "Welcome to""DON'T BE AGGRAVATED!""";'"A Dutch Parcheesi-like Boardgame": PRINT : PRINT " Written by \*Ferry Groothedde";'" Authorized Translation and";'" Adaptation"'" by \*Cedric R. Bastiaans";AT 21,0;"Need Instructions? (Y/N)": PAUSE 0: GO SUB 6000+(310 AND (INKEY$="n" OR INKEY$="N")) 20 LET b$(2)=" 172737475758595a5b6b7b7a7978778797a7b7b6b5a59585757473727161515253545545352515162636465666666666" 30 LET b$(e)=" "+b$(2,62 TO 81)+b$(2,2 TO 61)+"626364656666666666666666" 40 LET b$(3)=" "+b$(e,42 TO 81)+b$(e,2 TO 41)+"6a696867666666666666" 50 LET b$(4)=" "+b$(2,42 TO 81)+b$(2,2 TO 41)+"a69686766666666666666" 70 FOR p=2 TO 80 STEP 2: PRINT OVER e;AT 2*VAL b$(j,p)-2,2*VAL b$(j,p+e);"/\\ \\/": NEXT p 100 FOR p=2 TO 19: PRINT OVER e;AT p,12;"##": NEXT p: PRINT AT a,4;"######## ########";AT b,4;"######## ########" 130 DIM k(4): DIM s(4): DIM t(4): DIM x(4): DIM y(4) 150 FOR p=e TO 4: LET y(p)=4: NEXT p 160 PRINT OVER e;AT e,3;"4";TAB 22;"4";AT 20,3;"4";TAB 22;"4" 170 LET k(2)=4: LET k(3)=6: LET k(4)=2: LET k(e)=7 180 PRINT OVER e;AT 0,2;" ";TAB 21;" ";AT 2,2;" ";TAB 21;" ";AT 19,2;" ";TAB 21;" ";AT 21,2;" ";TAB 21;" " 190 PRINT #e;AT 0,0;"Highest throw starts game ( / ) throws"; 210 IF NOT LEN INKEY$ THEN GO TO 210 215 IF LEN INKEY$ THEN GO TO 215 220 BEEP .1,b: LET s=INT (RND*6+e): PRINT #e;s," throws "; 230 IF sp AND NOT LEN INKEY$ THEN GO TO 230 235 IF LEN INKEY$ AND sp THEN GO TO 235 240 BEEP .1,b: LET z=INT (RND*6+e): PRINT #e;z 250 FOR p=-b TO 50: BEEP .02,p: NEXT p: INPUT "": IF s=z THEN GO TO 190 260 FOR j=2 TO 4: IF j=2 AND s>z THEN LET j=4 270 IF j=4 OR (j=2 AND sp) THEN GO SUB 1000 280 IF j=3 OR (j=2 AND NOT sp) THEN GO SUB 300 290 NEXT j: GO TO 7000 300 LET z=INT (RND*6+e) 310 FOR p=e TO 3: PRINT PAPER k(j); INK 9;AT p+9,27;d$(VAL e$(z,p)): NEXT p 320 IF z=6 THEN FOR p=e TO 100: NEXT p 330 LET v=0: LET w=v 350 IF y(j) AND z=6 THEN GO TO 4000 360 IF x(j)+y(j)=4 THEN GO TO 880 370 FOR p=80 TO 2 STEP -2: LET st=a(VAL b$(j,p),VAL b$(j,p+e)) 380 IF st<>j+4 THEN GO TO 430 390 LET dl=a(VAL b$(j,p+2*z),VAL b$(j,e+p+2*z)) 400 IF dl=a-e THEN GO TO 430 410 IF dl<>j+4 THEN LET v=p 420 IF (p+2*z>80 AND NOT dl) OR (p=2 AND NOT dl) OR (dl AND dl<>j+4) THEN LET w=p 430 NEXT p: IF NOT v THEN GO TO 880 440 IF w THEN LET v=w 450 IF v+2*z>80 THEN LET x(j)=x(j)+e 470 LET aa=VAL b$(j,v): LET aaa=VAL b$(j,v+e): LET ab=VAL b$(j,v+2*z): LET abb=VAL b$(j,v+e+2*z) 500 LET a(aa,aaa)=0: LET aq=a(ab,abb) 510 IF aq<9 AND aq>4 THEN LET y(aq-4)=y(aq-4)+e 520 IF aq>a THEN LET t(aq-a)=0: LET y(2)=y(2)+e 530 IF aq AND aq<5 THEN LET s(aq)=0: LET y(4)=y(4)+e 540 LET a(ab,abb)=j+4 550 PRINT AT 2*aa-2,2*aaa;"/\\";AT 2*aa-e,2*aaa;"\\/": BEEP .1,RND*b: PRINT AT e,3;y(e);AT e,22;y(2);AT 20,3;y(4);AT 20,22;y(3);AT 2*ab-2,2*abb; INK j=e; PAPER k(j);"\p\i";AT 2*ab-e,2*abb;"\o\n": BEEP .1,RND*b 560 IF x(j)=4 THEN GO TO 8000 580 IF z=6 THEN RANDOMIZE : GO TO 300 590 RETURN 880 FOR p=e TO 100: NEXT p 900 FOR p=e TO 3: PRINT PAPER 0; OVER e; INVERSE e;AT p+a-e,27;" ": NEXT p 910 BEEP e,-RND*b: IF z=6 THEN RANDOMIZE : GO TO 300 920 RETURN 1000 IF sp=-e THEN GO TO 300 1010 LET s=INT (RND*6+e) 1020 FOR p=e TO 3: PRINT PAPER k(j); INK 9;AT p+9,27;d$(VAL e$(s,p)): NEXT p 1050 PRINT #e;AT e,e; INVERSE e;"Your move? (0=No Move Possible)" 1060 IF LEN INKEY$ THEN GO TO 1060 1070 LET u$=INKEY$: IF u$<"0" OR u$>"4" THEN GO TO 1070 1080 INPUT "": BEEP .05,a: LET v=VAL u$: IF v THEN GO TO 1200 1100 IF s=6 THEN GO TO 1000+(50 AND y(j)) 1120 RETURN 1200 IF s<6 AND NOT (s(v) AND j=4)+(t(v) AND j=2) THEN GO TO 1050 1202 IF j=4 AND a(b,5) AND a(b,5)<5 THEN GO SUB 2900+100*s 1203 IF j=2 AND a(e,7)>=a THEN GO SUB 2950+100*s 1205 IF (s(v) AND j=4)+(t(v) AND j=2)+s>44 OR (s(v) AND j=4)+(t(v) AND j=2)>40 THEN GO TO 1050 1207 IF j=4 THEN IF s<6 OR NOT y(j) OR (a(b,5) AND a(b,5)<5) THEN GO TO 1260 1208 IF j=2 THEN IF s<6 OR NOT y(j) OR a(e,7)>a THEN GO TO 1280 1210 IF (t(v) AND j=2) OR (s(v) AND j=4) THEN GO TO 2000 1215 BEEP e,b: IF j=2 THEN GO TO 1230 1220 LET s(v)=e: LET y3=b: LET y4=5: GO TO 1240 1230 LET t(v)=e: LET y3=e: LET y4=7 1240 LET y(j)=y(j)-e: PRINT AT 20,3;y(4);AT e,22;y(2): LET l=a(y3,y4): GO TO 1335 1260 LET y1=VAL b$(j,2*s(v)): LET y2=VAL b$(j,e+2*s(v)): LET y3=VAL b$(j,2*(s+s(v))): LET y4=VAL b$(j,e+2*(s+s(v))) 1270 GO TO 1300 1280 LET y1=VAL b$(j,2*t(v)): LET y2=VAL b$(j,e+2*t(v)): LET y3=VAL b$(j,2*(s+t(v))): LET y4=VAL b$(j,e+2*(s+t(v))) 1300 LET l=a(y3,y4) 1305 IF (l AND l<5 AND j=4) OR (l>a AND j=2) THEN GO TO 1050 1310 PRINT AT 2*y1-2,2*y2;"/\\";AT 2*y1-e,2*y2;"\\/" 1320 LET a(y1,y2)=0: IF j=2 THEN LET t(v)=t(v)+s: LET x(j)=x(j)+(t(v)>40): GO TO 1335 1330 LET s(v)=s(v)+s: LET x(j)=x(j)+(s(v)>40) 1335 IF l>a THEN LET t(l-a)=0: LET y(2)=y(2)+e 1337 IF l>4 AND l4 THEN LET v=a(b,5) 3010 RETURN 3050 IF a(2,7)4 THEN LET v=a(b,5) 3110 RETURN 3150 IF a(3,7)4 THEN LET v=a(b,5) 3210 RETURN 3250 IF a(4,7)4 THEN LET v=a(b,5) 3310 RETURN 3350 IF a(5,7)4 THEN LET v=a(b,5) 3410 RETURN 3450 IF a(5,8)4 THEN LET v=a(b,5) 3510 RETURN 3550 IF a(5,9)a THEN LET t(aa-a)=0: LET y(2)=y(2)+e 4040 IF aa>4 AND aae THEN GO TO 6310 6320 CLS : RETURN 7000 RANDOMIZE : FOR j=e TO 4 7010 IF j=e OR j=3 THEN GO SUB 3000 7020 IF j=2 THEN GO SUB 300+(700 AND sp) 7030 IF j=4 THEN GO SUB 1000 7040 NEXT j: GO TO 7000 8000 IF sp=-e THEN GO TO 8500 8010 INPUT "": PRINT #e;AT 0,0;"You have ";"both " AND sp;"lost the game": GO TO 8500 8100 INPUT "": PRINT #e;AT 0,0;" has won the game!": GO TO 8500 8200 INPUT "": IF sp THEN PRINT #e;AT 0,0;" has won the game!": GO TO 8500 8210 PRINT #e;AT 0,0;"You have won the game!" 8500 PRINT #e;AT e,0;"Another game? (y/n)", 8510 IF LEN INKEY$ THEN GO TO 8510 8520 IF NOT LEN INKEY$ THEN GO TO 8520 8530 IF INKEY$="n" OR INKEY$="N" THEN NEW 8540 RUN 9200 CLEAR : SAVE "parchisi" LINE 1: VERIFY "" 9300 DATA "\p",255,255,254,252,252,254,254,252 9310 DATA "\i",255,255,63,31,31,63,63,31 9320 DATA "\o",252,248,248,240,240,224,255,255 9330 DATA "\n",31,15,15,7,7,3,255,255 ```