ยปCore Development>Code coverage>Tools/demo/hanoi.py

Python code coverage for Tools/demo/hanoi.py

#countcontent
1n/a#!/usr/bin/env python3
2n/a
3n/a"""
4n/aAnimated Towers of Hanoi using Tk with optional bitmap file in background.
5n/a
6n/aUsage: hanoi.py [n [bitmapfile]]
7n/a
8n/an is the number of pieces to animate; default is 4, maximum 15.
9n/a
10n/aThe bitmap file can be any X11 bitmap file (look in /usr/include/X11/bitmaps for
11n/asamples); it is displayed as the background of the animation. Default is no
12n/abitmap.
13n/a"""
14n/a
15n/afrom tkinter import Tk, Canvas
16n/a
17n/a# Basic Towers-of-Hanoi algorithm: move n pieces from a to b, using c
18n/a# as temporary. For each move, call report()
19n/adef hanoi(n, a, b, c, report):
20n/a if n <= 0: return
21n/a hanoi(n-1, a, c, b, report)
22n/a report(n, a, b)
23n/a hanoi(n-1, c, b, a, report)
24n/a
25n/a
26n/a# The graphical interface
27n/aclass Tkhanoi:
28n/a
29n/a # Create our objects
30n/a def __init__(self, n, bitmap = None):
31n/a self.n = n
32n/a self.tk = tk = Tk()
33n/a self.canvas = c = Canvas(tk)
34n/a c.pack()
35n/a width, height = tk.getint(c['width']), tk.getint(c['height'])
36n/a
37n/a # Add background bitmap
38n/a if bitmap:
39n/a self.bitmap = c.create_bitmap(width//2, height//2,
40n/a bitmap=bitmap,
41n/a foreground='blue')
42n/a
43n/a # Generate pegs
44n/a pegwidth = 10
45n/a pegheight = height//2
46n/a pegdist = width//3
47n/a x1, y1 = (pegdist-pegwidth)//2, height*1//3
48n/a x2, y2 = x1+pegwidth, y1+pegheight
49n/a self.pegs = []
50n/a p = c.create_rectangle(x1, y1, x2, y2, fill='black')
51n/a self.pegs.append(p)
52n/a x1, x2 = x1+pegdist, x2+pegdist
53n/a p = c.create_rectangle(x1, y1, x2, y2, fill='black')
54n/a self.pegs.append(p)
55n/a x1, x2 = x1+pegdist, x2+pegdist
56n/a p = c.create_rectangle(x1, y1, x2, y2, fill='black')
57n/a self.pegs.append(p)
58n/a self.tk.update()
59n/a
60n/a # Generate pieces
61n/a pieceheight = pegheight//16
62n/a maxpiecewidth = pegdist*2//3
63n/a minpiecewidth = 2*pegwidth
64n/a self.pegstate = [[], [], []]
65n/a self.pieces = {}
66n/a x1, y1 = (pegdist-maxpiecewidth)//2, y2-pieceheight-2
67n/a x2, y2 = x1+maxpiecewidth, y1+pieceheight
68n/a dx = (maxpiecewidth-minpiecewidth) // (2*max(1, n-1))
69n/a for i in range(n, 0, -1):
70n/a p = c.create_rectangle(x1, y1, x2, y2, fill='red')
71n/a self.pieces[i] = p
72n/a self.pegstate[0].append(i)
73n/a x1, x2 = x1 + dx, x2-dx
74n/a y1, y2 = y1 - pieceheight-2, y2-pieceheight-2
75n/a self.tk.update()
76n/a self.tk.after(25)
77n/a
78n/a # Run -- never returns
79n/a def run(self):
80n/a while 1:
81n/a hanoi(self.n, 0, 1, 2, self.report)
82n/a hanoi(self.n, 1, 2, 0, self.report)
83n/a hanoi(self.n, 2, 0, 1, self.report)
84n/a hanoi(self.n, 0, 2, 1, self.report)
85n/a hanoi(self.n, 2, 1, 0, self.report)
86n/a hanoi(self.n, 1, 0, 2, self.report)
87n/a
88n/a # Reporting callback for the actual hanoi function
89n/a def report(self, i, a, b):
90n/a if self.pegstate[a][-1] != i: raise RuntimeError # Assertion
91n/a del self.pegstate[a][-1]
92n/a p = self.pieces[i]
93n/a c = self.canvas
94n/a
95n/a # Lift the piece above peg a
96n/a ax1, ay1, ax2, ay2 = c.bbox(self.pegs[a])
97n/a while 1:
98n/a x1, y1, x2, y2 = c.bbox(p)
99n/a if y2 < ay1: break
100n/a c.move(p, 0, -1)
101n/a self.tk.update()
102n/a
103n/a # Move it towards peg b
104n/a bx1, by1, bx2, by2 = c.bbox(self.pegs[b])
105n/a newcenter = (bx1+bx2)//2
106n/a while 1:
107n/a x1, y1, x2, y2 = c.bbox(p)
108n/a center = (x1+x2)//2
109n/a if center == newcenter: break
110n/a if center > newcenter: c.move(p, -1, 0)
111n/a else: c.move(p, 1, 0)
112n/a self.tk.update()
113n/a
114n/a # Move it down on top of the previous piece
115n/a pieceheight = y2-y1
116n/a newbottom = by2 - pieceheight*len(self.pegstate[b]) - 2
117n/a while 1:
118n/a x1, y1, x2, y2 = c.bbox(p)
119n/a if y2 >= newbottom: break
120n/a c.move(p, 0, 1)
121n/a self.tk.update()
122n/a
123n/a # Update peg state
124n/a self.pegstate[b].append(i)
125n/a
126n/a
127n/adef main():
128n/a import sys
129n/a
130n/a # First argument is number of pegs, default 4
131n/a if sys.argv[1:]:
132n/a n = int(sys.argv[1])
133n/a else:
134n/a n = 4
135n/a
136n/a # Second argument is bitmap file, default none
137n/a if sys.argv[2:]:
138n/a bitmap = sys.argv[2]
139n/a # Reverse meaning of leading '@' compared to Tk
140n/a if bitmap[0] == '@': bitmap = bitmap[1:]
141n/a else: bitmap = '@' + bitmap
142n/a else:
143n/a bitmap = None
144n/a
145n/a # Create the graphical objects...
146n/a h = Tkhanoi(n, bitmap)
147n/a
148n/a # ...and run!
149n/a h.run()
150n/a
151n/a
152n/a# Call main when run as script
153n/aif __name__ == '__main__':
154n/a main()