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
playersgoflag 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
cdis a simple incrementing pointer into the shuffled deck arrays, withcd1used 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
| Location | Issue |
|---|---|
| Line 650 | LET 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 870 | LET 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/280 | When 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
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.
