Card Trick

This file is part of Synchro-Sette November 1983 . Download the collection to get this file.
Date: November 1983
Type: Program
Platform(s): TS 1000
Tags: Game

This program implements the classic “21-card trick” in which a participant mentally selects one of 21 cards dealt face-up in three rows of seven. The deck is stored as a packed string in A$, with each card encoded in exactly three characters (rank plus suit), allowing random selection by indexing into B$ in steps of three. After the user mentally picks a card and identifies its row three times, the program shuffles the columns using a fixed interleave permutation (picking every 7th element starting from positions 1, 8, 15, then 2, 9, 16, etc.) to guarantee the chosen card ends up in the middle of the identified column. Card display uses block-graphic characters to draw playing-card outlines on screen, and the final reveal spells out the full rank and suit name.


Program Analysis

Program Structure

The program is organised into a main flow with five subroutines and a save stub at line 9998. The main flow handles initialisation, three rounds of dealing/shuffling, and the final reveal. The subroutines are:

  • 10001500: Deal a random card from B$ into C$, draw its frame, and print its value.
  • 20002050: Prompt the user to pick a row (1, 2, or 3) using INKEY$.
  • 30003100: Redisplay cards from D$ during the second shuffle display.
  • 40004100: Redisplay cards from E$ during the third shuffle display.
  • 50005160: Compact C$ by removing blank entries, shifting non-blank entries to the front.

Deck Encoding

The 52-card deck is stored in A$ as a flat string of 156 characters (52 × 3). Each card occupies exactly three characters: two for rank (e.g. "10", " 2", " A") and one for suit (D, H, C, S). A dealt card is marked as used by overwriting its three-character slot in B$ with " " (three spaces). Random selection at line 1030 generates a slot index and retries if that slot is already blank, implementing selection without replacement.

The 21-Card Trick Algorithm

The mathematical core relies on a column-interleave shuffle repeated three times. After the user identifies which of three rows (columns of 7) contains their card, that group of 7 is placed in the middle column of 21 cards by applying a fixed permutation. The permutation used at lines 180–201, 500–521 maps positions as follows:

Output indexSource index (first shuffle)
1C$(1)
2C$(8)
3C$(15)
4C$(2)
5C$(9)
6C$(16)

This is a column-major to row-major reordering of a 7×3 matrix, which is the standard mechanism of the trick. After three repetitions with the user’s row placed in the middle each time, the target card is guaranteed to land at position 11 of 21 (the mathematical centre).

Row Selection and Filtering

Subroutine 2000 waits for a keypress with character code 29, 30, or 31 (the ZX Spectrum digit keys “1”, “2”, “3” respectively as returned by INKEY$) and converts the result to an integer G via VAL G$. After each round, the non-selected rows are blanked: the loop at lines 220–240 (and equivalents at 530–540, 710–720) sets entries outside the range G*7-6 to G*7 to " ".

Card Frame Drawing

Each card is drawn using block-graphic escape sequences to form a bordered rectangle five lines tall. Subroutine 1000 at line 1020 prints the frame at screen position (X, Y); the rank (up to two characters) is printed at row X+1, Y+1 and the suit character at row X+3, Y+2. The final reveal at lines 950–960 draws a larger single card frame in the centre of the screen using the same technique.

Card Grid Layout

The 21 cards are laid out in a 3×7 grid using nested FOR loops. The outer loop steps X from 2 to 14 in steps of 6 (three rows), and the inner loop steps Y from 3 to 27 in steps of 4 (seven columns). This gives a compact grid that fits the 32-column display.

Rank and Suit Name Lookup

Lines 921–937 perform a sequential IF-chain to convert the stored rank character(s) to a word (e.g. "A""ACE") and suit letter to a word (e.g. "H""HEARTS"). The ten is handled specially at line 930 by comparing the first two characters: G$( TO 2)="10". The suit character is always read from position 3: G$(3).

Notable Techniques

  • The B$ string acts as a “used card” bitfield by zeroing dealt slots, avoiding a separate Boolean array.
  • Subroutine 5000 is a compaction routine that left-packs non-blank entries in C$, avoiding the need to track sparse indices.
  • Lines 541–558 apply the same compaction logic inline for D$ between the second and third rounds.
  • Lines 560–610 cross-reference C$ against D$ to retain only cards that appear in both, further narrowing the candidate set.
  • Lines 740–810 and 820–860 similarly cross-reference E$ against C$ to identify the final card.
  • SAVE "CARDTRIC%K" at line 9998 uses the ZX text escape %K to store the filename with an inverse-video K, a cosmetic flourish in the save name.

