home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyos2bin.zip / Demo / tkinter / guido / hanoi.py < prev    next >
Text File  |  1997-08-22  |  4KB  |  155 lines

  1. # Animated Towers of Hanoi using Tk with optional bitmap file in
  2. # background.
  3. #
  4. # Usage: tkhanoi [n [bitmapfile]]
  5. #
  6. # n is the number of pieces to animate; default is 4, maximum 15.
  7. #
  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.
  11.  
  12. # This uses Steen Lumholt's Tk interface
  13. from Tkinter import *
  14.  
  15.  
  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):
  19.     if n <= 0: return
  20.     hanoi(n-1, a, c, b, report)
  21.     report(n, a, b)
  22.     hanoi(n-1, c, b, a, report)
  23.  
  24.  
  25. # The graphical interface
  26. class Tkhanoi:
  27.  
  28.     # Create our objects
  29.     def __init__(self, n, bitmap = None):
  30.         self.n = n
  31.         self.tk = tk = Tk()
  32.         self.canvas = c = Canvas(tk)
  33.         c.pack()
  34.         width, height = tk.getint(c['width']), tk.getint(c['height'])
  35.  
  36.         # Add background bitmap
  37.         if bitmap:
  38.             self.bitmap = c.create_bitmap(width/2, height/2,
  39.                               bitmap=bitmap,
  40.                               foreground='blue')
  41.  
  42.         # Generate pegs
  43.         pegwidth = 10
  44.         pegheight = height/2
  45.         pegdist = width/3
  46.         x1, y1 = (pegdist-pegwidth)/2, height*1/3
  47.         x2, y2 = x1+pegwidth, y1+pegheight
  48.         self.pegs = []
  49.         p = c.create_rectangle(x1, y1, x2, y2, fill='black')
  50.         self.pegs.append(p)
  51.         x1, x2 = x1+pegdist, x2+pegdist
  52.         p = c.create_rectangle(x1, y1, x2, y2, fill='black')
  53.         self.pegs.append(p)
  54.         x1, x2 = x1+pegdist, x2+pegdist
  55.         p = c.create_rectangle(x1, y1, x2, y2, fill='black')
  56.         self.pegs.append(p)
  57.         self.tk.update()
  58.  
  59.         # Generate pieces
  60.         pieceheight = pegheight/16
  61.         maxpiecewidth = pegdist*2/3
  62.         minpiecewidth = 2*pegwidth
  63.         self.pegstate = [[], [], []]
  64.         self.pieces = {}
  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')
  70.             self.pieces[i] = p
  71.             self.pegstate[0].append(i)
  72.             x1, x2 = x1 + dx, x2-dx
  73.             y1, y2 = y1 - pieceheight-2, y2-pieceheight-2
  74.             self.tk.update()
  75.             self.tk.after(25)
  76.  
  77.     # Run -- never returns
  78.     def run(self):
  79.         while 1:
  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)
  86.  
  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]
  91.         p = self.pieces[i]
  92.         c = self.canvas
  93.  
  94.         # Lift the piece above peg a
  95.         ax1, ay1, ax2, ay2 = c.bbox(self.pegs[a])
  96.         while 1:
  97.             x1, y1, x2, y2 = c.bbox(p)
  98.             if y2 < ay1: break
  99.             c.move(p, 0, -1)
  100.             self.tk.update()
  101.  
  102.         # Move it towards peg b
  103.         bx1, by1, bx2, by2 = c.bbox(self.pegs[b])
  104.         newcenter = (bx1+bx2)/2
  105.         while 1:
  106.             x1, y1, x2, y2 = c.bbox(p)
  107.             center = (x1+x2)/2
  108.             if center == newcenter: break
  109.             if center > newcenter: c.move(p, -1, 0)
  110.             else: c.move(p, 1, 0)
  111.             self.tk.update()
  112.  
  113.         # Move it down on top of the previous piece
  114.         pieceheight = y2-y1
  115.         newbottom = by2 - pieceheight*len(self.pegstate[b]) - 2
  116.         while 1:
  117.             x1, y1, x2, y2 = c.bbox(p)
  118.             if y2 >= newbottom: break
  119.             c.move(p, 0, 1)
  120.             self.tk.update()
  121.  
  122.         # Update peg state
  123.         self.pegstate[b].append(i)
  124.  
  125.  
  126. # Main program
  127. def main():
  128.     import sys, string
  129.  
  130.     # First argument is number of pegs, default 4
  131.     if sys.argv[1:]:
  132.         n = string.atoi(sys.argv[1])
  133.     else:
  134.         n = 4
  135.  
  136.     # Second argument is bitmap file, default none
  137.     if sys.argv[2:]:
  138.         bitmap = sys.argv[2]
  139.         # Reverse meaning of leading '@' compared to Tk
  140.         if bitmap[0] == '@': bitmap = bitmap[1:]
  141.         else: bitmap = '@' + bitmap
  142.     else:
  143.         bitmap = None
  144.  
  145.     # Create the graphical objects...
  146.     h = Tkhanoi(n, bitmap)
  147.  
  148.     # ...and run!
  149.     h.run()
  150.  
  151.  
  152. # Call main when run as script
  153. if __name__ == '__main__':
  154.     main()
  155.