Cipher has three menus, and Q quits from each of them: the title, the pause menu and the result after a word. In the program from the previous lessons, every one of those Qs runs a bare STOP. The game ends wherever it happens to be, the ROM prints 9 STOP statement underneath, and nothing tells the player what the session added up to. This lesson sends all three through one closing routine that clears the screen, shows the won and lost tally, says how to play again and only then stops.
Add lines 25, 8500, 8510, 8520, 8530, 8540, 8550.
Replace lines 100, 660, 760.
25 LET wins=0: LET losses=0
100 IF k$="q" THEN GO TO 8500
660 IF k$="q" THEN GO TO 8500
760 IF k$="q" THEN GO TO 8500
8500 CLS : PRINT AT 3,10; INK 5; BRIGHT 1;"C I P H E R"
8510 PRINT AT 7,3;"Thanks for playing."
8520 PRINT AT 10,3;"Words won: ";wins
8530 PRINT AT 12,3;"Words lost: ";losses
8540 PRINT AT 17,3;"RUN plays again."
8550 STOPComplete source at this checkpoint
10 BORDER 0: PAPER 0: INK 7: BRIGHT 0: CLS
20 RANDOMIZE
25 LET wins=0: LET losses=0
30 PRINT AT 3,10; INK 5; BRIGHT 1;"C I P H E R"
40 PRINT AT 7,3;"Find the hidden word."
50 PRINT AT 9,2;"Reveal every matching letter."
60 PRINT AT 11,3;"Seven mistakes per word."
70 PRINT AT 13,3;"Repeat guesses cost nothing."
80 PRINT AT 17,3;"S starts. Q quits."
90 GO SUB 8000
100 IF k$="q" THEN GO TO 8500
110 IF k$<>"s" THEN GO TO 90
200 LET wins=0: LET losses=0: LET round=0: LET last=0: LET total=24
210 LET pick=INT (RND*total)+1
220 IF pick=last THEN GO TO 210
230 LET last=pick: LET round=round+1: RESTORE 9000
240 FOR i=1 TO pick: READ w$: NEXT i
250 LET d$="": LET t$="": LET m$="": LET left=7: LET u$="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
260 FOR i=1 TO LEN w$: LET d$=d$+"_": NEXT i
270 LET a$="Choose a letter.": GO SUB 2000
300 GO SUB 2500
310 GO SUB 8000
320 IF CODE k$=13 THEN GO TO 600
330 LET c=CODE k$
340 IF c<97 OR c>122 THEN GO TO 310
350 LET g$=CHR$ (c-32): LET seen=0
355 IF t$="" THEN GO TO 390
360 FOR i=1 TO LEN t$: IF t$(i)=g$ THEN LET seen=1
370 NEXT i
380 IF seen=1 THEN LET a$=g$+" already tried. No cost.": GO TO 300
390 LET t$=t$+g$: LET found=0: LET u$(c-96 TO c-96)="."
395 PRINT AT 14+INT ((c-97)/13),3+2*((c-97)-13*INT ((c-97)/13));"."
400 FOR i=1 TO LEN w$
410 IF w$(i)=g$ THEN LET d$(i TO i)=g$: LET found=found+1
420 NEXT i
430 IF found>0 THEN LET a$=g$+" reveals "+STR$ found+" letter(s)."
440 IF found=0 THEN LET left=left-1: LET m$=m$+g$: LET a$=g$+" is not in the word."
450 IF d$=w$ THEN LET wins=wins+1: LET a$="Word found!": GO TO 700
460 IF left=0 THEN LET losses=losses+1: LET a$="No guesses left. Word revealed.": GO TO 700
470 GO TO 300
600 CLS : PRINT AT 3,10; INK 5; BRIGHT 1;"C I P H E R"
610 PRINT AT 7,3;"PAUSED - word stays hidden."
620 PRINT AT 10,3;"C continues this word."
630 PRINT AT 12,3;"R resets words and scores."
640 PRINT AT 14,3;"Q quits to BASIC."
650 GO SUB 8000
660 IF k$="q" THEN GO TO 8500
670 IF k$="r" THEN GO TO 200
680 IF k$="c" THEN GO SUB 2000: GO TO 300
690 GO TO 650
700 GO SUB 2000
710 PRINT AT 6,16-LEN w$; INK 4; BRIGHT 1;
720 FOR i=1 TO LEN w$: PRINT w$(i);" ";: NEXT i
730 IF left=0 THEN PRINT AT 6,16-LEN w$; INK 6; BRIGHT 1;: FOR i=1 TO LEN w$: PRINT w$(i);" ";: NEXT i
740 PRINT AT 21,1;"SPACE next. R resets. Q quits. "
750 GO SUB 8000
760 IF k$="q" THEN GO TO 8500
770 IF k$="r" THEN GO TO 200
780 IF k$=" " THEN GO TO 210
790 GO TO 750
2000 CLS
2010 PRINT AT 1,2; INK 5; BRIGHT 1;"CIPHER";AT 1,19;"WORD ";round
2020 PRINT AT 3,2;"Won ";wins;" Lost ";losses
2110 PRINT AT 12,2; INK 5;"UNTRIED LETTERS"
2120 FOR j=1 TO 26
2160 PRINT AT 14+INT ((j-1)/13),3+2*((j-1)-13*INT ((j-1)/13)); INK 7;
2170 PRINT u$(j);
2190 NEXT j
2200 PRINT AT 21,1;"Letter guesses. ENTER pauses."
2205 GO SUB 2500
2210 RETURN
2500 PRINT AT 6,16-LEN d$; INK 7; BRIGHT 1;
2510 FOR i=1 TO LEN d$: PRINT d$(i);" ";: NEXT i
2520 PRINT AT 9,2; INK 6;"MISTAKES LEFT: ";left
2530 PRINT AT 10,2; INK 6;
2540 FOR i=1 TO 7
2550 IF i<=left THEN PRINT "O ";
2560 IF i>left THEN PRINT ". ";
2570 NEXT i
2580 PRINT AT 17,2;"Misses: ";m$
2590 LET b$=a$+" ": PRINT AT 19,1; INK 6;b$( TO 30)
2600 RETURN
8000 LET k$=INKEY$
8010 IF INKEY$<>"" THEN GO TO 8010
8020 LET k$=INKEY$: IF k$="" THEN GO TO 8020
8030 IF CODE k$>=65 AND CODE k$<=90 THEN LET k$=CHR$ (CODE k$+32)
8040 RETURN
8500 CLS : PRINT AT 3,10; INK 5; BRIGHT 1;"C I P H E R"
8510 PRINT AT 7,3;"Thanks for playing."
8520 PRINT AT 10,3;"Words won: ";wins
8530 PRINT AT 12,3;"Words lost: ";losses
8540 PRINT AT 17,3;"RUN plays again."
8550 STOP
9000 DATA "WINDOW","BOTTLE","KETTLE","LADDER","RABBIT","GARDEN"
9010 DATA "POCKET","CANDLE","PILLOW","BUTTON","BASKET","BRIDGE"
9020 DATA "ORANGE","SILVER","HAMMER","ROCKET","JACKET","FOREST"
9030 DATA "CAMERA","MARKET","CARPET","SHELL","TUNNEL","STREAM"RUN, play a word to the end, start another and lose it, then press Q at the result. The board disappears and the game finishes on its own screen:

