This program implements the Tower of Hanoi puzzle, presenting three pegs on screen with up to seven discs displayed as proportionally wider block-graphic strings. The board is drawn using block graphic characters to represent peg shafts and discs of seven distinct sizes stored in a string array A$(7,8). Game state is tracked in a 3×7 integer array A(3,7), where each element holds either 1 (empty slot) or a disc number 2–7. The invalid-move indicator uses a flicker effect by alternating a normal and inverse-video version of “INVALID MOVE” in a loop of 31 iterations. Victory is detected by checking whether peg 1 or peg 3 has a disc in slot 2 (the second-from-top), which implicitly confirms the full stack has been moved.
Program Analysis
Program Structure
The program is organised into four functional sections:
- Initialisation and screen draw (lines 5–150): Draws the playing field border, peg shafts, and loads disc graphics into
A$. - Main game loop (lines 155–420): Redraws the board, accepts moves, validates them, updates state, and increments the move counter.
- Invalid-move handler (lines 1000–1050): Flickers an error message and returns to input.
- Win detection and restart (lines 2000–2080): Congratulates the player, prints the move count, and offers a replay.
Data Representation
The board state is held in array A(3,7): three pegs, each with seven slots numbered 1–7 from top to bottom. A slot value of 1 represents an empty space (matching A$(1), a bare peg-shaft graphic), while values 2 through 7 represent discs of increasing width. This means disc identity doubles as an index into A$, keeping the rendering loop at line 180 to a single PRINT AT statement.
Disc Graphics
Seven disc strings are stored in A$(7,8) (seven strings, each eight characters wide). The block graphic \ : (▐, right half-block) represents the peg shaft through empty slots and disc ends, while % characters pad disc bodies with spaces to create width variation. The widest disc (A$(7)) fills all eight columns.
| Index | Content | Meaning |
|---|---|---|
| 1 | " \ :" | Empty slot / peg shaft |
| 2 | " % \: " | Disc width 2 |
| 3 | " \ :% % " | Disc width 3 |
| 4–7 | progressively wider | Discs 4–7 |
Move Validation Logic
Validation proceeds in two passes. The first pass (lines 270–330) scans peg J top-to-bottom looking for the topmost non-empty slot; if none is found the move is invalid. The found disc number is stored in Q at position P. The second pass (lines 340–370) scans peg K looking for the first occupied slot; if that slot’s disc is smaller than Q the move is illegal. The destination slot for placement is computed at line 380 as D-1, i.e. the slot immediately above the first occupied (or the bottom slot if all were empty).
Win Condition
Victory is tested at line 205:
IF A(1,2)=2 OR A(3,2)=2 THEN GOTO 2000
This checks whether disc 2 (the second-smallest) sits in slot 2 of peg 1 or peg 3. Because the discs must be stacked in strict size order, disc 2 in slot 2 implies disc 3 in slot 3, disc 4 in slot 4, and so on all the way down — confirming the full seven-disc tower has been assembled on an end peg. The condition only triggers after the board has been redrawn at line 160, so the completed tower is always shown before the congratulations message.
Invalid-Move Flicker Effect
Lines 1000–1040 implement a simple flicker by printing the plain and inverse-video versions of INVALID MOVE alternately at the same screen position inside a FOR U=0 TO 30 loop. The inverse text uses per-character inverse markers (%I%N%V%A%L%I%D% %M%O%V%E).
Notable Techniques and Idioms
- The border row at line 30 uses a long run of
\''(▀ top half-block) characters to draw a solid horizontal rule across the full screen width. - The move counter
Cis initialised to1at line 155 and incremented before redisplay, so the displayed count at win isC-1(line 2000), correctly reflecting only completed moves. - Line 395’s
DIM A$(7,8)fixes each string at exactly eight characters, keeping column alignment consistent across all peg positions regardless of disc width. - Restart uses
RUN(line 2040) rather thanGOTO 20, which fully reinitialises all variables and arrays — ensuring a clean slate without a separate reset routine.
Bugs and Anomalies
- Line 130 initialises
A(1,Z)=1andA(3,Z)=1(empty pegs) but also setsA(2,Z)=Zfor all Z from 7 down to 1. This places disc numberZin slotZof peg 2 — which correctly stacks discs 1 through 7 top-to-bottom only if slot index equals disc number, which it does here by design. - The redraw loop at lines 160–195 unconditionally redraws all three pegs on every move, which causes minor flicker but is functionally correct.
- Line 2070 (
SAVE "1021%3") followed byRUNat line 2080 are unreachable dead code;STOPat line 2050 halts execution before either is ever reached in normal play.
Content
Source Code
5 REM "TOWERS"
20 CLS
30 PRINT AT 20,0;"\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''"
35 PRINT AT 21,8;"1";TAB 16;"2";TAB 24;"3"
40 FOR X=10 TO 19
50 PRINT AT X,5;" \ : \ : \ :"
60 NEXT X
61 DIM A(3,7)
65 DIM A$(7,8)
67 LET A$(1)=" \ :"
70 LET A$(2)=" % \: "
80 LET A$(3)=" \ :% % "
90 LET A$(4)=" % % % \: "
100 LET A$(5)=" \ :% % % % "
110 LET A$(6)=" % % % % % \: "
120 LET A$(7)="\ :% % % % % % "
130 FOR Z=7 TO 1 STEP -1
135 LET A(1,Z)=1
140 LET A(2,Z)=Z
145 LET A(3,Z)=1
150 NEXT Z
155 LET C=1
160 FOR Z=1 TO 3
170 FOR Y=7 TO 1 STEP -1
180 PRINT AT Y+12,Z*8-3;A$(A(Z,Y))
190 NEXT Y
195 NEXT Z
201 PRINT AT 0,24;"MOVE: ";C
205 IF A(1,2)=2 OR A(3,2)=2 THEN GOTO 2000
208 PRINT AT 0,0;" "
210 PRINT AT 0,0;"FROM? "
220 INPUT J
230 PRINT AT 0,0;J;" TO ?"
240 INPUT K
250 PRINT AT 0,0;J;" TO ";K
255 IF J>3 OR J<1 OR K>3 OR K<1 THEN GOTO 1000
260 IF K=J THEN GOTO 1000
270 FOR D=1 TO 7
280 IF A(J,D)=1 THEN GOTO 320
290 LET P=D
300 LET Q=A(J,D)
310 GOTO 340
320 NEXT D
330 GOTO 1000
340 FOR D=1 TO 7
350 IF A(K,D)=1 THEN GOTO 370
360 IF A(K,D)<Q THEN GOTO 1000
365 IF A(K,D)>1 THEN GOTO 380
370 NEXT D
380 LET D=D-1
390 LET A(K,D)=A(J,P)
400 LET A(J,P)=1
410 LET C=C+1
420 GOTO 160
\n1000 FOR U=0 TO 30
\n1020 PRINT AT 0,0;"INVALID MOVE";AT 0,0;"%I%N%V%A%L%I%D% %M%O%V%E"
\n1040 NEXT U
\n1050 GOTO 208
\n2000 PRINT AT 0,0;"YOU HAVE COMPLETED THE TOWERS IN";C-1;" MOVES"
\n2010 PRINT
\n2020 PRINT "TRY AGAIN?"
\n2030 INPUT S$
\n2040 IF S$(1)="Y" THEN RUN
\n2050 STOP
\n2070 SAVE "1021%3"
\n2080 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
