Codebreaker is a Mastermind-style number-guessing game where the player has 10 attempts to deduce a hidden 4-digit code, each digit ranging from 1 to 6. Each guess is entered one keypress at a time, with digits rendered in their corresponding INK color using block graphic characters. After each guess, the program scores it by printing UDG characters and CHR$ 143/144 indicators for exact matches (black pegs) and color-only matches (white pegs), zeroing out matched positions to avoid double-counting. The UDG at character 144 is defined via DATA at line 360 and POKEd into the UDG memory area at startup, providing a custom symbol for feedback display.
Program Structure
The program is organized into a main flow with two short subroutines for scoring feedback:
- Lines 10–20: UDG setup and screen initialization.
- Lines 30–50: Array allocation and secret code generation.
- Lines 60–130: Main input loop — one guess of 4 digits per turn.
- Lines 140–220: Scoring loop — exact matches first, then color-only matches.
- Lines 230–250: Audio feedback and turn counter increment.
- Lines 260–310: Failure/replay handler.
- Lines 320–330: Subroutines for exact-match and color-match scoring.
- Line 340: Win message handler.
- Line 360: UDG DATA for the custom peg graphic.
Secret Code Generation
Line 50 generates the 4-element secret code array a() using INT(RND*6)+1, producing values 1–6 inclusive, mirroring the six colors of a classic Mastermind set. RANDOMIZE at line 40 ensures a different seed each game.
Input Handling
The game reads digits one at a time via INKEY$ in a tight polling loop (line 80–90), accepting only characters "1" through "6". Line 110 implements a key-release wait — it loops while INKEY$ still returns the same character — preventing a single keypress from being counted multiple times. Each accepted digit is printed immediately using INK VAL i$, so digits 1–6 appear in their corresponding spectrum ink colors, using the block graphic \:: (█) as a filled tile for visual effect.
Scoring Algorithm
Scoring uses the classic two-pass Mastermind algorithm to avoid double-counting:
- Pass 1 (lines 150–170): Compares
b(j)(guess) againstc(j)(copy of secret), callingGO SUB 320for exact position matches. Matched elements are zeroed in both arrays. - Pass 2 (lines 190–210): Nested loop over all remaining non-zero pairs, calling
GO SUB 330for color-only matches, again zeroing matched positions to prevent reuse.
Note that array c() is a working copy of a() loaded at line 120 (LET c(j)=a(j) inside the input loop), preserving the original secret for subsequent turns.
Feedback Display and Audio
Exact matches print CHR$ 143 (a block graphic) with a high-pitched short beep (BEEP .01,50); color-only matches print CHR$ 144 (the custom UDG) with a lower beep (BEEP .01,30). The variable p accumulates the total number of pegs awarded. After scoring, line 230 checks NOT p (i.e., p=0) to play a failure tone, while line 240 plays a rising sequence of beeps proportional to the peg count, iterating from p to PI — since PI≈3.14159, only integer steps 0–3 are traversed, meaning at most 4 beeps regardless of peg count.
UDG Definition
Line 10 POKEs 8 bytes of DATA into USR "\a" (UDG “A”), defining a custom graphic. The DATA at line 360 is 255,129,P,P,P,P,P,255. The value P here is the BASIC keyword token for PRINT (decimal 245 / &F5), which in this context is being used as a raw byte value — an unusual but functional trick to embed a specific bit pattern into the UDG data without requiring a decimal literal.
Win and Loss Conditions
If p=4 after the exact-match pass (line 180), the game jumps to line 340 which prints a flashing FLASH 1 congratulations message using AT s*2,9 to position it on the current row. After 10 failed attempts, lines 260–270 reveal the secret code by printing each element with its own INK a(j) color. The replay prompt (lines 280–310) checks for lowercase "p" or "x" only; uppercase input loops back to line 280.
Notable Idioms and Anomalies
TAB PI(lines 60, 270) usesPI≈3.14159 as a tab stop, which truncates to column 3 — a compact way to writeTAB 3.- The
FOR j=p TO PIloop at line 240 exploits floating-point truncation: the loop body executes for each integer step frompup to 3, neatly bounding the beep count without an explicit limit constant. - Line 370 uses
LINE 0in theSAVEcommand, targeting line 0 which does not exist — a known technique that causes the program to load without auto-running from any specific line on some loaders. - The
PRINT 'at line 220 emits a newline using the print-literal-newline idiom (the apostrophe separator in PRINT).
Content
Source Code
10 RESTORE :FOR j=0 TO 7:READ p:POKE USR "\a"+j,p:NEXT j
20 BORDER 7:PAPER 7:INK 9:CLS
30 DIM a(4):DIM b(4):DIM c(4)
40 LET s=1:RANDOMIZE
50 FOR j=1 TO 4:LET a(j)= INT (RND*6)+1:NEXT j
60 PRINT s; TAB PI;
70 FOR j=1 TO 4
80 LET i$= INKEY$
90 IF i$<"1" OR i$>"6" THEN GO TO 80
100 PRINT INK VAL i$;"\:: ";
110 IF i$= INKEY$ THEN GO TO 110
120 LET b(j)= VAL i$:LET c(j)=a(j)
130 NEXT j:PRINT " ";
140 LET p=0
150 FOR j=1 TO 4
160 IF b(j)=c(j) THEN GO SUB 320
170 NEXT j
180 IF p=4 THEN GO TO 340
190 FOR j=1 TO 4:FOR h=1 TO 4
200 IF b(j)>0 AND b(j)=c(h) THEN GO SUB 330
210 NEXT h:NEXT j
220 PRINT '
230 IF NOT p THEN BEEP .5,2:GO TO 250
240 FOR j=p TO PI:BEEP .1,5:NEXT j
250 LET s=s+1:IF s <=10 THEN GO TO 60
260 PRINT "You have failed to break the code:-"
270 PRINT TAB PI;:FOR j=1 TO 4:PRINT INK a(j);"\:: ";:NEXT j
280 INPUT "P to play again: X to stop ";a$
290 IF a$="p" THEN RUN
300 IF a$="x" THEN STOP
310 GO TO 280
320 PRINT CHR$ 143; CHR$ 32;:BEEP .01,50:LET b(j)=0:LET c(j)=0:LET p=p+1:RETURN
330 PRINT CHR$ 144; CHR$ 32;:BEEP .01,30:LET b(j)=0:LET c(h)=0:LET p=p+1:RETURN
340 PRINT AT s*2,9; INK 2; FLASH 1;"CORRECT IN ";s
350 GO TO 280
360 DATA 255,129,P,P,P,P,P,255
370 SAVE "B&C" LINE 0
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
