This program implements the Towers of Hanoi puzzle on a pixel-graphics display, supporting both manual play and an automated computer solver. The display uses PLOT/UNPLOT to draw disc representations on three pegs drawn with block graphics characters, and the game tracks move counts against the theoretical minimum of 2ⁿ−1. The computer solver at line 700 uses two different movement strategies depending on whether the disc count is odd or even, cycling through pairs of pegs (subroutine 900) until all discs reach peg 3. Disc size is encoded as an integer in a two-dimensional array D(N,3), with a stack-pointer array N(3) tracking the top disc on each peg.
Program Analysis
Program Structure
The program is organized into clearly delineated sections accessed via GOSUB:
| Line range | Purpose |
|---|---|
| 65–185 | Initialization: screen drawing, disc count input, stack setup |
| 185–285 | Main game loop: manual move input and validation |
| 300–382 | Move execution subroutine (calls UNPLOT and PLOT routines, updates arrays) |
| 383–397 | Win/new-game handler |
| 400–460 | PLOT subroutine — draws a disc on a peg |
| 500–580 | UNPLOT subroutine — erases a disc from a peg |
| 600–695 | Computer-solve prompt subroutine |
| 700–780 | Computer solver — even disc count strategy |
| 800–855 | Computer solver — odd disc count strategy |
| 900–935 | Single legal move between a peg pair |
| 940–960 | CLEAR, SAVE and RUN for auto-restart |
Data Representation
Two arrays manage the puzzle state. N(3) (declared at line 140, shadowing the scalar N which holds the disc count — note the name collision) acts as a stack pointer for each of the three pegs. D(N,3) is a 2-D array where D(k,p) holds the size of disc at position k on peg p. Disc sizes run from 1 (smallest) to N (largest). A value of 0 in D means the slot is empty.
There is a notable naming collision: the variable N is first used as the disc count scalar, then DIM N(3) at line 140 replaces it with an array. Sinclair BASIC allows a scalar and an array to share the same letter, so both coexist, with N (scalar) remaining accessible as the disc count and N(x) being the stack-pointer array.
Display Technique
The three pegs are represented as vertical columns of block-graphic characters ("\@@" — solid block characters) drawn with PRINT AT in lines 75–86. Disc graphics are rendered with PLOT/UNPLOT in the pixel domain. The PLOT subroutine (lines 400–460) computes a horizontal centre H = 20*Y - 6 for each peg and a vertical coordinate V = 27 + 2*N(Y), then plots symmetric pairs of pixels outward from the centre for each unit of disc size. The UNPLOT subroutine mirrors this to erase. This gives discs a proportional pixel-width representation.
Input Handling
All key input uses the pattern of printing a flashing cursor (alternating plain "?" and inverse "%?"), then reading CODE INKEY$ in a tight loop. This is a standard TS2068/Spectrum idiom for single-keypress input without blocking via INPUT. Digit keys 1–8 have CODE values 29–36 (Sinclair key codes), checked at lines 116 and 215/242. The ENTER/NEW-LINE key has code 118, checked at line 395.
Computer Solver Algorithm
The solver does not use recursion. Instead it exploits the cyclic property of the Tower of Hanoi: for an even number of discs, the optimal solution is achieved by repeatedly cycling moves in the order (1→2), (1→3), (2→3); for odd disc counts the order is (1→3), (1→2), (3→2). The cycle repeats until peg 3 holds all discs, then jumps to the win handler at line 383.
Subroutine 900 (lines 905–935) implements a single legal move between pegs P and Q: it picks the peg with the smaller top disc (or the non-empty peg if one is empty) as the source, then calls the move execution subroutine at 300.
Move Validation
Manual moves are validated at lines 257–270. If the destination stack is non-empty (N(Y)>0) and the moving disc is not smaller than the top disc on the destination, the move is rejected as illegal. An empty destination always accepts any disc (line 257). Same-peg moves are caught at line 250.
Win Condition
The game checks N(3)=N (i.e., the stack pointer for peg 3 equals the total disc count) at lines 275 and 760/820. When satisfied, the win handler prints a prompt and waits for ENTER to start a new game via GOTO 2 (a non-existent line, which causes the program to fall through to the next available line — line 65 — a well-known Sinclair BASIC technique).
Notable Techniques
- Flashing cursor using alternating plain and inverse
?withPRINT ATover the same position. - Pixel-level disc drawing with
PLOT/UNPLOTsymmetrically around a peg centre. - Non-recursive computer solver using a fixed peg-pair cycling strategy differentiated by disc parity.
- The
SAVE "1026%1"at line 950 uses an inverse character in the filename as an auto-run marker. VAL (CHR$ C)at lines 117 and 245 converts a key code to its digit value without a lookup table.
Bugs and Anomalies
- Line 270 uses
GOTO 200and line 285 usesGOTO 2, both targeting non-existent lines; execution resumes at the next existing line (205 and 65 respectively). This is intentional Sinclair BASIC shorthand. - The subroutine nominally starting at line 300 actually begins at line 305, since there is no line 300. The
GOSUB 300calls at lines 271 and 930 correctly fall through to line 305. - Line 703 resets
NN=0for the computer solver run but this does not reset the on-screen counter until the first move is printed; a minor cosmetic inconsistency. - The win check at line 275 only tests
N(3)<Nand jumps to 200 if false, meaning it only detects victory when all discs are on peg 3, which is the conventional goal but means the game cannot end on peg 1 or 2.
Content
Source Code
65 CLS
70 FOR I=0 TO 7
75 PRINT AT I,7;"\@@";TAB 17;"\@@";TAB 27;"\@@"
80 PRINT AT 8,3+I;"\@@";AT 8,31-I;"\@@";AT 8,11+I;"\@@";AT 8,23-I;"\@@"
81 PRINT AT 9,3+I;"\@@";AT 9,31-I;"\@@";AT 9,11+I;"\@@";AT 9,23-I;"\@@"
85 NEXT I
86 PRINT AT 10,3;"\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~"
90 PRINT AT 8,7;1;TAB 17;2;TAB 27;3
95 PRINT AT 9,6;" ** TOWERS OF HANOI ** "
105 PRINT AT 11,0;"NUMBER OF DISCS = "
110 PRINT AT 11,18;"?"
111 PRINT AT 11,18;"%?"
115 LET C=CODE INKEY$
116 IF C<29 OR C>36 THEN GOTO 110
117 LET N=VAL (CHR$ C)
118 PRINT AT 11,18;N
119 LET NN=0
120 PRINT AT 13,0;"NUMBER OF MOVES = ";NN
121 PRINT AT 14,1;"MINIMUM NUMBER = ";2**N-1
140 DIM N(3)
145 DIM D(N,3)
150 LET Y=1
155 FOR I=1 TO N
160 LET N(Y)=I
165 LET D(N(Y),Y)=N+1-I
170 GOSUB 400
180 NEXT I
185 GOSUB 600
195 IF CC=62 THEN GOTO 700
205 PRINT AT 11,0;"MOVE FROM STACK TO STACK "
210 PRINT AT 11,16;"?"
211 PRINT AT 11,16;"%?"
214 LET C=CODE INKEY$
215 IF C<29 OR C>31 THEN GOTO 210
216 LET X=VAL (CHR$ C)
220 IF N(X)>0 THEN GOTO 230
225 PRINT AT 12,0;"STACK ";X;" IS EMPTY "
226 GOTO 210
230 PRINT AT 11,16;X
231 PRINT AT 12,0;" "
235 PRINT AT 11,27;"?"
236 PRINT AT 11,27;"%?"
240 LET C=CODE INKEY$
242 IF C<29 OR C>31 THEN GOTO 235
245 LET Y=VAL (CHR$ C)
250 IF Y=X THEN GOTO 235
255 PRINT AT 11,27;Y
257 IF N(Y)=0 THEN GOTO 271
260 IF D(N(X),X)<D(N(Y),Y) THEN GOTO 271
265 PRINT AT 12,0;"ILLEGAL MOVE - TRY AGAIN PLEASE"
270 GOTO 200
271 GOSUB 300
275 IF N(3)<N THEN GOTO 200
280 GOSUB 383
285 GOTO 2
305 GOSUB 500
310 LET N(Y)=N(Y)+1
315 LET D(N(Y),Y)=D(N(X),X)
320 GOSUB 400
325 LET D(N(X),X)=0
330 LET N(X)=N(X)-1
380 LET NN=NN+1
381 PRINT AT 13,18;NN
382 RETURN
385 PRINT AT 15,0;"TO START NEW GAME PRESS ","""NEW-LINE"" KEY "
390 LET C=CODE INKEY$
395 IF C=118 THEN GOTO 397
396 GOTO 390
397 GOTO 2
405 LET D=D(N(Y),Y)
410 LET H=20*Y-6
412 LET V=27+2*N(Y)
420 FOR J=1 TO D
425 PLOT H+1+J,V
426 PLOT H-J,V
440 NEXT J
460 RETURN
505 LET D=D(N(X),X)
510 LET H=20*X-6
512 LET V=27+2*N(X)
520 FOR J=D TO 1 STEP -1
525 UNPLOT H+1+J,V
526 UNPLOT H-J,V
540 NEXT J
580 RETURN
605 PRINT AT 15,0;"DO YOU WISH COMPUTER TO MAKE","THE MOVES? "
610 PRINT AT 16,11;"YES OR %NO"
611 PRINT AT 16,11;"%YES OR NO"
615 LET CC=CODE INKEY$
620 IF CC=62 OR CC=51 THEN GOTO 630
625 GOTO 610
630 FOR V=15 TO 16
635 FOR C=0 TO 31
640 PRINT AT V,C;" "
645 NEXT C
650 NEXT V
655 LET C=0
695 RETURN
703 LET NN=0
705 IF N=1 OR N=3 OR N=5 OR N=7 THEN GOTO 800
715 LET P=1
720 LET Q=2
725 GOSUB 900
730 LET P=1
735 LET Q=3
740 GOSUB 900
745 LET P=2
750 LET Q=3
755 GOSUB 900
760 IF N(3)=N THEN GOTO 385
780 GOTO 715
805 LET P=1
810 LET Q=3
815 GOSUB 900
820 IF N(3)=N THEN GOTO 385
825 LET P=1
830 LET Q=2
835 GOSUB 900
840 LET P=3
845 LET Q=2
850 GOSUB 900
855 GOTO 805
905 LET X=P
910 LET Y=Q
915 IF N(P)=0 THEN LET X=Q
916 IF N(P)=0 OR N(Q)=0 THEN GOTO 925
920 IF D(N(P),P)>D(N(Q),Q) THEN LET X=Q
925 IF X=Q THEN LET Y=P
930 GOSUB 300
935 RETURN
940 CLEAR
950 SAVE "1026%1"
960 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

