This is a Mastermind-style code-breaking game using digits 1–6 instead of colours. The program generates a four-digit secret code stored in A$, then gives the player up to nine attempts (lines 80–300 loop from column 21 down to 5 in steps of −2). Exact-position matches are shown with a filled block character and misplaced-digit matches with a dotted block character, displayed to the right of the guess. Line 50 uses the idiomatic VAL “RND*5+1” trick to embed a numeric expression as a string, saving memory and deferring evaluation. The scoring logic modifies working copies B$ and C$ in-place to avoid double-counting matched digits across both the exact and misplaced passes.
Program Analysis
Program Structure
The program is organised into four logical phases:
- Initialisation (lines 10–60): Prints the title banner in inverse video, dimensions two four-character string arrays, and fills
A$with a random secret code. - Game loop (lines 80–300): Iterates over
FOR A=21 TO 5 STEP -2, giving nine rows on screen, each handling one guess. - End-of-game (lines 310–4020): Prints either “GAME OVER” or nothing (using the
ANDboolean idiom), reveals the secret, shows the number of tries, pauses, clears, and restarts. - Alternate path (lines 5000–5010): Dead code reachable only by direct
GOTO— never actually reached in normal play because line 310 handles all endings.STOPprevents further execution.
Secret Code Generation
Line 50 builds each character of the secret code using:LET A$(N)="123456"(VAL "RND*5+1")
The VAL "RND*5+1" idiom evaluates the expression at run-time while storing it as a string literal in the token stream, saving a few bytes of RAM. Slicing a string literal with a computed index is a clean ZX81/TS1000 pattern to pick a random element from a fixed set — here digits 1 through 6, corresponding to Mastermind’s six colours.
Scoring Algorithm
The scoring is a two-pass algorithm that correctly handles duplicate digits:
- Pass 1 (lines 130–190): Scans for exact matches (right digit, right position). Matching positions in both
B$(the guess copy) andC$(the code copy) are overwritten with a filled block graphic\;;to prevent them being counted again in pass 2. - Pass 2 (lines 210–290): Scans remaining positions for misplaced matches (right digit, wrong position). Each match overwrites the relevant position in
B$with a dotted block\..to prevent double-counting, and prints the misplaced indicator.
The variable B (reset to 0 each round at line 90) acts as a print-column accumulator for the scoring markers, advancing by 2 per marker. When B>=8 all four positions are matched and the game ends in victory via GOTO 310.
Screen Layout
| Column range | Content |
|---|---|
| Col 9–12 | Player’s four-character guess (B$) |
| Col 0, 2, 4, 6 | Scoring markers (exact = \;; ▐, misplaced = \.. ▄) |
| Col 6, row 1 | Title “NUMBER MASTER” in inverse video |
Key BASIC Idioms
PRINT "..." AND condition— prints the string only when the condition is true (non-zero), a standard ZX BASIC space-saving trick used in line 310.VAL "11-A/2"in line 320 computes the number of tries from the loop counterAwithout a separate variable. SinceAsteps from 21 down by 2, the formula recovers the 1-based attempt count.PAUSE 40000at line 4000 provides a long but finite pause (approximately 11 minutes at 50 Hz) before auto-restarting — effectively “press any key to continue” without anINKEY$loop.
Bugs and Anomalies
- Variable
Bused for two purposes:Bserves as both the scoring-marker column counter and (implicitly) a “score” register. This works because it is reset to 0 at line 90, but the dual role makes the code harder to follow. - Line 105 validation: The guard against spaces in the input only checks for a literal space character; it does not validate that each character is in the range 1–6, so invalid input (e.g. letters) is silently accepted.
- Lines 5000–5010 are unreachable: Line 310 always prints the game-over state and falls through to line 320; no code path issues a
GOTO 5000. This block appears to be a leftover from an earlier version. - DIM B$(4) at line 30 allocates only four characters, matching the four-digit guess. However,
INPUT B$at line 100 does not constrain input length, so entering more than four characters will cause a subscript error when lines referenceB$(5)etc. implicitly through the four-character DIM. In practice the DIM limits the usable string to exactly four characters. - NEXT F placement:
NEXT Fat line 280 is inside the body of the inner loop but positioned after aGOTO 290, meaning it is only reached when no match is found. This is an intentional early-exit loop pattern, not a bug.
Content
Source Code
10 PRINT AT 1,6;"% %N%U%M%B%E%R% %M%A%S%T%E%R% "
20 DIM A$(4)
30 DIM B$(4)
40 FOR N=1 TO 4
50 LET A$(N)="123456"(VAL "RND*5+1")
60 NEXT N
80 FOR A=21 TO 5 STEP -2
90 LET B=0
100 INPUT B$
105 IF B$(1)=" " OR B$(2)=" " OR B$(3)=" " OR B$(4)=" " THEN GOTO 100
110 PRINT AT A,9;B$
120 LET C$=A$
130 FOR E=1 TO 4
140 IF B$(E)<>C$(E) THEN GOTO 190
150 PRINT AT A,B;";;"
160 LET B=B+2
170 LET B$(E)=".."
175 IF B>=8 THEN GOTO 310
180 LET C$(E)=";;"
190 NEXT E
200 IF B>=8 THEN GOTO 310
210 FOR E=1 TO 4
220 FOR F=1 TO 4
230 IF C$(E)<>B$(F) THEN GOTO 280
240 PRINT AT A,B;".."
250 LET B=B+2
260 LET B$(F)=".."
270 GOTO 290
280 NEXT F
290 NEXT E
300 NEXT A
310 PRINT AT 3,0;"GAME OVER" AND A=1;TAB 8;" ";A$,
320 IF A<>1 THEN PRINT INT VAL "11-A/2";" TRIES"
4000 PAUSE 40000
4010 CLS
4020 RUN
5000 PRINT AT 2,0;"NICE TRY" AND A=1;TAB 8;" ";A$,
5010 STOP
9998 SAVE "NUMBER MASTE%R"
9999 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
