1 # Animated Towers of Hanoi using Tk with optional bitmap file in
4 # Usage: tkhanoi [n [bitmapfile]]
6 # n is the number of pieces to animate; default is 4, maximum 15.
8 # The bitmap file can be any X11 bitmap file (look in
9 # /usr/include/X11/bitmaps for samples); it is displayed as the
10 # background of the animation. Default is no bitmap.
12 # This uses Steen Lumholt's Tk interface
16 # Basic Towers-of-Hanoi algorithm: move n pieces from a to b, using c
17 # as temporary. For each move, call report()
18 def hanoi(n
, a
, b
, c
, report
):
20 hanoi(n
-1, a
, c
, b
, report
)
22 hanoi(n
-1, c
, b
, a
, report
)
25 # The graphical interface
29 def __init__(self
, n
, bitmap
= None):
32 self
.canvas
= c
= Canvas(tk
)
34 width
, height
= tk
.getint(c
['width']), tk
.getint(c
['height'])
36 # Add background bitmap
38 self
.bitmap
= c
.create_bitmap(width
/2, height
/2,
46 x1
, y1
= (pegdist
-pegwidth
)/2, height
*1/3
47 x2
, y2
= x1
+pegwidth
, y1
+pegheight
49 p
= c
.create_rectangle(x1
, y1
, x2
, y2
, fill
='black')
51 x1
, x2
= x1
+pegdist
, x2
+pegdist
52 p
= c
.create_rectangle(x1
, y1
, x2
, y2
, fill
='black')
54 x1
, x2
= x1
+pegdist
, x2
+pegdist
55 p
= c
.create_rectangle(x1
, y1
, x2
, y2
, fill
='black')
60 pieceheight
= pegheight
/16
61 maxpiecewidth
= pegdist
*2/3
62 minpiecewidth
= 2*pegwidth
63 self
.pegstate
= [[], [], []]
65 x1
, y1
= (pegdist
-maxpiecewidth
)/2, y2
-pieceheight
-2
66 x2
, y2
= x1
+maxpiecewidth
, y1
+pieceheight
67 dx
= (maxpiecewidth
-minpiecewidth
) / (2*max(1, n
-1))
68 for i
in range(n
, 0, -1):
69 p
= c
.create_rectangle(x1
, y1
, x2
, y2
, fill
='red')
71 self
.pegstate
[0].append(i
)
72 x1
, x2
= x1
+ dx
, x2
-dx
73 y1
, y2
= y1
- pieceheight
-2, y2
-pieceheight
-2
77 # Run -- never returns
80 hanoi(self
.n
, 0, 1, 2, self
.report
)
81 hanoi(self
.n
, 1, 2, 0, self
.report
)
82 hanoi(self
.n
, 2, 0, 1, self
.report
)
83 hanoi(self
.n
, 0, 2, 1, self
.report
)
84 hanoi(self
.n
, 2, 1, 0, self
.report
)
85 hanoi(self
.n
, 1, 0, 2, self
.report
)
87 # Reporting callback for the actual hanoi function
88 def report(self
, i
, a
, b
):
89 if self
.pegstate
[a
][-1] != i
: raise RuntimeError # Assertion
90 del self
.pegstate
[a
][-1]
94 # Lift the piece above peg a
95 ax1
, ay1
, ax2
, ay2
= c
.bbox(self
.pegs
[a
])
97 x1
, y1
, x2
, y2
= c
.bbox(p
)
102 # Move it towards peg b
103 bx1
, by1
, bx2
, by2
= c
.bbox(self
.pegs
[b
])
104 newcenter
= (bx1
+bx2
)/2
106 x1
, y1
, x2
, y2
= c
.bbox(p
)
108 if center
== newcenter
: break
109 if center
> newcenter
: c
.move(p
, -1, 0)
110 else: c
.move(p
, 1, 0)
113 # Move it down on top of the previous piece
115 newbottom
= by2
- pieceheight
*len(self
.pegstate
[b
]) - 2
117 x1
, y1
, x2
, y2
= c
.bbox(p
)
118 if y2
>= newbottom
: break
123 self
.pegstate
[b
].append(i
)
130 # First argument is number of pegs, default 4
132 n
= string
.atoi(sys
.argv
[1])
136 # Second argument is bitmap file, default none
139 # Reverse meaning of leading '@' compared to Tk
140 if bitmap
[0] == '@': bitmap
= bitmap
[1:]
141 else: bitmap
= '@' + bitmap
145 # Create the graphical objects...
146 h
= Tkhanoi(n
, bitmap
)
152 # Call main when run as script
153 if __name__
== '__main__':