Bridge

This file is part of and Miscellaneous Programs. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Game

This program implements a practice bridge hand dealer and card-play trainer. It deals a shuffled 52-card deck into four hands (North, East, South, West), displays them on screen using suit UDGs for spades, hearts, diamonds, and clubs, then allows the user to enter a contract and play out all 13 tricks. The shuffle uses a Fisher-Yates-style algorithm encoded in a string of two-digit card numbers stored in `A$`. Trick-taking logic evaluates played cards numerically, tracking trump and lead suit, and sounds BEEP tones at contract-making or defeating trick counts.


Program Structure

The program is organized into loosely coupled routines, navigated via GO TO and GO SUB. The main flow is:

  1. Lines 1–15: UDG setup and jump to intro/deal entry point.
  2. Lines 670–699: Title screen, instructions, deal invocation, sort, then display.
  3. Lines 600–645: Card shuffle and deck initialization.
  4. Lines 100–150: Selection sort of each hand.
  5. Lines 60–80: Hand display loop.
  6. Lines 250–570: Contract input, card play, trick resolution loop.
  7. Lines 900–920: End-of-hand options (redeal or replay).

Subroutines are used sparingly: GO SUB 20 builds a display string for each suit holding, and GO SUB 100 sorts each hand. Most other logic uses GO TO chains.

UDG Initialization

Lines 5–10 define four UDGs for the suit symbols using POKE USR X$+J,X, reading glyph bitmaps from DATA. The characters loaded are "H" (hearts), "C" (clubs), "D" (diamonds), and "S" (spades), occupying UDG slots corresponding to those letters. These are then referenced in the display string I$="\s\h\d\c" at line 671 and in suit indicator prints throughout the play loop.

Shuffle Algorithm

The deck is encoded in A$ at line 600 as a 104-character string of zero-padded two-digit numbers from "01" to "52". The shuffle loop (lines 610–645) picks a random two-character substring, extracts it into B$(X) and A(X), then removes those two characters from A$ using string slicing. This is a correct partial Fisher-Yates draw-without-replacement. The special case at lines 620–625 handles the final card when LEN A$=2 and issues a RETURN mid-loop — a notable structural quirk that exits the GO SUB 600 call early from inside the FOR loop body.

Hand Sorting

Lines 100–150 implement a selection sort over 13 elements. Variable C is initialized to 12 (step count), and each pass finds the maximum value in the unsorted tail, swapping it to the end. The sort is descending by card number (where Ace=14 is highest). The loop decrements C and returns when C=0. The comment REM FLOAT SORT, SYNC 4:2,20 is a note to the author’s own documentation system.

Hand Display and Suit String Building

The GO SUB 20 routine (lines 20–45) constructs a Procrustean (fixed-capacity) string E$(ED) of up to 10 characters representing a suit holding. It scans the hand array for cards belonging to the current suit offset B, builds a rank string using D$="AKQJ1098765432", and handles the special two-character case "10". The variable V$ is a space character used as a sentinel/padding value throughout the display and erasure logic.

Line 60 uses DATA 0,12,8,20,16,12,8,0 at line 75 to supply screen row/column coordinates for the four hands’ display positions, printing with INK 2 for red suits (hearts and diamonds).

Contract and Play Input

Lines 275–305 validate three separate INPUT fields: declarer direction (H$), denomination (K$: 1–7), and suit/NT (T$: S/H/D/C/N). Each is checked against the lookup string O$="NESWNSHDC1234567" using a FOR loop; invalid input loops back to line 275. This is an efficient single-string multi-field lookup idiom.

The card play input at line 435 accepts rank strings (e.g., "A", "10", "J") validated against the current suit holding R$ using a sliding substring search at lines 450–455. Entering "X" at any input point triggers a return to trick 1 (line 495 via GO TO 80).

Trick Evaluation

The array C(4) stores the effective trick value for each player’s played card. Lines 470–475 assign values: if following the lead suit, the card’s numeric value is used; if playing trump, 13 is added to the value, making any trump beat any non-trump. The winner is determined at lines 500–510 by finding the maximum in C(1..4).

