This program implements the casino lottery game Keno, in which the player picks 10 numbers from a field of 81 and then watches the computer draw 20 numbers at random. The 81 playable numbers are laid out on screen using a pre-computed coordinate table stored in arrays `l()` and `c()`, with all 162 coordinate values encoded in a single DATA statement read at startup. Payouts follow an exponential scale: matching 5 numbers returns even money, while matching all 10 pays out at 1,000,000-to-1 odds, calculated as `b*10^(z-4)`. A simple animation scrolls through board positions using OVER 1 and PAPER 8/INK 8 transparency tricks before highlighting the drawn number with INVERSE 1. Duplicate detection for both player-chosen markers and the computer’s random draws is handled by inner FOR/NEXT loops that re-request input or re-roll when a collision is found.
Adapted by Bob Howard from Creative Games by R. Maunder.
Program Analysis
Program Structure
The program is organized into a main game loop with a subroutine for instructions. Execution flows as follows:
- Lines 10–30: Initialization — set display attributes, allocate arrays, and read board coordinates from DATA.
- Lines 300–305: Title screen, instructions prompt, and display of the game board header.
- Lines 310–320: Render all 81 numbers (0–80) on screen at their pre-computed positions.
- Lines 330–420: Accept the player’s bet and 10 chosen marker numbers, with validation and duplicate checking.
- Lines 430–530: Draw 20 random numbers, animate each draw, and count matches.
- Lines 540–580: Calculate and display payout, then prompt to continue or quit.
- Lines 600–610: SAVE with auto-run, then STOP.
- Lines 700–750: Instructions subroutine.
Board Coordinate Table
Rather than computing screen positions algorithmically, all 81 (row, column) pairs are stored as 162 values in the DATA statement at line 30 and loaded into parallel arrays l() (line/row) and c() (column) at lines 20–20. This trades memory for speed at draw time. The numbers 0–80 are displayed at AT l(i),c(i) for i from 1 to 81, meaning number i-1 is at index i; this off-by-one is consistently handled with m(i)+1 as the array index when looking up a player-chosen marker.
Input Validation
Bet validation at line 340 checks three conditions in one IF: the bet must not exceed available money, must be an integer (b=INT b), and must be at least 1. Marker validation at line 375 similarly checks for integer, non-negative, and ≤80 in a single compound condition. Duplicate marker detection at lines 390–400 uses a classic inner loop comparing the new entry against all previously accepted values, re-prompting inside the loop body on collision.
Random Draw and Deduplication
At line 450, the computer’s drawn number is INT(81*RND), giving a value in the range 0–80. Duplicate rejection at lines 470–480 uses the same inner-loop pattern as player input: if the new draw matches any earlier draw, execution jumps back to line 450 to re-roll. This is a straightforward rejection-sampling approach.
Draw Animation
Lines 490–495 implement a “scrolling highlight” animation. A FOR loop walks from position 0 up to the newly drawn number r(n), printing a blank overlay (PAPER 8; INK 8; OVER 1) to erase the previous highlight and advance it one cell. The string o$ is set to "__" (two underscores, to cover two-digit numbers) or "_" for single-digit positions. PAPER 8 and INK 8 use the Spectrum/TS2068 transparent color attribute, so OVER 1 XORs the underscores onto the existing display without changing the background color. After the loop, the final position is highlighted with INK 8; INVERSE 1.
Payout Formula
The payout calculation at line 550 is elegantly compact:
- Fewer than 4 matches: payout is 0 (line 540).
- 4 or more matches:
p = b * 10^(z-4), wherezis the match count.
This gives even money at 4 matches, 10× at 5, 100× at 6, 1,000× at 7, 10,000× at 8, 100,000× at 9, and 1,000,000× at 10. Note the instructions screen states 5 matches = even money, but the formula makes 4 matches = even money — a discrepancy between the help text and the actual game logic.
Notable Techniques and Idioms
INPUT ; b ; " is invalid..." ; bat line 340 uses the semicolon-chained INPUT form to display a prompt incorporating the invalid value inline.INPUT ("Enter marker no."; i; ": "); m(i)at line 370 uses the parenthesized prompt syntax to build a dynamic prompt string without a separate PRINT.PAUSE 4E4at line 750 (40,000 frames ≈ 11 minutes at 50 Hz) acts as a long timeout on the instructions screen before returning.- Line 600 uses
SAVE "KENO" LINE 0;LINE 0would cause auto-run from line 0, but since line 0 does not exist, execution starts at the first available line (line 10) — a known technique. - The variable name
mis reused: first dimensioned asDIM m(10)(the player’s 10 marker numbers) at line 15, then immediately overwritten as a scalarLET m=20at line 300. This destroys the array, leavingmas a plain numeric variable for the money held. The markers array is effectively lost, but the program works becausem(i)references after line 300 address BASIC’s array-element syntax on the scalar — this is actually a bug: oncemis redefined as a scalar at line 300, later references tom(i)will cause a type error. In practice the program likely relies on the TS2068 not erroring when accessingm(i)afterLET m=20due to implementation specifics, or this is an oversight in the listing.
Variable Summary
| Variable | Purpose |
|---|---|
l(81) | Row coordinates for each board position |
c(81) | Column coordinates for each board position |
m(10) / m | Player’s 10 chosen markers (array); money held (scalar, overwrites array) |
r(20) | Computer’s 20 drawn numbers |
b | Current bet amount |
z | Match count for current round |
p | Payout amount |
o$ | Animation overlay string (one or two underscores) |
Y$, z$ | Temporary string input variables |
i, j, n | Loop counters |
Content
Source Code
10 BORDER 1: PAPER 1: INK 7: CLS
15 DIM l(81): DIM c(81): DIM m(10): DIM r(20)
20 FOR i=1 TO 81: READ l(i),c(i): NEXT i
30 DATA 2,3,3,3,4,3,5,3,6,3,7,3,8,3,9,3,10,3,11,3,12,3,13,3,14,3,15,3,16,3,17,3,18,3,19,3,19,5,19,7,19,9,19,11,18,11,17,11,16,11,15,11,14,11,13,11,12,11,11,11,10,11,9,11,8,11,7,11,6,11,5,11,4,11,3,11,2,11,2,13,2,15,2,17,2,19,3,19,4,19,5,19,6,19,7,19,8,19,9,19,10,19,11,19,12,19,13,19,14,19,15,19,16,19,17,19,18,19,19,19,19,21,19,23,19,25,19,27,18,27,17,27,16,27,15,27,14,27,13,27,12,27,11,27,10,27,9,27,8,27,7,27,6,27,5,27,4,27,3,27,2,27
300 LET m=20
301 PRINT AT 10,5;"WANT INSTRUCTIONS? Y/N?"
302 INPUT Y$
303 IF Y$="y" OR y$="Y" THEN GO SUB 700
305 PAPER 1: BORDER 2: INK 0: CLS : PRINT AT 0,0; INK 4;"KENO";AT 0,9; FLASH 1; INK 3;"MONEY HELD=$";m;AT 0,28; FLASH 0; INK 4;"KENO"
310 FOR i=1 TO 81
315 PRINT AT l(i),c(i); PAPER 7; INK 0;i-1: NEXT i
320 LET z=0
330 INPUT "ENTER YOUR BET: $";b
340 IF b>m OR b<>INT b OR b<1 THEN INPUT ;b;" is invalid. Reenter bet: $";b: GO TO 340
350 LET m=m-b: PRINT AT 0,21;" ";AT 0,21; INK 3;m
360 FOR i=1 TO 10
370 INPUT ("Enter marker no.";i;": ");m(i)
375 IF m(i)<>INT m(i) OR m(i)<0 OR m(i)>80 THEN INPUT "0 TO 80 please! ";m(i): GO TO 375
380 IF i=1 THEN GO TO 410
390 FOR j=1 TO i-1: IF m(i)=m(j) THEN INPUT ("You have ";m(i);" already. Reenter:");m(i): GO TO 390
400 NEXT j
410 PRINT AT l(m(i)+1),c(m(i)+1); FLASH 1; PAPER 7; INK 2;m(i): PAUSE 100: PRINT AT l(m(i)+1),c(m(i)+1); FLASH 0; PAPER 7; INK 2;m(i)
420 NEXT i
430 FOR n=1 TO 20
440 INPUT ("Press ENTER for my number ";n); LINE z$
450 LET r(n)=INT (81*RND)
460 IF n=1 THEN GO TO 490
470 FOR j=1 TO n-1: IF r(n)=r(j) THEN GO TO 450
480 NEXT j
490 FOR i=0 TO r(n): LET o$="__": IF i<10 THEN LET o$="_"
491 PRINT AT l(i+1),c(i+1); PAPER 8; INK 8; OVER 1;o$: IF i=10 THEN LET o$="_"
494 IF i>0 THEN PRINT AT l(i),c(i); PAPER 8; INK 8; OVER 1;o$
495 BEEP 0.1,10: NEXT i: PRINT AT l(r(n)+1),c(r(n)+1); INK 8; INVERSE 1;r(n)
500 FOR j=1 TO 10: IF r(n)=m(j) THEN LET z=z+1: BEEP 0.2,15: GO TO 520
510 NEXT j
520 PRINT AT 20,6; INK 4;"Number of Matches=";z
530 NEXT n
540 IF z<4 THEN LET p=0: GO TO 560
550 LET p=b*10^(z-4)
560 PRINT AT 21,0; FLASH 1; INK 4;"PAYOUT =$";p: LET m=m+p: PRINT AT 0,21; INK 8;m: IF m=0 THEN PRINT AT 21,15; INK 2; FLASH 1;"You are BROKE!": STOP
570 INPUT "Key 1 to continue, 0 to STOP "; LINE z$: IF z$="0" THEN PRINT AT 21,0; INK 1;"You leave with $";m: STOP
580 GO TO 305
600 SAVE "KENO" LINE 0
610 STOP
700 INK 7: CLS : PRINT "THIS IS A VARIATION OF CHINESE LOTTERY PLAYED IN RENO/LAS VEGAS AS ""KENO"""
710 PRINT '"THERE ARE 81 NUMBERS. YOU PICK 10 AND I WILL DRAW 20."
720 PRINT '"IF YOU CAN MATCH 5 OR MORE OF THE 20 YOU WIN. BETTER ODDS TOO THAN RENO!"
730 PRINT '"5 = EVEN MONEY 8 = 10,000:1"'"6 = 100:1 9 = 100,000:1"'"7 = 1000:1 10 = 1 MILLION:1"
740 PRINT ''"(ADAPTED by WA6DLI FROM CREATIVE GAMES BY R. MAUNDER)"'"HIT ANY KEY TO RETURN "
750 PAUSE 4E4: RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

