Black Jack

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

This program implements a text-based Blackjack card game for one player against a computer house dealer. It defines four custom UDG characters (H, C, D, S) to represent the card suit symbols Hearts, Clubs, Diamonds, and Spades, loaded via POKE USR. The deck is represented as an array of 52 cards shuffled using a Fisher-Yates-style random swap loop, with suit and value extracted arithmetically. Card display uses color-coded INK (red for even-numbered suits, black for odd) and each card is outlined with PLOT/DRAW box-drawing. The game tracks a running money total, animates winnings/losses with a counting loop and BEEP tones, and supports multiple hands per session with a replay option.


Program Analysis

Program Structure

The program is organized into a main game loop (lines 200–410) with several subroutines handling distinct responsibilities. Execution flows from initialization (lines 10–140) into a 5-hand game loop, calling subroutines for screen clearing, card dealing, and money animation. The subroutine layout is:

  • Lines 500–540: Draw a single card at a given screen position
  • Lines 650–690: Animate the money counter up or down
  • Lines 800–840: Deal the initial two-card hand for player or house
  • Lines 850–880: Deal one additional “twist” card
  • Lines 900–930: Clear the message and card areas of the screen

UDG Suit Symbols

Lines 20–30 load four custom UDG characters corresponding to the letters H, C, D, and S (Hearts, Clubs, Diamonds, Spades). Each character is defined by 8 bytes POKEd into memory starting at USR x$, where x$ is the character letter. Line 60 pre-computes the character codes for display: s(i)=CODE s$(i)+79 shifts each letter’s ASCII code into the UDG character range so the correct symbol is printed with CHR$ s(sn) in line 510.

Deck Representation and Shuffling

The 52-card deck is stored in array c(), initialized to values 1–52 (line 70). Shuffling (line 80) uses a simple random-swap approach: for each position i, a random index r is chosen from the full range 1–52 and the cards at positions i and r are swapped. This is not a strict Fisher-Yates shuffle (which would restrict r to i..52), so the distribution is slightly biased, though practically acceptable for a card game. Lines 90 decode each shuffled card into suit t(i) (1–4) and value v(i) (1–13) using integer division and modular arithmetic.

Card Display Subroutine (Lines 500–540)

Each card is printed at screen row l1, column c1. The value character is taken from V$="A23456789TJQK" using v$(vn), and the suit UDG is printed on the line below. INK color is determined by the expression INK 2-(sn=2*INT(sn/2))*2: for even-numbered suits (Clubs=2, Spades=4) this evaluates to INK 0 (black), and for odd suits (Hearts=1, Diamonds=3) it gives INK 2 (red). A 17×17-pixel box is drawn around each card using PLOT/DRAW. A short BEEP tone accompanies each card dealt.

Money Animation (Lines 650–690)

The subroutine at line 650 animates the player’s balance m counting toward its new value m1. The FOR loop step is computed as 1-2*(m1<m), which evaluates to -1 when the new amount is less (a loss) and +1 when it is greater (a win). Each iteration prints the running total and sounds a BEEP, giving a slot-machine-like effect. Note that line 650 reads LET m1=+incm — the unary + is redundant but harmless; the intent is to set m1 as the target amount rather than an increment. The actual new balance should logically be m+incm, so there is a bug here: m1 is set to incm rather than m+incm, meaning the displayed and stored balance after each round equals only the bet amount or payout rather than the cumulative total.

Game Logic

The player’s turn (lines 240–300) loops via GO TO, prompting for ENTER (stick) or any other input (twist) using INPUT ... LINE z$. The house’s turn (lines 320–350) automatically twists while ht<=pt AND ht<19, implementing a simple house strategy. Bust detection and win/draw conditions are handled with explicit IF/GO TO branches. The game runs for exactly 5 hands per session (FOR g=1 TO 5), after which the player may restart with RUN (line 400).

Notable Techniques

  • The playersgo flag variable selects the screen row for card display in subroutine 800, allowing the same dealing subroutine to serve both player and house.
  • INPUT ... LINE z$ is used throughout to capture raw keypresses including ENTER, avoiding the need for a separate INKEY$ polling loop.
  • The card deal index cd is a simple incrementing pointer into the shuffled deck arrays, with cd1 used to track the start of the current hand for column spacing of twist cards.
  • Screen clearing in subroutine 900 uses PRINT with spaces rather than CLS, preserving the static labels and border graphics.

Anomalies and Bugs

LocationIssue
Line 650LET m1=+incm sets the target balance to the raw income/loss value rather than m+incm, so the balance counter never accumulates correctly across hands.
Line 870LET inct=v(cd) reads the next undealt card’s value before incrementing cd, while GO SUB 500 on line 860 uses the same cd before incrementing. The indexing is consistent within the subroutine but relies on the order of operations across lines 860–870.
Line 260/280When the player reaches exactly 21, execution jumps to line 310 skipping the stick prompt, which is correct behavior, but the player total display at AT 7,4 is only printed during twist (line 280), so on an initial 21 the sum may not be visible in the card area.

Content

Appears On