Score Tracking and Audio

Running trick counts are displayed for both N-S and E-W. BEEP calls provide audio feedback at contract-making or defeating thresholds:

  • A short beep (BEEP .25,30 or BEEP .25,-20) sounds on each trick won.
  • A long beep (BEEP 1,0 or BEEP 1,-60) sounds when the contract is made or defeated, computed as VAL K$+6 tricks for declarer or 8-VAL K$ tricks for defenders.

Notable Idioms and Techniques

  • VAL H$ converts direction letters to numeric offsets (N=0 implied by ASCII difference or lookup position) — actually VAL H$ on "N", "E", "S", "W" will return 0; the program relies on O$(R) position for numeric direction via R, but uses VAL H$*4 — this only works correctly if H$ has been set to a digit string, which happens at line 340: H$=O$(R+1) where positions 5–8 of O$ are "N","S","H","D" — actually O$ positions 1–4 are N,E,S,W and 5–8 are re-used as suit chars; this is a latent confusion but the program resets H$ from position-derived values.
  • String boolean expressions like (D$(Y) AND Y<5) select substrings conditionally without IF.
  • RESTORE 315 / READ loops re-read the suit symbol data multiple times during play (lines 476–483).
  • The REM HERE comments on lines 45, 150, and 340 are positional markers indicating jump targets for GO TO statements, a common idiom when the target is mid-routine.

Content

Related Products

Related Articles

Related Content

Image Gallery

Bridge

