This program implements the Knight’s Tour puzzle, where the player must move a chess knight to every square on an 8×8 board without revisiting any square. The board is drawn using alternating inverse-video and normal characters to simulate a chequered pattern, and move numbers are printed directly onto the board at calculated screen positions using AT coordinates. Input is taken as a two-character string (e.g. “34” for row 3, column 4), with the subroutine at line 410 handling validation of range and already-visited squares. The program runs in FAST mode during board setup and switches to SLOW for interactive play, a common ZX81 technique to speed up the initial screen draw.
Program Analysis
Program Structure
The program divides cleanly into several phases:
- Initialisation (lines 10–160): Dimensions the 8×8 board array, draws the chequered grid, and zeroes all cells.
- Starting position (lines 170–270): Prompts the player for a starting square, validates it via the subroutine, marks it, and records the position.
- Main game loop (lines 280–400): Repeatedly asks for the next move, validates it, checks knight-move legality, and updates the board until all 64 squares are visited or the player quits.
- Input/validation subroutine (lines 410–480): Parses the two-character input string, range-checks both coordinates, and rejects already-visited squares.
- End/replay (lines 490–520): Offers replay on NEWLINE or halts on any other input.
Board Display
The chequered board is constructed from two alternating string patterns. A$ (line 20) contains inverse-video characters forming one row style, and B$ (line 30) contains the complementary row. These are printed in a loop (lines 80–100) using TAB and the ;; double-semicolon idiom to suppress spacing. Move numbers are placed directly on the board using PRINT AT L*2, C*3+3, mapping logical board coordinates to screen positions. A trailing space (line 240) is printed when the move count is less than 10 to keep single-digit numbers tidy.
Input Parsing
Player input is a two-character string such as "35", parsed at lines 430–440 using VAL C$(1) and VAL C$(2) to extract the row and column digits individually. This avoids any need for numeric input or comma-separated values, keeping entry fast. Entering "0" at line 340 allows the player to quit mid-game.
Knight-Move Validation
Lines 370–380 check whether the proposed square is a legal knight’s move from the current position (L1, C1). The logic attempts to replicate the two valid L-shaped move families:
- Line 370:
L=L1±2paired withC=C1±1 - Line 380:
L=L1±1paired withC=C1±2
However, these conditions contain a well-known ZX81 BASIC operator-precedence bug. The expression L=L1-2 OR L=L1+2 AND C=C1-1 OR C=C1+1 is evaluated as L=L1-2 OR (L=L1+2 AND C=C1-1) OR C=C1+1 because AND binds more tightly than OR. This means a move is accepted whenever either the column offset is ±1 (regardless of the row) or the row offset is ±2 with column offset −1. The correct check would require parentheses grouping both row and column conditions together. The same flaw appears on line 380. As a result, several illegal moves will be accepted and some valid ones may behave unexpectedly.
Array Usage and State Tracking
The 2D array B(8,8) acts as a visited-squares bitmap: cells are set to 1 at line 270 when visited, and the subroutine at line 452 rejects any square where B(L,C)=1. The move counter M serves double duty as both a display label and a win condition (M=64 at line 280).
FAST/SLOW Usage
FAST is engaged at line 50 before the board is drawn, suppressing the display during the computationally intensive screen-building loop. SLOW is restored at line 170 before interactive input begins, restoring the live display for the player.
Notable Idioms and Anomalies
| Line | Idiom / Issue |
|---|---|
90 | ;; (double semicolon) suppresses the automatic space between PRINT items |
210 | Sentinel value L=9 is used to signal invalid input from the subroutine — a classic ZX81 out-of-band return technique |
310, 410 | Fixed-width space strings are used to blank previous messages rather than CLS, preserving the board |
370–380 | Operator precedence bug makes knight-move validation incorrect (see above) |
510 | An empty INPUT response (bare NEWLINE) returns C$="", used as the replay trigger |
Content
Source Code
1 REM KNIGHTS MOVE
10 DIM B(8,8)
20 LET A$="%I%-%-%I%-%-%I%-%-%I%-%-%I%-%-%I%-%-%I%-%-%I%-%-%I"
30 LET B$="I% % I% % I% % I% % I% % I% % I% % I% % I"
40 CLS
50 FAST
60 PRINT TAB 6;"1 2 3 4 5 6 7 8"
70 PRINT TAB 5;A$
80 FOR L=1 TO 8
90 PRINT TAB 3;;L;" ";B$;TAB 5;A$
100 NEXT L
110 FOR L=1 TO 8
120 FOR C=1 TO 8
130 LET B(L,C)=0
140 NEXT C
150 NEXT L
160 LET M=0
170 SLOW
180 PRINT AT 20,0;"WHERE DO YOU WISH TO BEGIN?"
190 INPUT C$
200 GOSUB 410
210 IF L=9 THEN GOTO 180
220 LET M=M+1
230 PRINT AT L*2,C*3+3;M
240 IF M<10 THEN PRINT AT L*2,C*3+4;" "
250 LET L1=L
260 LET C1=C
270 LET B(L,C)=1
280 IF M<64 THEN GOTO 310
290 PRINT AT 20,0;"CONGRATULATIONS"
300 GOTO 490
310 PRINT AT 19,0;" 10 SPACES "
320 PRINT AT 20,0;"WHERE DO YOU WISH TO GO NEXT?"
330 INPUT C$
340 IF C$="0" THEN GOTO 490
350 GOSUB 410
360 IF L=9 THEN GOTO 320
370 IF L=L1-2 OR L=L1+2 AND C=C1-1 OR C=C1+1 THEN GOTO 220
380 IF L=L1-1 OR L=L1+1 AND C=C1-2 OR C=C1+2 THEN GOTO 220
390 PRINT AT 19,0;"IMPOSSIBLE"
400 GOTO 320
410 PRINT AT 20,0;" 28 SPACES "
420 IF LEN C$<>2 THEN GOTO 470
430 LET L=VAL C$(1)
440 LET C=VAL C$(2)
450 IF L<1 OR L>8 OR C<1 OR C>8 THEN GOTO 460
452 IF B(L,C)=1 THEN GOTO 460
454 RETURN
460 LET L=9
470 PRINT AT 19,0;"IMPOSSIBLE"
480 RETURN
490 PRINT AT 21,0;"NL TO REPLAY"
500 INPUT C$
510 IF C$="" THEN GOTO 40
520 STOP
600 SAVE "1013%3"
700 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