The biggest LIST tape yet — play poker accompanied by chip-tune renditions of classic songs, diagnose illnesses with a Bayesian expert system, master Z80 opcodes with a quiz, or unscramble anagrams before the cauldron boils over. Four custom fonts included.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

   10 PAPER 7: INK 0: FLASH 0: BORDER 7: CLS 
   20 FOR i=1 TO 4: READ x$: FOR j=0 TO 7: READ x: POKE USR x$+j,x: NEXT j: NEXT i
   30 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
   40 LET S$="HCDS": LET V$="A23456789TJQK"
   50 DIM c(52): DIM t(52): DIM v(52): DIM s(4)
   60 FOR i=1 TO 4: LET s(i)=CODE s$(i)+79: NEXT i
   70 FOR i=1 TO 52: LET c(i)=i: NEXT i
   80 FOR i=1 TO 52: LET r=INT (52*RND)+1: LET z=c(i): LET c(i)=c(r): LET c(r)=z: NEXT i
   90 FOR i=1 TO 52: LET t(i)=INT ((c(i)-1)/13)+1: LET v(i)=c(i)-13*(t(i)-1): NEXT i
  100 GO SUB 900
  110 PLOT 55,152: DRAW 193,0: DRAW 0,-81: DRAW -193,0: DRAW 0,81
  120 PRINT INK 1;AT 4,0;"PLAYER";AT 10,0;"HOUSE"
  130 LET m=50: PRINT AT 5,2;"$";m: LET b=10: LET cd=1
  140 PRINT AT 0,7;"B L A C K J A C K"
  200 FOR g=1 TO 5: GO SUB 900: PAUSE 100
  210 PRINT AT 15,2;"Hand no.";g;".  The bet is $";b
  220 PAUSE 150
  230 LET incm=-b: GO SUB 650
  240 LET playersgo=1: GO SUB 800: LET pt=total
  250 IF pt>21 THEN PRINT AT 6,2; INVERSE 1; INK 2;"BUST": PRINT AT 18,6;"You bust!  The house wins.": GO TO 380
  260 IF pt=21 THEN PRINT AT 16,6;"You have exactly 21!": GO TO 310
  270 INPUT "Press ENTER to stick, any other key to twist"; LINE z$: IF z$="" THEN GO TO 300
  280 GO SUB 850: LET pt=pt+inct: PRINT AT 7,4;pt: GO TO 250
  300 PRINT AT 16,8;"You stick with ";pt
  310 PAUSE 200
  320 LET playersgo=0: GO SUB 800: LET ht=total
  330 IF ht>21 THEN PRINT AT 12,2; INVERSE 1; INK 2;"BUST";AT 18,6;"The house bust!  You win.": GO TO 370
  340 IF ht<=pt AND ht<19 THEN GO SUB 850: LET ht=ht+inct: PRINT AT 13,4;ht: GO TO 330
  350 IF ht>pt THEN PRINT AT 18,8;"The house wins": GO TO 380
  360 IF ht=pt THEN PRINT AT 18,9;"It is a draw": LET incm=b: GO SUB 650: GO TO 380
  370 PRINT AT 19,11;"You gain $";2*b: LET incm=2*b: GO SUB 650
  380 INPUT "Press ENTER to continue"; LINE z$
  390 NEXT g: PRINT AT 20,3;"That's it.  You have $";m
  400 PAUSE 150: INPUT "Press ENTER to play again, or 0 to stop"; LINE z$: IF z$="" THEN RUN 
  410 STOP 
  500 PAPER 7: LET vn=v(n): LET sn=t(n): INK 2-(sn=2*INT (sn/2))*2
  510 PRINT AT l1,c1;v$(vn);" ";AT l1+1,c1;" ";CHR$ s(sn)
  520 INK 0
  530 PLOT c1*8-1,176-8*l1: DRAW 17,0: DRAW 0,-17: DRAW -17,0: DRAW 0,17
  540 BEEP 1,5: RETURN 
  650 LET m1=+incm
  660 FOR i=m TO m1 STEP 1-2*(m1<m)
  670 PRINT AT 5,3;i;" ": BEEP .01,15
  680 NEXT i
  690 LET m=m1: RETURN 
  800 LET l1=10
  810 IF playersgo THEN LET l1=4
  820 LET c1=8: LET n=cd: LET cd1=cd: LET cd=cd+1: GO SUB 500: LET c1=11: LET n=cd: LET cd=cd+1: GO SUB 500
  830 LET total=v(cd-1)+v(cd-2): PRINT AT l1+3,0; INK 1;"Sum:";total
  840 RETURN 
  850 PRINT AT 17,13; INK 3; FLASH 1;"TWIST": PAUSE 150: PRINT AT 17,13;"     "
  860 LET c1=3*(cd-cd1+1)+5: LET n=cd: GO SUB 500
  870 LET inct=v(cd): LET cd=cd+1
  880 RETURN 
  900 FOR i=15 TO 19: PRINT AT i,0;"                                ": NEXT i
  910 PRINT AT 6,2;"    ";AT 7,0;"      ";AT 12,2;"    ";AT 13,0;"      "
  920 FOR i=3 TO 12: PRINT PAPER 4;AT i,7;"                        ": NEXT i      
  930 RETURN 
 9997 STOP 
 9998 SAVE "BLACK JACK" LINE 0

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

People

No people associated with this content.

Scroll to Top