Source Code

    1 REM  SAVE "DEAL A" AT B35
    5 FOR I=1 TO 4: READ X$: FOR J=0 TO 7: READ X: POKE USR X$+J,X: NEXT J: NEXT I
   10 DATA "H",34,119,127,127,62,62,28,8,"C",28,28,8,107,127,107,8,8,"D",8,28,62,127,62,28,8,0,"S",8,28,62,127,127,127,107,8
   15 GO TO 670
   20 LET ED=ED+1: LET F$="": IF ED=17 THEN LET ED=1: REM  PRINT HAND/SUIT ROUTINE TO...
   25: FOR R=A TO A+12: LET X=A(R): LET Y=X-B: IF Y>0 AND Y<14 THEN GO TO 40
   30 NEXT R
   35 PRINT E$(ED): LET G$(ED)=E$(ED): LET V=V+1: RETURN 
   40 LET F$=F$+(D$(Y) AND Y<5)+("10" AND Y=5)+(D$(Y+1) AND Y>5): LET E$(ED)=F$
   45 GO TO 30: REM  HERE
   60 RESTORE 75: FOR A=1 TO 40 STEP 13: READ V: READ H: FOR B=0 TO 39 STEP 13: PRINT INK (2 AND (B=13 OR B=26));AT V,H;I$(B/13+1);;V$;: GO SUB 20
   65 NEXT B: NEXT A: GO TO 250
   75 DATA 0,12,8,20,16,12,8,0
   80 FOR X=20 TO 21: FOR Y=0 TO 31: PRINT AT X,Y;V$: NEXT Y: NEXT X: GO TO 60
  100 LET C=12: REM  FLOAT SORT, SYNC 4:2,20; TO...
  110 LET K=A: LET Q=A(A)
  115 FOR S=A+1 TO A+C: IF A(S)<Q THEN GO TO 130
  120 LET Q=A(S): LET K=S
  130 NEXT S
  135 LET Z=A(A+C): LET A(A+C)=A(K): LET A(K)=Z
  140 LET C=C-1: IF C=0 THEN RETURN 
  150 GO TO 110: REM  HERE
  250 LET O$="NESWNSHDC1234567": DIM C(4)
  255 LET A=14: LET K=13: LET Q=12: LET J=11
  260 LET N=0: LET E=1: LET S=2: LET W=3
  265 LET H=2: LET D=3: LET C=4
  270 LET I=1: LET TR=1: LET II=0
  275 INPUT "DECLARER?";H$;"CONTRACT?";K$;T$
  280 LET J$=H$: FOR R=1 TO 4: IF H$=O$(R) THEN GO TO 290
  285 NEXT R: GO TO 275
  290 FOR R=10 TO 16: IF K$=O$(R) THEN GO TO 300
  295 NEXT R: GO TO 275
  300 FOR R=5 TO 9: IF T$=O$(R) THEN GO TO 310
  305 NEXT R: GO TO 275: REM  END ERROR TRAPS
  310 FOR M=1 TO 5: READ M$: READ N$: PRINT AT 21,0;H$;": ";K$; INK (2 AND (T$="H" OR T$="D"));N$ AND M$=T$: NEXT M
  315 DATA "S","\s","H","\h","D","\d","C","\c","N","NT"
  320 RESTORE 315
  330 FOR R=1 TO 4: IF H$=O$(R) THEN GO TO 340: REM  PASS PLAY ROUTINE TO...
  335 NEXT R
  340 LET H$=O$(R+1): REM  HERE
  345 PRINT AT 20,0;H$;" TO PLAY"
  350 IF I>1 THEN GO TO 395
  352 LET VV=0: REM  ONE-SUIT HAND ROUTINE...
  355 FOR T=1 TO 4: IF E$(VAL H$*4+T,1)=V$ THEN GO TO 365
  360 LET TT=T: GO TO 367
  365 LET VV=VV+1
  367 NEXT T
  369 IF VV=3 THEN LET S$=O$(TT+5)
  370 IF VV=3 THEN GO TO 385: REM  TO HERE
  375 INPUT "SUIT?";S$: IF S$="X" THEN GO TO 495
  380 IF S$<>"S" AND S$<>"H" AND S$<>"D" AND S$<>"C" THEN GO TO 375
  385 IF I=1 THEN LET W$=S$: REM  W$ IS LEAD;L$ IS WORKING SUIT
  390 LET L$=S$
  395 IF L$="S" THEN LET Z=VAL H$*4+1: REM  "S" ALREADY VALUED FOR SOUTH
  400 IF L$="S" THEN GO TO 410
  405 LET Z=VAL H$*4+VAL L$
  410 FOR R=1 TO 10: IF E$(Z,R)=V$ THEN GO TO 420: REM  R-1 IS # OF VISIBLE CHARACTERS IN PROCRUSTEAN E$
  415 NEXT R
  420 LET R$=E$(Z,1 TO R-1)
  425 IF LEN R$=0 THEN GO TO 352: REM  VOIDS
  430 IF R$="10" OR LEN R$=1 THEN LET C$=R$: GO TO 440: REM  SINGLETONS
  435 INPUT "CARD?";C$: IF C$="X" THEN GO TO 495
  440 IF LEN C$>1 AND C$<>"10" THEN GO TO 435
  445 IF C$="" THEN GO TO 435
  450 FOR R=1 TO LEN R$: IF R$(R TO R+LEN C$-1)=C$ THEN GO TO 460
  455 NEXT R: GO TO 435
  460 LET E$(Z)=R$( TO R-1)+R$(R+LEN C$ TO )
  465 PRINT AT Z-1+(4 AND H$="E")+(8 AND H$="S")-(4 AND H$="W"),14+(8 AND H$="E")-(12 AND H$="W");E$(Z)+((V$+V$) AND E$(Z)=""): REM  REMOVES CARD FROM HAND AND CLOSES UP SUIT
  470 LET C(VAL H$+1)=(VAL C$ AND L$=W$)
  475 IF L$=T$ THEN LET C(VAL H$+1)=VAL C$+13
  476 FOR M=1 TO 4: READ M$: READ N$: IF M$=L$ THEN GO TO 480: REM  READS 315
  477 NEXT M
  480 LET V=10+(2 AND H$="S")-(2 AND H$="N"): LET HZ=14+(2 AND H$="E")-(2 AND H$="W")
  481 PRINT AT V,HZ; INK (2 AND (L$="H" OR L$="D"));N$; INK 0;C$;V$: REM  PLAYS CARD TO CENTER
  483 RESTORE 315
  485 LET I=I+1: IF I<5 THEN GO TO 575
  495 LET I=1: FOR X=8 TO 12 STEP 2: FOR Y=12 TO 18: PRINT AT X,Y;V$: NEXT Y: NEXT X: IF C$="X" OR S$="X" THEN GO TO 80: REM   PICKS UP TRICK WITH ACCEPTABLE DELAY
  500 LET R=1: FOR X=2 TO 4: IF C(R)>C(X) THEN GO TO 510
  505 LET R=X
  510 NEXT X
  515 LET H$=O$(R): PRINT AT 21,20;"E-W": PRINT AT 21,12;"N-S": IF R=1 OR R=3 THEN GO TO 545: REM  PASSES LEAD TO WINNER;E-W TRICK ROUTINE
  520 LET II=II+1: PRINT AT 21,24;II: IF J$="S" OR J$="N" THEN GO TO 535
  525 BEEP .25,30: IF II=VAL K$+6 THEN BEEP 1,0
  530 GO TO 565
  535 BEEP .25,-20: IF II=8-VAL K$ THEN BEEP 1,-60
  540 GO TO 565
  545 PRINT AT 21,16;TR-II: IF J$="E" OR J$="W" THEN GO TO 560: REM  N-S TRICK ROUTINE
  550 BEEP .25,30: IF TR-II=VAL K$+6 THEN BEEP 1,0
  555 GO TO 565
  560 BEEP .25,-20: IF TR-II=8-VAL K$ THEN BEEP 1,-60
  565 LET TR=TR+1: IF TR=14 THEN GO TO 900
  570 GO TO 345
  575 LET L$=W$: GO TO 330: REM  TO FOLLOW LEAD RATHER THAN LAST SUIT PLAYED
  600 LET A$="01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152"
  602 LET ED=0: DIM E$(16,10): DIM G$(16,10): REM  WORKING AND RECORDING SUIT STRINGS
  603 LET D$="AKQJ1098765432": LET V$=" "
  605 DIM B$(52,2): DIM A(52)
  610 FOR X=1 TO 52
  615 LET R=(INT (RND*(53-X))+1)*2-1
  620 IF LEN A$=2 THEN LET A(X)=VAL A$
  625 IF LEN A$=2 THEN RETURN 
  630 LET B$(X)=A$(R TO R+1)
  635 LET A$=A$( TO R-1)+A$(R+2 TO )
  640 LET A(X)=VAL B$(X): REM  CONVERT TO NUMBERS
  645 NEXT X: REM  SYNC 4:2,10
  670 PRINT TAB 5;"PRACTICE BRIDGE HANDS"'
  671 LET I$="\s\h\d\c": FOR I=1 TO 4: PRINT INK (2 AND (I=2 OR I=3));AT 1,I*4+5;I$(I): NEXT I
  672 PRINT : PRINT "Decide how hand should be bid."''
  674 PRINT "Enter contract. Enter suit and" 
  676 PRINT "card to play hand. Forced plays"
  678 PRINT "are automatic."''
  680 PRINT "Input denomination of spot cards"
  682 PRINT "and initial letter of suits and"
  684 PRINT "face cards; then press ENTER."''
  686 PRINT "Illegal inputs will not ENTER."''
  687 PRINT "To change unENTERED input, use"
  688 PRINT "R/L arrows and retype."''
  689 PRINT "To return to trick 1, press ""X""."'''
  690 GO SUB 600
  694 FOR A=1 TO 40 STEP 13: GO SUB 100
  695 NEXT A
  696 PRINT "Press ""ENTER"" to deal hand."
  697 INPUT U$
  699 CLS : GO TO 60
  900 CLS : PRINT "Press R for a new deal." 
  905 PRINT "Press ""X"" for last hand."
  910 IF INKEY$="X" THEN GO TO 920
  912 IF INKEY$="R" THEN RUN 
  915 GO TO 910
  920 CLS : GO TO 60

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

People

No people associated with this content.

Scroll to Top