--- title: "Patience" id: 71236 type: "computer_media" slug: "patience" url: "http://localhost/computer_media/patience/" markdown_url: "http://localhost/computer_media/patience.md" published_at: "2026-08-30T20:20:03+00:00" modified_at: "2026-08-30T20:20:03+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/Patience-1.png" alt: "Patience screen" excerpt: "A solitaire card game that renders fully pip-illustrated playing cards on screen and challenges you to clear the deck by matching pairs totaling eleven or J-Q-K runs." 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/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Patience%20%28198x%29%28-%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/08/Patience-1.png" alt: "Patience screen" - url: "http://localhost/wp-content/uploads/2026/08/Patience-2.png" alt: "Patience screen" media_type_tags: "Game" --- # Patience This program implements the card game “11-Up Patience,” a solitaire variant where the player covers pairs of non-picture cards totaling eleven (Ace = 1) or a Jack-Queen-King run. Nine cards are laid out in a 3×3 grid, with a ninth central card slot for dealing when no moves are available. The deck is represented as a string variable `p$` where each card occupies a 5-character record encoding face value, suit symbol, and ink color, and shuffling is accomplished by 60 iterations of string slicing and concatenation rather than any array-based Fisher-Yates algorithm. Card rendering at lines 1260–1390 draws pip layouts for each face value using block graphics and UDG characters, including distinct multi-row patterns for Jack, Queen, and King. The program uses DEF FN functions to map card positions (1–9) to screen coordinates, streamlining the PRINT AT placement arithmetic throughout. *** ### Program Structure The program is organized as a set of subroutines branching from a central game loop. The main sections are: - **Lines 1020–1030:** DEF FN definitions and initialization preamble. - **Lines 1040–1090:** Game setup — shuffling, dealing, and the main input loop. - **Lines 1090–1220:** Input validation and game-move processing. - **Lines 1250–1390:** Card-printing subroutine with pip layout logic. - **Lines 1400–1490:** Pack preparation and shuffling routine. - **Lines 1510–1590:** End-game handling (win/loss/replay). - **Lines 1600–1680:** Title screen and instructions. - **Lines 1690–1750:** Animated instruction text display and variable initialization. - **Lines 1760–1850:** UDG graphics loader (tape-stop prompt, DATA, POKE USR). - **Line 9990:** SAVE with autostart at the graphics loader. ### Data Representation The entire 52-card deck is stored as the string variable `p$`, where each card occupies exactly 5 characters: | Position | Content | | --- | --- | | 1 | Face letter/digit (A, 2–9, `\a`=10, J, Q, K) | | 2–3 | Numeric value as two-digit string (e.g., “01” for Ace, “11” for Jack) | | 4 | Suit symbol character from `b$` | | 5 | INK color digit (0 for red suits, 2 for black suits — note: `COL=0` for P=1,3 gives red, `COL=2` gives black, which maps to INK 0=black and INK 2=red on Spectrum; the logic appears inverted but the coloring is set at line 1430) | The source template `d$` at line 1410 encodes all 13 face values in 3-character groups. Cards are assembled into `a$` by iterating over suits via `b$`, then `p$` is assigned from `a$`. The nine on-screen card positions each have their current face value tracked in the 2D string array `r$(9,5)`, which stores just the numeric value portion (characters 2–3) of each card’s 5-character record. ### Coordinate Mapping via DEF FN Two DEF FN functions centralize the screen coordinate logic for the 3×3 grid plus central position: - `FN c(x)` — returns the column (x-coordinate) for card position `x`, encoding the three columns at offsets 6, 12, 18, and 24. - `FN d(x)` — returns the row (y-coordinate), stepping by 6 rows per tier, with a special case for positions above 4 and between 4 and 9. These are called repeatedly throughout the dealing (line 1060–1070) and move-processing (line 1220) routines to avoid duplicated arithmetic. ### Shuffling Algorithm Shuffling (lines 1470–1480) performs 60 iterations. On each pass, a random 5-card block position `A` is selected. On even iterations the block is moved to the front; on odd iterations it is moved to the end. This is a cut-based string shuffle rather than a statistically uniform permutation, but provides adequate randomization for gameplay. A `BEEP` is sounded on each iteration to provide audiovisual feedback during the shuffle animation. ### Input Validation The input loop (lines 1090–1200) is thorough: 1. Length check — rejects inputs longer than 3 characters. 2. Character check — rejects any non-digit character via `CODE` comparison against 48–57. 3. Duplicate position check — rejects entries where two or more card positions are the same (using sum-of-equality-booleans idiom at lines 1130–1140). 4. Single-card input validation — only position “9” (the center deal card) is legal as a lone entry. 5. Sum validation — two-card entries must total 11; three-card entries must total 36 (i.e., J+Q+K = 11+12+13). Error handling routes through the subroutine at line 1230 via the variable `H` (set to 1230 at line 1730), and the main game loop is retried via `GO TO G` where `G`=1100. This is a standard BASIC variable-as-line-number idiom used to make the target address modifiable at runtime. ### Card Rendering The subroutine at lines 1260–1390 draws each card using `PRINT AT` statements. The approach: - A white (PAPER 7) rectangle is printed first to clear the card area, with height adjusted dynamically based on the row position (`y`). - The face letter `f$` and suit symbol `e$` are placed in the top-left and bottom-right corners. - Pip positions for numeric cards (Ace through 10) are rendered using a series of `IF` guards checking `f$`, each printing the suit symbol at the appropriate sub-cell offsets. - Court cards (J, Q, K) use multi-character block graphic strings to draw representational figures. - The UDG character `\a` (loaded at lines 1780–1840) represents the 10 card face, since a two-character “10” would not fit in a single character field. ### UDG Graphics Five UDGs (`\a` through `\e`) are defined in the loader section (lines 1760–1840). The DATA statements provide 8-byte bitmap patterns for each. These are POKEd into memory via `USR CHR$ (97+N)`. The suit symbols for spades, clubs, diamonds, and hearts are stored in `b$` using these UDGs. The graphics loader is placed first in the execution order (via the SAVE autostart at line 9990), so UDGs are ready before the main game runs. ### End-Game Logic The variable `RES` flags a resignation (line 1150 sets `RES=1` when input is “0”). The end-game routine at line 1510 checks `RES` to branch between a loss message with a descending tone sequence and a win message with a rising arpeggio. The replay option (lines 1570–1590) re-runs initialization and the shuffle subroutine before jumping back to line 1050, allowing multiple games without reloading. ### Notable Techniques and Idioms - `GO TO G` and `GO SUB H` — variables used as line numbers for flexible jump targets (lines 1730). - Boolean arithmetic in DEF FN — `FN c(x)` and `FN d(x)` use Spectrum boolean (0/1) expressions multiplied by offsets to compute positions without IF branches. - Sum-of-booleans for duplicate detection — e.g., `(Z(1)=Z(2))+(Z(1)=Z(3))+(Z(2)=Z(3))` at line 1140 returns non-zero if any pair matches. - Animated instruction display (lines 1690–1700) — each character of each instruction line is printed one position at a time with a brief PAUSE and BEEP, creating a typewriter effect. - PAUSE 0 / INKEY$ pattern — used at lines 1560–1590 for efficient keypress detection after end-game. ### Bugs and Anomalies - Line 1120 uses `VAL Z$(N)` after checking digit codes, but the outer loop variable conflicts: the outer FOR loop at line 1110 uses `N`, and line 1120 continues that loop — this is valid BASIC but the inline `NEXT N` at line 1120 completes the loop started at 1110, which is correct. - Line 1230 contains an INPUT statement used as the error handler, but the branch from it via `GO TO H` (where H=1230) creates a recursive error-prompt loop — intentional design for repeated bad input. - The `FA` variable (a flag for single-card plays) is checked at line 1160 but only set once at line 1170, and is never reset between individual input attempts within a session — this could cause spurious rejection of a legitimate single-card play after a prior single-card move, though the initialization at line 1720 resets it to 0 at game start. - Line 1570 calls `GO SUB 1710` twice (initializing variables redundantly) before calling `GO SUB 1460` (the shuffle loop start, skipping pack assembly at 1400) — this means a replay reuses whatever pack was built initially but reshuffles it, which is functionally acceptable. ## Source Code ``` 1020 DEF FN c(x)=6*(x=2 OR x=6)+12*(x=9)+18*(x=3 OR x=7)+24*(x=4 OR x=8):DEF FN d(x)=2+6*(x>4)+6*(\{18}\{0}x>4 AND x<9) 1030 RANDOMIZE :RANDOMIZE 1040 GO SUB 1600:BORDER 4:PAPER 4:INK 0:CLS :GO SUB 1710:GO SUB 1400:GO SUB 1500 1050 REM *PRINT STARTING HAND* 1060 LET a=1:FOR n=1 TO 44 STEP 5:LET x= FN c(a)+2:LET y= FN d(a)+7:PRINT AT y,x; PAPER 6; INK 0;" ";A;" ":LET a=a+1:NEXT n 1070 LET a=1:FOR n=1 TO 44 STEP 5:LET x= FN c(a):LET y= FN d(a):LET c$=p$(n TO n+4):LET r$(a)=c$(2 TO 3):GO SUB 1260:LET a=a+1:NEXT n:LET CD=9 1080 LET p$=p$(46 TO ) 1090 PRINT AT 21,13; PAPER 5; INK 0;" "; AT 19,13;"CARDS"; AT 20,13;"LEFT "; AT 21,15;52-CD:INPUT ; AT 0,0;"ENTER POSITION OF CARDS TO BE"; AT 1,0;"COVERED eg. 35 (0 TO RESIGN)"; LINE Z$:IF Z$="" THEN GO SUB H 1100 IF LEN Z$>3 THEN GO SUB H:GO TO G 1110 DIM Z(LEN Z$):FOR N=1 TO LEN Z$:IF CODE Z$(N)<48 OR CODE Z$(N)>57 THEN GO SUB H:GO TO G 1120 LET Z(N)=\{18}\{0}(VAL Z$(N)):NEXT N:IF LEN Z$=1 AND Z$(1) <>"9" AND Z$(1) <>"0" THEN GO SUB h:GO TO g 1130 IF LEN Z$=2 THEN LET FA=0:IF (Z(1)=Z(2)) THEN GO SUB h:GO TO g 1140 IF LEN Z$=3 THEN LET FA=0:IF (Z(1)=Z(2))+(Z(1)=Z(3))+(Z(2)=Z(3)) THEN GO SUB H:GO TO G 1150 IF VAL Z$=0 THEN LET RES=1:GO TO 1510 1160 IF FA THEN GO SUB H:GO TO G 1170 IF LEN Z$=1 THEN LET FA=FA+1 1180 FOR N=1 TO LEN Z$:LET T=T+ VAL R$(Z(N)):NEXT N:IF T <>11 AND T <>36 AND LEN Z$ <>1 THEN GO SUB H:LET T=0:GO TO G 1190 IF T=11 AND LEN Z$ <>2 THEN GO SUB H:LET T=0:GO TO G 1200 IF T=36 AND LEN Z$ <>3 THEN GO SUB H:LET T=0:GO TO G: 1210 FOR N=1 TO LEN Z$:LET C$=P$(1 TO 5):LET P$=P$(6 TO ):LET CD=CD+1:IF CD=52 THEN GO TO 1510 1220 LET X= FN C(Z(N)):LET Y= FN D(Z(N)):GO SUB 1260:LET R$(Z(N))=C$(2 TO 3):NEXT N:LET T=0:GO TO 1090 1230 :INPUT ; AT 0,0;"INPUT UNACCEPTABLE"; AT 1,0;"PLEASE ENTER AGAIN"; LINE Z$:IF Z$="" THEN GO TO H 1240 RETURN 1250 REM **PRINT CARD** 1260 INK VAL c$(5):LET e$=c$(4):LET f$=c$(1) 1270 PAPER 7:FOR m=y TO 8+12*(y>10)+6*(y=8):PRINT AT m,x+1; INK 0;" ":NEXT m:PRINT AT y,x+1;f$; AT y+6,x+5; 1280 PRINT AT y+1,x+1;e$; AT y+5,x+5; 1290 IF (F$="A")+(F$="3")+(F$="5")+(F$="9") THEN PRINT AT Y+3,X+3;E$ 1300 IF (F$="2")+(F$="3") THEN PRINT AT Y+2,X+3;E$; AT Y+4,X+3;E$ 1310 IF (F$="4")+(F$="5")+(F$="8")+(F$="9")+(F$="\a") THEN PRINT AT Y+2,X+2;E$; AT Y+2,X+4;E$; AT Y+4,X+2;E$; AT y+4,x+4;e$ 1320 IF (F$="6")+(F$="7") THEN PRINT AT Y+1,X+2;E$; AT Y+1,X+4;E$; AT Y+3,X+2;E$; AT Y+3,X+4;E$; AT Y+5,X+2;E$; AT Y+5,X+4;E$ 1330 IF (F$="7") THEN PRINT AT Y+3,X+3;E$ 1340 IF (F$="8")+(F$="9")+(F$="\a") THEN PRINT AT Y+1,X+2;E$; AT Y+1,X+4;E$; AT Y+5,X+2;E$; AT Y+5,X+4;E$ 1350 IF (F$="\a") THEN PRINT AT Y+3,X+2;E$; AT Y+3,X+4;E$ 1360 IF F$="J" THEN PRINT AT Y+1,X+3;"\..\.."; AT Y+2,X+4;"\: "; AT Y+3,X+4;"\: "; AT Y+4,X+2;"\ : \: "; AT Y+5,X+2;"\ '\''\' " 1370 IF F$="Q" THEN PRINT AT Y+1,X+2;"\ .\..\. "; AT Y+2,X+2;"\ :\ \: "; AT Y+3,X+2;"\ :\ \: "; AT Y+4,X+2;"\ :\ .\: "; AT Y+5,X+2;"\ '\':\' "; AT Y+6,X+3;"\ '\' " 1380 IF F$="K" THEN PRINT AT Y+1,X+2;"\: \ :\: "; AT Y+2,X+2;"\: \::"; AT Y+3,X+2;"\::\: "; AT Y+4,X+2;"\: \::"; AT Y+5,X+2;"\: \ :\: " 1390 RETURN 1400 REM **SET UPPACK** 1410 LET a$="":LET d$="A01202303404505606707808909\a10J11Q12K13" 1420 PRINT AT 8,9; INK 1; PAPER 5;B$;B$;B$;B$; AT 10,10; FLASH 1; PAPER 7; INK 2;"PREPARING PACK"; AT 12,9; FLASH 0; PAPER 5; INK 1;B$;B$;B$;B$ 1430 FOR Q=1 TO 39 STEP 3:FOR P=1 TO 4:LET COL=0:IF P=1 OR P=3 THEN LET COL=2 1440 LET A$=A$+D$(Q TO Q+2)+B$(P)+ STR$ COL 1450 NEXT P:NEXT Q 1460 CLS :PRINT AT 8,9;; PAPER 5; INK 1;B$;B$;B$;B$; AT 10,12;; PAPER 7; FLASH 1;"SHUFFLING"; AT 12,9; PAPER 5; INK 1; FLASH 0;B$;B$;B$;B$ 1470 FOR N=1 TO 60:LET A=1+(5*(1+ INT (RND*50))):IF N/2= INT (N/2) THEN LET A$=A$(A TO A+4)+A$( TO A-1)+A$(A+5 TO ):BEEP .01,N 1480 IF N/2 <> INT (N/2) THEN LET A$=A$( TO A-1)+A$(A+5 TO )+A$(A TO A+4):BEEP .01,N+10 1490 NEXT N:LET P$=A$:CLS :RETURN 1500 INPUT "PRESS ENTER TO CONTINUE "; LINE z$:BEEP .05,10:RETURN 1510 REM **ENDGAME** 1520 PAPER 5:INK 1:FOR N=12 TO 21:PRINT AT N,0; PAPER 5;" ":NEXT N 1530 IF RES THEN PRINT AT 13,1;"BAD LUCK: THE CARDS DID NOT "; AT 14,1;"RUN YOUR WAY":FOR N=-10 TO -30 STEP -1:BEEP ABS N/100,N:NEXT N 1540 IF NOT RES THEN PRINT AT 13,1; FLASH 1;"!!!!! WELL DONE !!!!!"; AT 14,1; FLASH 0;"YOUR PATIENCE IS REWARDED":FOR N=1 TO 3:FOR M=10 TO 40 STEP 3:BEEP .01,M:NEXT M:PAUSE 10:NEXT N 1550 PRINT AT 16,3;"YOU MAY"; AT 17,5;"1)PLAY AGAIN"; AT 18,5; AT 19,5;"2)FINISH PLAYING" 1560 PAUSE 0 1570 IF INKEY$="1" THEN BORDER 4:PAPER 4:INK 0:CLS :GO SUB 1710:GO SUB 1710:GO SUB 1460:GO SUB 1500:GO TO 1050 1580 IF INKEY$="2" THEN STOP 1590 PAUSE 0:GO TO 1570 1600 REM INSTRUCTIONS** 1610 LET T$="\ \ \::\::\ \ \::\::\ \ \ \ \ \::\ \ \ \::\ \ \::\::\::\::\ \ \ \ \ \ \ \ \ \ \ \::\ \ \ \::\ \ \ \ \ \::\ \ \ \::\ \ \::\ \ \ \::\ \ \ \ \ \ \ \ \ \ \::\ \ \ \::\ \ \ \ \ \::\ \ \ \::\ \ \::\ \ \ \::\ \ \ \ \ \ \ \ \ \ \::\ \ \ \::\ \ \ \ \ \::\ \ \ \::\ \ \::\::\::\::\ \ \ \ \ \ \ \ \ \ \ \::\ \ \ \:: \::\::\::\ \::\ \ \ \::\ \ \::\ \ \ \ \ \ \ \ \ \ \ \ \ \ \::\ \ \:: \:: \::\ \ \::\ \ \ \ \ \ \ \ \ \ \ \ \ \::\ \ \ \::\ \ \ \ \ \:: \::\ \ \::\ \ \ \ \ \ \ \ " 1620 BORDER 2:PAPER 3:INK 1:CLS :PRINT AT 7,0;; BRIGHT 1;T$:FOR N=5 TO 15 STEP 10:PRINT AT N,8; INK 0; PAPER 6; BRIGHT 1;; FLASH 1;"P A T I E N C E":NEXT N 1630 PRINT #1; AT 0,0;"FOR INSTRUCTIONS PRESS ""1"""; AT 1,0;"OTHERWISE ANY KEY":PAUSE 0:IF INKEY$ <>"1" THEN RETURN 1640 CLS :PRINT AT 1,5; INK 6;"11-UP PATIENCE:RULES ":PAUSE 100 1650 DIM U$(6,30):LET U$(1)="NINE CARDS WILL BE DEALT OUT":LET U$(2)="YOU MUST COVER EITHER :-":LET U$(3)="TWO NON PICTURE CARDS TOTALING":LET U$(4)="ELEVEN (ACE=1) OR ":LET U$(5)="A RUN OF J-Q-K ":LET U=5 1660 GO SUB 1690:GO SUB 1500:LET U$(1)="IF YOU CAN'T MOVE THEN YOU MAY":LET U$(2)="DEALA SINGLE CARD INTO THE":LET U$(3)="CENTER: CARD (9)":LET U$(4)="IF YOU ARE STILL UNABLE TO":LET U$(5)="PLAY THEN YOU HAVE FAILED AND":LET U$(6)="MUST RESIGN.":LET U=6 1670 GO SUB 1690:GO SUB 1500 1680 RETURN 1690 FOR N=2 TO 17:PRINT AT N,1; PAPER 5;" ":NEXT N 1700 LET B=1:FOR N=4 TO 3+(U*2) STEP 2:FOR M=1 TO 30:PRINT AT N,M; PAPER 7; INK 1;"*":PAUSE 2:PRINT AT N,M; PAPER 5;U$(B,M):BEEP .01,0:NEXT M:LET B=B+1:NEXT N 1710 REM ***INIT*** 1720 LET a=1:LET cd=0:LET t=0:LET fa=0:LET res=0 1730 LET G=1100:LET H=1230:DIM r$(9,5) 1740 LET b$="\b\d\c\e" 1750 RETURN 1760 REM **GRAPHICS** 1770 BORDER 2:CLS :PRINT AT 10,2;"STOP THE TAPE PLEASE" 1780 RESTORE 1800:FOR N=0 TO 4:FOR M=0 TO 7:BORDER M:BEEP .01,N 1790 READ A:POKE USR CHR$ (97+N)+M,A:NEXT M:NEXT N:RUN 1800 DATA 0,94,82,82,82,82,94,0 1810 DATA 0,16,56,124,254,124,56,16 1820 DATA 0,108,254,254,124,124,56,16 1830 DATA 16,56,124,124,254,214,84,16 1840 DATA 0,56,56,16,214,254,214,16 1850 RUN 9990 PAPER 7:BORDER 7:INK 0:CLEAR :SAVE "PATIENCE" LINE 1760 ```