--- title: "Stumper" id: 57633 type: "computer_media" slug: "stumper" url: "http://localhost/computer_media/stumper/" markdown_url: "http://localhost/computer_media/stumper.md" published_at: "2024-10-06T00:59:49+00:00" modified_at: "2026-04-03T07:58:11+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/stumper.png" excerpt: "A taunting number-battle game where you pick from ten skewed random values and the computer plays a greedy counter-strategy—can you outsmart \"Stumper\"?" category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 56726 title: "Synchro-Sette November 1983" type: "computer_media" url: "http://localhost/computer_media/synchro-sette-november-1983/" media_type: "Program" mediadate: "November 1983" images: - url: "http://localhost/wp-content/uploads/2024/10/stumper.png" media_type_tags: "Game" --- # Stumper 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: 1. **Initialisation (lines 10–36):** Sets up string and numeric arrays, zeroes score counters, and calls the board-drawing subroutine. 2. **Round setup (lines 40–120):** Runs in `FAST` mode to generate and display ten random numbers for each side. 3. **Game loop (lines 200–590):** Ten turns of human input, computer response, comparison, and score update. 4. **End-of-game (lines 600–870):** Evaluates totals, branches to randomised taunt messages, then restarts. 5. **Board subroutine (lines 9000–9160):** Draws the pixel grid background and column headers using `PLOT`. 6. **Save line (9998–9999):**`SAVE "STUMPER"` followed by `RUN`, 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: 1. Scan `B(I)` for the first value greater than the player’s chosen `A(O)`; if found, use it (line 320). 2. 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` (or `800+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 variable `MARGIN`, 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 40000` is 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. ## 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 ```