This program implements a two-player number-comparison card game called “Stumper,” in which the human player and the computer each hold ten randomly generated numbers (up to 7 digits, produced by multiplying four RND values to skew the distribution toward smaller numbers). On each turn the human selects one of their numbers by pressing a key (0–9), and the computer automatically picks its best counter-move: the smallest computer number that still beats the player’s choice, or if none exists, it uses any remaining positive value. Wins are tracked with counters AA and BB, and at the end of ten rounds the program randomly selects one of three taunting messages for each outcome. The subroutine at line 9000 draws a pixel grid using PLOT to create a scoreboard background, and right-aligned number display is achieved by padding with spaces from the pre-dimensioned empty string X$(32).
Program Analysis
Program Structure
The program is divided into four logical sections:
- Initialisation (lines 10–36): Sets up string and numeric arrays, zeroes score counters, and calls the board-drawing subroutine.
- Round setup (lines 40–120): Runs in
FASTmode to generate and display ten random numbers for each side. - Game loop (lines 200–590): Ten turns of human input, computer response, comparison, and score update.
- End-of-game (lines 600–870): Evaluates totals, branches to randomised taunt messages, then restarts.
- Board subroutine (lines 9000–9160): Draws the pixel grid background and column headers using
PLOT. - Save line (9998–9999):
SAVE "STUMPER"followed byRUN, a common ZX81/TS1000 pattern to relaunch after saving.
Random Number Generation and Distribution
Each number is generated as INT(10000000*RND*RND*RND*RND). Multiplying four independent uniform random variables produces a heavily right-skewed (Beta-like) distribution concentrated near zero. This means most values are small, making it less likely the computer will always find a winning counter, and keeping games competitive despite the computer’s greedy strategy.
Computer Strategy
The computer’s move selection (lines 300–360) is a greedy “smallest winning value” approach:
- Scan
B(I)for the first value greater than the player’s chosenA(O); if found, use it (line 320). - If no winning value exists, fall through to lines 340–360 and pick any remaining positive value.
This is a simple but not optimal strategy; it finds the first (not the smallest) computer value that beats the human, because the array is unsorted.
Right-Aligned Number Display
Numbers are right-aligned in an 8-character field using a clean idiom. X$(32) is dimensioned but never filled, so it contains 32 spaces. The expression X$( TO 8-LEN C$)+C$ pads C$ on the left with spaces to exactly 8 characters, which is then stored in A$(N) or B$(N) (lines 85–97). This avoids any explicit loop or TAB arithmetic.
Human Input Handling
Input (lines 220–240) reads a single keypress via INKEY$ and validates it by checking that its character code falls between 28 and 37 (the ZX81/TS1000 codes for digits ‘0’–’9′). VAL O$+1 converts the digit character to a 1-based array index. Line 250 also guards against re-selecting an already-played number by checking whether the slot has been blanked to eight spaces.
Randomised Taunt Messages
Instead of a single end-of-game message, the program selects one of three taunts for wins and losses using a computed GOTO:
LET D=20*(INT(3*RND)+1)produces 20, 40, or 60.GOTO 700+D(or800+D) jumps to lines 720, 740, or 760 (human win) and 820, 840, or 860 (computer win).- Lines 710 and 810 are never directly executed; they exist solely as jump-over code between the branch instruction and the first target.
Board Drawing Subroutine
The subroutine at lines 9000–9160 uses PLOT loops to draw horizontal lines every 4 pixels (STEP 4) and vertical lines every 18 pixels (STEP 18) to create a grid background. This runs in FAST mode to speed up the plotting. Column headers “YOU” and “STUMPER” and row numbers 0–9 are then printed over the graphics.
Victory Indicator
Lines 450–460 print an inverse-video asterisk (%* — a block graphic rendered as a highlighted star) at the row of the winning player’s number. The % prefix denotes inverse video in the source encoding, giving a clear visual indicator of who won each round without clearing the board.
Notable Variables
| Variable | Purpose |
|---|---|
A(N) / B(N) | Numeric values for human/computer hands |
A$(N) / B$(N) | Right-aligned 8-char string representations |
X$(32) | Space-padding source string |
D$ | Animated/decorative string of block graphics (▖▄▖▄…) used as a “played” marker |
AA / BB | Human/computer round-win counters |
O / I | Human-chosen index / computer-chosen index |
Bugs and Anomalies
- The computer’s greedy scan (lines 300–320) finds the first array entry that beats the human, not the smallest such value. Because the array is in random order, this is neither the strongest nor the weakest valid play.
- Line 25 (
POKE 16418,0) writes to the ZX81 system variableMARGIN, setting the vertical blank interrupt margin to zero. This suppresses the normal display interrupt, a common technique to eliminate flicker or speed up display in certain modes. PAUSE 40000is used at lines 640 and 998 to wait for the Enter key; on a ZX81/TS1000 this pauses for approximately 40,000 frames (roughly 11 minutes at 50 Hz) unless interrupted by a keypress, functioning as a practical “press any key” wait.- Lines 998–999 (bare
PAUSE 40000/GOTO 999) are unreachable dead code; program flow never reaches them in normal play.
Content
Source Code
10 LET D$=",,..,,..,,..,,.."
15 RAND
20 GOSUB 9000
25 POKE 16418,0
30 DIM X$(32)
32 DIM A$(10,8)
34 DIM B$(10,8)
35 LET AA=0
36 LET BB=0
40 FAST
50 DIM A(10)
60 DIM B(10)
70 FOR N=1 TO 10
80 LET A(N)=INT (10000000*RND*RND*RND*RND)
85 LET C$=STR$ A(N)
87 LET A$(N)=X$( TO 8-LEN C$)+C$
90 LET B(N)=INT (10000000*RND*RND*RND*RND)
95 LET C$=STR$ B(N)
97 LET B$(N)=X$( TO 8-LEN C$)+C$
100 PRINT AT N*2,5;A$(N);AT N*2,16;" "
110 PRINT AT N*2,23;B$(N);AT N*2,20;" "
120 NEXT N
200 SLOW
210 FOR N=1 TO 10
215 PRINT AT 23,0;"YOUR MOVE, HUMAN ::"
220 LET O$=INKEY$
230 IF CODE O$<28 OR CODE O$>37 THEN GOTO 220
235 PRINT AT 23,0;X$
240 LET O=VAL O$+1
250 IF A$(O)=" " THEN GOTO 220
260 PRINT AT O*2,5;D$
300 FOR I=1 TO 10
310 IF B(I)=0 THEN GOTO 330
320 IF B(I)>A(O) THEN GOTO 400
330 NEXT I
340 FOR I=1 TO 10
350 IF B(I)>0 THEN GOTO 400
360 NEXT I
400 PRINT AT I*2,23;D$
410 PRINT AT 22,3;A$(O)
420 PRINT AT 22,23;B$(I)
430 IF A(O)>B(I) THEN LET AA=AA+1
440 IF B(I)>A(O) THEN LET BB=BB+1
450 IF A(O)>B(I) THEN PRINT AT N*2,16;"%*";
460 IF B(I)>A(O) THEN PRINT AT N*2,20;"%*";
500 LET A$(O)=" "
510 LET B$(I)=" "
520 LET A(O)=0
530 LET B(I)=0
590 NEXT N
600 PRINT AT 23,0;X$
610 IF AA>BB THEN GOTO 700
620 IF BB>AA THEN GOTO 800
630 PRINT AT 23,0;"DRAW GAME, HUMAN - PRESS ENTER"
640 PAUSE 40000
650 PRINT AT 23,0;X$
660 PRINT AT 22,0;X$
670 LET AA=0
680 LET BB=0
690 GOTO 70
700 LET D=20*(INT (3*RND)+1)
710 GOTO 700+D
720 PRINT AT 23,0;"YOU LUCKED OUT, PRESS ENTER"
730 GOTO 640
740 PRINT AT 23,0;"YOU WONT WIN AGAIN, PRESS ENTER"
750 GOTO 640
760 PRINT AT 23,0;"YOU CHEATED, PRESS ENTER"
770 GOTO 640
800 LET D=20*(INT (3*RND)+1)
810 GOTO 800+D
820 PRINT AT 23,0;"I WIN (AS USUAL), PRESS ENTER"
830 GOTO 640
840 PRINT AT 23,0;"GIVE UP, I 'LL WIN ANYWAY"
850 GOTO 640
860 PRINT AT 23,0;"HO HUM, THIS IS GETTING BORING"
870 GOTO 640
998 PAUSE 40000
999 GOTO 999
9000 FAST
9005 CLS
9010 FOR Y=0 TO 43 STEP 4
9020 FOR X=9 TO 63
9030 PLOT X,Y
9040 NEXT X
9050 NEXT Y
9060 FOR X=9 TO 63 STEP 18
9070 FOR Y=0 TO 40
9080 PLOT X,Y
9090 NEXT Y
9100 NEXT X
9110 FOR N=1 TO 10
9120 PRINT AT N*2,0;N-1
9130 NEXT N
9140 PRINT AT 0,8; "YOU STUMPER"
9160 RETURN
9998 SAVE "STUMPE%R"
9999 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