Bugs and Anomalies

  • The row-input subroutine at line 2000 checks CODE G$<29 OR CODE G$>31, but on the ZX Spectrum the digit keys “1”, “2”, “3” return character codes 49, 50, 51. Codes 29–31 correspond to keyword tokens, not digit characters. This means the INKEY$ comparison as written will never match and the subroutine will loop forever unless the machine this runs on maps numeric keys differently than standard.
  • Lines 820–860 use FOR N=1 TO 3 nested over FOR I=1 TO 7 to find the card in E$, but there is no NEXT N statement—control falls through from line 860 to line 900 regardless of whether a match was found, which means N retains its last value (3) if no match occurs, potentially printing the wrong card.
  • The shuffle permutation is deterministic (not random), so the “shuffle” displayed on screen is cosmetic only; the mathematical interleave is hardcoded across lines 180–201 etc.

Content

Appears On

Cassette to accompany the November 1983 issue of Synchro-Sette.

Related Products

Related Articles

Related Content

Image Gallery

Card Trick

Source Code

  10 LET A$="A D2 D3 D4 D5 D6 D7 D8 D9 D10DJ DQ DK DA H2 H3 H4 H5 H6 H7 H8 H9 H10HJ HQ HK HA C2 C3 C4 C5 C6 C7 C8 C9 C10CJ CQ CK CA S2 S3 S4 S5 S6 S7 S8 S9 S10SJ SQ SK S"
  20 LET B$=A$
  30 DIM C$(21,3)
  40 DIM D$(21,3)
  50 DIM E$(21,3)
  80 LET A=0
  90 LET H$="010203040506070809101112131415161718192021"
 100 CLS 
 105 PRINT AT 4,0;1;AT 10,0;2;AT 16,0;3
 110 FOR X=2 TO 14 STEP 6
 120 FOR Y=3 TO 27 STEP 4
 130 GOSUB 1000
 140 NEXT Y
 150 NEXT X
 160 GOSUB 2000
 165 PRINT AT 0,8;"SHUFFLING"
 180 LET D$(1)=C$(1)
 181 LET D$(2)=C$(8)
 182 LET D$(3)=C$(15)
 183 LET D$(4)=C$(2)
 184 LET D$(5)=C$(9)
 185 LET D$(6)=C$(16)
 186 LET D$(7)=C$(3)
 187 LET D$(8)=C$(10)
 188 LET D$(9)=C$(17)
 189 LET D$(10)=C$(4)
 190 LET D$(11)=C$(11)
 191 LET D$(12)=C$(18)
 192 LET D$(13)=C$(5)
 193 LET D$(14)=C$(12)
 194 LET D$(15)=C$(19)
 195 LET D$(16)=C$(6)
 197 LET D$(17)=C$(13)
 198 LET D$(18)=C$(20)
 199 LET D$(19)=C$(7)
 200 LET D$(20)=C$(14)
 201 LET D$(21)=C$(21)
 210 LET A=0
 220 FOR N=1 TO 21
 230 IF N<G*7-6 OR N>G*7 THEN LET C$(N)="   "
 240 NEXT N
 250 GOSUB 5000
 410 PRINT AT 0,8;"SHUFFLING"
 430 FOR X=2 TO 14 STEP 6
 440 FOR Y=3 TO 27 STEP 4
 450 GOSUB 3000
 460 NEXT Y
 470 NEXT X
 480 PRINT AT 0,8;"         "
 490 GOSUB 2000
 500 LET E$(1)=D$(1)
 501 LET E$(2)=D$(8)
 502 LET E$(3)=D$(15)
 503 LET E$(4)=D$(2)
 504 LET E$(5)=D$(9)
 505 LET E$(6)=D$(16)
 506 LET E$(7)=D$(3)
 507 LET E$(8)=D$(10)
 508 LET E$(9)=D$(17)
 509 LET E$(10)=D$(4)
 510 LET E$(11)=D$(11)
 511 LET E$(12)=D$(18)
 512 LET E$(13)=D$(5)
 513 LET E$(14)=D$(12)
 514 LET E$(15)=D$(19)
 515 LET E$(16)=D$(6)
 517 LET E$(17)=D$(13)
 518 LET E$(18)=D$(20)
 519 LET E$(19)=D$(7)
 520 LET E$(20)=D$(14)
 521 LET E$(21)=D$(21)
 525 LET A=0
 530 FOR N=1 TO 21
 535 IF N<G*7-6 OR N>G*7 THEN LET D$(N)="   "
 540 NEXT N
 541 LET B=1
 542 FOR N=1 TO 21
 544 IF D$(N)<>"   " THEN GOTO 550
 546 NEXT N
 548 GOTO 560
 550 LET D$(B)=D$(N)
 552 LET B=B+1
 554 NEXT N
 556 FOR N=B+1 TO 21
 557 LET D$(N)="   "
 558 NEXT N
 560 FOR N=1 TO 7
 565 LET C=0
 570 FOR I=1 TO 7
 580 IF C$(N)=D$(I) THEN LET C=1
 590 NEXT I
 600 IF C=0 THEN LET C$(N)="   "
 610 NEXT N
 615 GOSUB 5000
 620 PRINT AT 0,8;"SHUFFLING"
 630 FOR X=2 TO 14 STEP 6
 640 FOR Y=3 TO 27 STEP 4
 650 GOSUB 4000
 660 NEXT Y
 670 NEXT X
 680 PRINT AT 0,8;"         "
 690 GOSUB 2000
 700 LET A=0
 710 FOR N=1 TO 21
 715 IF N<G*7-6 OR N>G*7 THEN LET E$(N)="   "
 720 NEXT N
 740 LET C=1
 750 FOR I=1 TO 21
 760 IF E$(I)<>"   " THEN GOTO 790
 770 NEXT I
 780 GOTO 820
 790 LET E$(C)=E$(I)
 800 LET C=C+1
 810 NEXT I
 820 FOR N=1 TO 3
 830 FOR I=1 TO 7
 840 IF C$(N)=E$(I) THEN GOTO 900
 850 NEXT I
 860 NEXT N
 900 CLS 
 910 PRINT AT 1,0;"YOUR CARD IS"
 920 LET G$=C$(N)
 921 IF G$(1)="A" THEN LET O$="ACE"
 922 IF G$(1)="2" THEN LET O$="TWO"
 923 IF G$(1)="3" THEN LET O$="THREE"
 924 IF G$(1)="4" THEN LET O$="FOUR"
 925 IF G$(1)="5" THEN LET O$="FIVE"
 926 IF G$(1)="6" THEN LET O$="SIX"
 927 IF G$(1)="7" THEN LET O$="SEVEN"
 928 IF G$(1)="8" THEN LET O$="EIGHT"
 929 IF G$(1)="9" THEN LET O$="NINE"
 930 IF G$( TO 2)="10" THEN LET O$="TEN"
 931 IF G$(1)="J" THEN LET O$="JACK"
 932 IF G$(1)="Q" THEN LET O$="QUEEN"
 933 IF G$(1)="K" THEN LET O$="KING"
 934 IF G$(3)="H" THEN LET P$="HEARTS"
 935 IF G$(3)="D" THEN LET P$="DIAMONDS"
 936 IF G$(3)="S" THEN LET P$="SPADES"
 937 IF G$(3)="C" THEN LET P$="CLUBS"
 940 PRINT "THE ";O$;" OF ";P$
 950 PRINT AT 10,10;"\:'\''\''\: ";AT 11,10;"\:   \: ";AT 12,10;"\:   \: ";AT 13,10;"\:   \: ";AT 14,10;"\:.\..\..\: "
 955 PRINT AT 11,11;G$( TO 2)
 960 PRINT AT 13,12;G$(3)
 970 PAUSE 40000
 980 CLS 
 990 RUN 
