Skip to content

Read the board

Show unused letters and update the parts of the screen that change.

  • Sinclair ZX Spectrum
  • BASIC

Make the available choices visible. The board adds a spaced word, seven mistake markers and a two-row alphabet. Used letters become dots; misses still have their own list. Readability does not depend on distinguishing two colours.

Add lines 395, 720, 730, 2110, 2120, 2160, 2170, 2190, 2510, 2530, 2540, 2550, 2560, 2570.

Replace lines 250, 390, 710, 2500.

changes.bas
 250 LET d$="": LET t$="": LET m$="": LET left=7: LET u$="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 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));"."
 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
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
2500 PRINT AT 6,16-LEN d$; INK 7; BRIGHT 1;
2510 FOR i=1 TO LEN d$: PRINT d$(i);" ";: NEXT i
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
Complete source at this checkpoint
cipher.bas
  10 BORDER 0: PAPER 0: INK 7: BRIGHT 0: CLS
 200 LET wins=0: LET losses=0: LET round=1
 210 LET w$="BOTTLE"
 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 STOP
 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 STOP
 770 IF k$="r" THEN GO TO 200
 780 IF k$=" " THEN LET round=round+1: 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

RUN and press T. The two Ts should appear in the word, while T becomes a dot in the alphabet. Press Z: one marker becomes a dot and Z joins the miss list. Pause and continue; the same board should return.

Store what can be redrawn

The new u$ begins as the uppercase alphabet. The game already knows that c is the code of a lowercase letter. Subtracting 96 gives its position in u$: a becomes one, z becomes twenty-six. Line 390 replaces that position with a dot. The string can now reconstruct the alphabet after a menu has covered the screen.

This is a second use of slice assignment. In d$, a known letter replaces an underscore; in u$, a used letter becomes a dot. The attempt history still prevents duplicate costs, while u$ describes how the choices should look.

Fold a row into two

For alphabet position j, first use j-1 to get a position from zero to twenty-five. Dividing by thirteen and taking INT gives zero for the first row and one for the second. Adding fourteen selects screen row 14 or 15. Subtracting thirteen times that row offset leaves the position within the row. Multiply by two for letter spacing, then add three for the left margin.

Where should N, alphabet position 14, appear?

Show the explanation

At screen row 15, column 3. Its zero-based position is 13; INT(13/13) is one. Removing one row of thirteen leaves zero, so it starts the second row.

PRINT AT addresses a character row and column from zero. It does not use the string’s one-based positions. Line 395 performs the same calculation for the newly guessed letter using c-97. It prints just that letter’s dot during play.

Redraw only what changed

The complete board routine loops through all twenty-six letters when entering a round, returning from pause or showing a result. Ordinary guesses redraw the word and feedback fields, plus one alphabet cell. Clearing the whole board after every guess would do work the screen does not need and make the response slower.

The word loop prints each character followed by a space. Its starting column, 16-LEN d$, centres that doubled width in the thirty-two-column display. The marker loop prints O for each remaining mistake and a dot for each spent one; both occupy the same width, so older markers disappear cleanly.

INK chooses text colour, BRIGHT selects brightness, and BORDER and PAPER establish the surrounding and background colours. Colour controls inside PRINT apply to that PRINT statement. The rules still use stored letters and numbers, never the colour of a screen cell.

Try T, Z and a repeated Z; check the word, alphabet, count, markers and miss list agree. Then test pause/continue and both endings. This checkpoint still plays BOTTLE each round, so the same inputs give the same state changes.

Sources

Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapter 8, chapter 10, chapter 15, chapter 16.

Run it here

This unit's program, built for you.

Program
cipher.tap
Machine
ZX Spectrum 48K (PAL)

Download cipher.tap