Read the report
Here is what the previous program showed when Q was pressed on the title:

The Spectrum prints a report at the bottom of the screen whenever a BASIC program stops, whatever the reason. It has three parts:
- 9 is the report code. The manual’s table of reports runs from 0 to 9 and then from A to R, so you can look a code up. Report 0 is
OK, a normal finish. Report 9 means the program reached aSTOP. - STOP statement is the short message that goes with the code.
- 100:2 is where the program stopped: line 100, statement 2. Statement 1 starts the line, and each colon or
THENbegins the next one. InIF k$="q" THEN STOP, theIFis statement 1 and theSTOPafterTHENis statement 2.
The report is written for the person who wrote the program: it says why the program stopped and exactly where. That is useful while we are building and testing. A player who sees STOP statement printed under the instructions has been told nothing they can use, and it reads more like a fault than a goodbye. The same report appeared at 660:2 from the pause menu and at 760:2 from the result, each time on top of whatever was on the screen.
One way out
Lines 100, 660 and 760 still test for Q, but each now says GO TO 8500 instead of STOP. It is GO TO, not GO SUB: the closing routine never returns, so nothing needs to remember where it came from.
The routine at 8500 does the whole ending in one place. CLS removes the title, pause menu or board, whichever was showing. Line 8500 reprints the name in the same colours as the title. Lines 8520 and 8530 print wins and losses, the tally that line 2020 has been showing at the top of the board all session. Line 8540 tells the player how to start again, and line 8550 is the program’s only STOP.
The ROM still prints its report, now 9 STOP statement, 8550:1. It sits under the game’s own words instead of replacing them, and it names the routine’s STOP whichever menu the player left from. To change the ending later, we edit one routine instead of three lines.
During play, Q is still an ordinary letter guess. Only the three menus send Q to the routine, so a player cannot end a session by guessing a letter.
Line 25 creates wins and losses before the title appears, yet line 200 sets them both to zero again when S starts a session. Suppose line 25 were left out. What would Q on the title do?
Show the explanation
The routine would stop with 2 Variable not found, 8520:1. On a fresh RUN, the title’s Q is pressed before line 200 has ever run, so wins does not exist yet. Line 8510 still prints Thanks for playing., then line 8520 is the first statement to read wins and the ROM stops there with report 2. That is the manual’s description of report 2: a simple variable used before a LET, READ or INPUT has assigned it.
Line 25 creates both variables at zero, so Q on the title shows a tally of 0 and 0. Line 200 still resets them at the start of every session, which is what R relies on.
After the game ends
STOP does not clear the variables. After quitting, type PRINT wins as a direct command and the Spectrum still knows the tally. Its report, 0 OK, 0:1, follows the same rules: code 0 for a normal finish, and line 0 because a direct command has no line number of its own. RUN clears every variable and starts again from the lowest line, so the title returns and S begins a fresh session at zero. That is why the closing screen says RUN plays again.
Try each exit: Q on the title, Q from the pause menu (Enter during a word) and Q at a result. Each should give the same closing screen with the tally at that moment and the report 9 STOP statement, 8550:1. Then play on with RUN and S.
This is the version to keep. Save it with the same direct command as before, SAVE "cipher" LINE 10, and check the new tape in a fresh machine as the previous lesson describes.
Sources
Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), appendix B for the reports, their three parts and how statements are counted.
Run it here
This unit's program, built for you.
- Program
- cipher.tap
- Machine
- ZX Spectrum 48K (PAL)