\n1000 LET A=A+1
\n1020 PRINT AT X,Y;"\:'\''\''\: ";AT X+1,Y;"\:   \: ";AT X+2,Y;"\:   \: ";AT X+3,Y;"\:   \: ";AT X+4,Y;"\:.\..\..\: "
\n1030 LET Z=INT (52*RND)+1
\n1050 IF B$(Z*3-2 TO Z*3)="   " THEN GOTO 1030
\n1070 LET C$(A)=B$(Z*3-2 TO Z*3)
\n1090 LET B$(Z*3-2 TO Z*3)="   "
\n1100 PRINT AT X+1,Y+1;C$(A, TO 2)
\n1110 PRINT AT X+3,Y+2;C$(A,3)
\n1500 RETURN 
\n2000 PRINT AT 21,0;" WHICH ROW? ";AT 21,0;"% %W%H%I%C%H% %R%O%W%?% "
\n2010 LET G$=INKEY$
\n2020 IF CODE G$<29 OR CODE G$>31 THEN GOTO 2000
\n2030 LET G=VAL G$
\n2040 PRINT AT 21,0;"            "
\n2050 RETURN 
\n3000 LET A=A+1
\n3040 PRINT AT X+1,Y+1;D$(A, TO 2)
\n3060 PRINT AT X+3,Y+2;D$(A,3)
\n3100 RETURN 
\n4000 LET A=A+1
\n4040 PRINT AT X+1,Y+1;E$(A, TO 2)
\n4060 PRINT AT X+3,Y+2;E$(A,3)
\n4100 RETURN 
\n5000 LET B=1
\n5010 FOR N=1 TO 21
\n5020 IF C$(N)<>"   " THEN GOTO 5100
\n5030 NEXT N
\n5040 GOTO 5130
\n5100 LET C$(B)=C$(N)
\n5110 LET B=B+1
\n5120 NEXT N
\n5130 FOR N=B+1 TO 21
\n5140 LET C$(N)="   "
\n5150 NEXT N
\n5160 RETURN 
\n9998 SAVE "CARDTRIC%K"
\n9999 RUN 

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

People

No people associated with this content.

Scroll to Top