The guess 2211 contains every digit in the practice code 1122, but none is in the right place. Add OTHER to describe those matches. Repeated digits make the counting interesting: one occurrence must never pay for two matches.
Replace lines 1030, 1040, 3000, 3120, 4020.
Add lines 3030, 3040, 3050, 3060, 3070, 3080, 3090, 3100, 3110.
1030 PRINT AT 4,1; INK 5;"TRY";AT 4,7;"CODE";AT 4,19;"EXACT";AT 4,26;"OTHER"
1040 PRINT AT 5,1; INK 1;"-";AT 5,7;". . . .";AT 5,21;".";AT 5,28;"."
3000 DIM g(4): LET bulls=0: LET total=0
3030 FOR d=1 TO 6
3040 LET cc=0: LET gc=0
3050 FOR i=1 TO 4
3060 IF c(i)=d THEN LET cc=cc+1
3070 IF g(i)=d THEN LET gc=gc+1
3080 NEXT i
3090 IF cc<=gc THEN LET total=total+cc
3100 IF gc<cc THEN LET total=total+gc
3110 NEXT d
3120 LET cows=total-bulls: RETURN
4020 PRINT AT 4 +t,21; INK 4;bulls;AT 4 +t,28; INK 6;cowsRUN the changed program.
Complete source at this checkpoint
10 BORDER 0: PAPER 0: INK 7: BRIGHT 1: CLS
200 DIM c(4): LET c(1)=1: LET c(2)=1: LET c(3)=2: LET c(4)=2
220 LET t=1: LET g$="": GO SUB 1000
230 GO SUB 9000
240 GO SUB 2000
250 LET k$=INKEY$: IF k$="" THEN GO TO 250
260 IF k$="q" OR k$="Q" THEN GO TO 8000
270 IF k$="r" OR k$="R" THEN GO TO 200
280 IF k$=CHR$ 13 THEN GO TO 400
290 IF k$="d" OR k$="D" OR k$=CHR$ 12 THEN GO TO 350
300 IF k$<"1" OR k$>"6" THEN GO TO 230
310 IF LEN g$=4 THEN GO TO 230
320 LET g$=g$+k$: GO TO 230
350 IF LEN g$>0 THEN LET g$=g$( TO LEN g$-1)
360 GO TO 230
400 IF LEN g$<>4 THEN PRINT AT 18,2; INK 6;"Enter four digits first. ": GO TO 230
410 GO SUB 3000
420 GO SUB 4000: PRINT AT 18,2;" "
470 GO TO 230
1000 CLS
1010 PRINT AT 0,1; INK 5;"LOCKSMITH";AT 0,21; INK 7;"PRACTICE"
1020 PRINT AT 2,1; INK 7;"Practice code: 1122"
1030 PRINT AT 4,1; INK 5;"TRY";AT 4,7;"CODE";AT 4,19;"EXACT";AT 4,26;"OTHER"
1040 PRINT AT 5,1; INK 1;"-";AT 5,7;". . . .";AT 5,21;".";AT 5,28;"."
1050 PRINT AT 16,1; INK 5;"------------------------------"
1060 PRINT AT 20,1; INK 7;"1-6: digits D: erase"
1070 PRINT AT 21,1;"ENTER: check R: clear Q: quit"
1080 RETURN
2000 PRINT AT 17,1; INK 5;"TRY ";t;" ";AT 17,7; INK 7;"_ _ _ _"
2010 FOR i=1 TO LEN g$: PRINT AT 17,5 +2 *i; PAPER 1; INK 7;g$(i): NEXT i
2020 RETURN
3000 DIM g(4): LET bulls=0: LET total=0
3010 FOR i=1 TO 4: LET g(i)=VAL g$(i): IF g(i)=c(i) THEN LET bulls=bulls+1
3020 NEXT i
3030 FOR d=1 TO 6
3040 LET cc=0: LET gc=0
3050 FOR i=1 TO 4
3060 IF c(i)=d THEN LET cc=cc+1
3070 IF g(i)=d THEN LET gc=gc+1
3080 NEXT i
3090 IF cc<=gc THEN LET total=total+cc
3100 IF gc<cc THEN LET total=total+gc
3110 NEXT d
3120 LET cows=total-bulls: RETURN
4000 PRINT AT 4 +t,1; INK 7;t
4010 FOR i=1 TO 4: PRINT AT 4 +t,5 +2 *i; PAPER 1; INK 7;g$(i): NEXT i
4020 PRINT AT 4 +t,21; INK 4;bulls;AT 4 +t,28; INK 6;cows
4030 RETURN
8000 PAPER 0: INK 7: BRIGHT 0: PRINT AT 21,1;"LOCKSMITH finished. ": STOP
9000 IF INKEY$<>"" THEN GO TO 9000
9010 RETURNTry 2211. Expect 0 EXACT and 4 OTHER. The visible practice code and single result row remain; each submission still replaces that row and leaves its guess editable.
Count what each side can supply
For each digit from 1 to 6, count its occurrences in the code and in the guess. Only the smaller count can contribute matches.
For code 1122 and guess 1111, the counts are:
| Digit | In the code | In the guess | Available matches |
|---|---|---|---|
| 1 | 2 | 4 | 2 |
| 2 | 2 | 0 | 0 |
| 3–6 | 0 | 0 | 0 |
The four guessed ones cannot all match when the code supplies only two. The total is 2. Both matches are already EXACT, so OTHER is 0.
Two loops, two questions
The outer loop chooses a digit d, from 1 through 6. At 3040, cc and gc are cleared for that digit. The inner loop then visits all four positions, counting code occurrences in cc and guess occurrences in gc. NEXT i finishes that scan before NEXT d chooses another digit.
Lines 3090 and 3100 add the smaller count to total. When cc equals gc, only the first test succeeds: it uses <=, while the second uses <. Equal counts are added once.
This total includes correct digits in correct positions. We have already counted those in bulls, so cows = total - bulls leaves the OTHER count. The names bulls and cows stay inside the program; the screen explains their meanings as EXACT and OTHER.
Why would comparing each of the four guessed ones with every code digit give a bad answer for 1111 against 1122?
Show the explanation
The same two code occurrences would be reused for several guessed ones. Even a search that stops at the first matching code digit for each guessed one would incorrectly award four matches. Counting the available occurrences caps the contribution at two. Subtracting the two exact matches then leaves zero other matches.
Check both kinds of clue
Try these guesses against the unchanged 1122 code:
| Guess | EXACT | OTHER |
|---|---|---|
| 1111 | 2 | 0 |
| 2211 | 0 | 4 |
| 1212 | 2 | 2 |
| 1234 | 1 | 1 |
| 1112 | 3 | 0 |
| 3456 | 0 | 0 |
For 1234, the shared digits are one 1 and one 2. Only the 1 is correctly placed. For 1112, the available matches are two ones and one two; all three are already exact.
If a repeated guess changes its clues, check the resets at 3000 and 3040. If EXACT plus OTHER exceeds four, check the two smaller-count tests. Colours and printed characters take no part in these calculations.
Sources
Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapter 4, chapter 12. Nested loops visit digit values and array positions. The occurrence-counting rule and worked examples describe this game’s scorer.
Run it here
This unit's program, built for you.
- Program
- locksmith.tap
- Machine
- ZX Spectrum 48K (PAL)