Patience

Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Game

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:

PositionContent
1Face letter/digit (A, 2–9, \a=10, J, Q, K)
2–3Numeric value as two-digit string (e.g., “01” for Ace, “11” for Jack)
4Suit symbol character from b$
5INK 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.

Content

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top