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,
40 'foreground': 'blue'})
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
,
72 self
.pegstate
[0].append(i
)
73 x1
, x2
= x1
+ dx
, x2
-dx
74 y1
, y2
= y1
- pieceheight
-2, y2
-pieceheight
-2
78 # Run -- never returns
81 hanoi(self
.n
, 0, 1, 2, self
.report
)
82 hanoi(self
.n
, 1, 2, 0, self
.report
)
83 hanoi(self
.n
, 2, 0, 1, self
.report
)
84 hanoi(self
.n
, 0, 2, 1, self
.report
)
85 hanoi(self
.n
, 2, 1, 0, self
.report
)
86 hanoi(self
.n
, 1, 0, 2, self
.report
)
88 # Reporting callback for the actual hanoi function
89 def report(self
, i
, a
, b
):
90 if self
.pegstate
[a
][-1] != i
: raise RuntimeError # Assertion
91 del self
.pegstate
[a
][-1]
95 # Lift the piece above peg a
96 ax1
, ay1
, ax2
, ay2
= c
.bbox(self
.pegs
[a
])
98 x1
, y1
, x2
, y2
= c
.bbox(p
)
103 # Move it towards peg b
104 bx1
, by1
, bx2
, by2
= c
.bbox(self
.pegs
[b
])
105 newcenter
= (bx1
+bx2
)/2
107 x1
, y1
, x2
, y2
= c
.bbox(p
)
109 if center
== newcenter
: break
110 if center
> newcenter
: c
.move(p
, -1, 0)
111 else: c
.move(p
, 1, 0)
114 # Move it down on top of the previous piece
115 pieceheight
= y2
-y1
-2
116 newbottom
= by2
- pieceheight
*len(self
.pegstate
[b
]) - 2
118 x1
, y1
, x2
, y2
= c
.bbox(p
)
119 if y2
>= newbottom
: break
124 self
.pegstate
[b
].append(i
)
131 # First argument is number of pegs, default 4
133 n
= string
.atoi(sys
.argv
[1])
137 # Second argument is bitmap file, default none
140 # Reverse meaning of leading '@' compared to Tk
141 if bitmap
[0] == '@': bitmap
= bitmap
[1:]
142 else: bitmap
= '@' + bitmap
146 # Create the graphical objects...
147 h
= Tkhanoi(n
, bitmap
)
153 # Call main when run as script
154 if __name__
== '__main__':