Towers of Hanoi

This file is part of and Timex Sinclair Public Domain Library Tape 1006. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000
Tags: Game

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 rangePurpose
65–185Initialization: screen drawing, disc count input, stack setup
185–285Main game loop: manual move input and validation
300–382Move execution subroutine (calls UNPLOT and PLOT routines, updates arrays)
383–397Win/new-game handler
400–460PLOT subroutine — draws a disc on a peg
500–580UNPLOT subroutine — erases a disc from a peg
600–695Computer-solve prompt subroutine
700–780Computer solver — even disc count strategy
800–855Computer solver — odd disc count strategy
900–935Single legal move between a peg pair
940–960CLEAR, 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 ? with PRINT AT over the same position.
  • Pixel-level disc drawing with PLOT/UNPLOT symmetrically 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 200 and line 285 uses GOTO 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 300 calls at lines 271 and 930 correctly fall through to line 305.
  • Line 703 resets NN=0 for 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)<N and 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

Appears On

Assembled by Tim Ward from many sources. Contains programs 10252 – 10293.

Related Products

Related Articles

Related Content

Image Gallery

Towers of Hanoi

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.

People

No people associated with this content.

Scroll to Top