import time
from Tkinter import *

def waitLoop(progress, c):
    x = IntVar()
    c.after(progress * 1000, lambda w: w.set(1), x)
    c.wait_variable(x)

class Towers:
    
    def __init__(self, num = 3, progress = 2, TK = 0, scale=1):
        self.num = num
        self.progress = progress
        self.TK = TK
        self.scale = scale
        self.tow = {}
        self.tow["A"] = [(num - i) for i in range(num)]
        self.tow["B"] = []
        self.tow["C"] = []
        self.errTXT = "No error"
        self.movTXT = "Initial towers (use %d lines terminal)\n" % (
            3 * (2 * num + 1) + 3,)
        if self.TK:
            self.initTK()
            self.rng = [self.mkRing("A", self.num - i, i) for i in range(num)]

    def __call__(self):
        if self.TK:
            self.canvas.after(self.progress * 1000,
                              self.toh, (self.num, "A", "B", "C"))
            self.root.mainloop()
        else:
            self.show()
            self.toh((self.num, "A", "B", "C"))

    def quit(self, e):
        self.canvas.quit()
        self.frame.quit()
        self.root.quit()
        self.root.destroy()

    def initTK(self):
        self.root = Tk()
        self.frame = Frame(self.root)
        self.frame.pack()
        self.canvas = Canvas(self.frame,
                             height = self.num * self.scale,
                             width = 3 * (2 * self.num + 1) * self.scale)
        self.canvas.bind("<Button-1>", self.quit)
        self.canvas.pack()

    def mkRing(self, tower, num, h=None):
        x0 = (ord(tower) - ord("A")) * (2 * self.num + 1) * self.scale + 1
        x0 += (self.num - num + 1) * self.scale
        x1 = x0 + (2 * (num - 1) + 1) * self.scale
        if h == None:
            y0 = (self.num - len(self.tow[tower])) * self.scale - self.scale/2
        else:
            y0 = (self.num - h) * self.scale - self.scale/2
        return self.canvas.create_line(x0, y0, x1, y0, width = self.scale)

    def delRing(self, ring):
        self.canvas.delete(ring)

    def mvRing(self, f, t):
        num = self.tot(f)
        ring = self.rng[self.num - num]
        self.delRing(ring)
        self.rng[self.num - num] = self.mkRing(t, num)

    def tot(self, t):
        return self.tow[t][len(self.tow[t])-1]

    def tail(self, t):
        x = self.tot(t)
        self.tow[t] = self.tow[t][:len(self.tow[t])-1]
        return x

    def valid(self, f, t):
        if self.tow[f]:
            if self.tow[t]:
                if self.tot(f) > self.tot(t):
                    self.errTXT = "Can not move %d on top of %d" % (
                        self.tot(f), self.tot(t))
                    return 0
                return 1
            return 1
        self.errTXT = "Can not move from empty tower " + f
        return 0
    
    def move(self, f, t):
        print "move from", f, "to", t
        if self.valid(f, t):
            self.movTXT = "Move %d from %s to %s\n" % (self.tot(f), f, t)
            if self.TK:
                self.mvRing(f, t)
            self.tow[t].append(self.tail(f))
        else:
            raise ValueError, self.errTXT

    def showASCII(self):
        print self.movTXT
        for i in ["A", "B", "C"]:
            print
            g = ["  "] * (self.num - 1) + [i + " "] + ["  "] * (self.num - 1)
            for j in self.tow[i]:
                for k in range(1, self.num + 1):
                    if j >= k:
                        g[self.num - k] += "** "
            for j in range(self.num) + range(self.num - 2, -1, -1):
                print g[j]
            print
        time.sleep(self.progress)

    def showTK(self):
        waitLoop(self.progress, self.canvas)

    def show(self):
        if self.TK:
            self.showTK()
        else:
            self.showASCII()

    def toh(self, (n, f, t, v)):
        if n == 1:
            self.move(f, t)
            self.show()
        else:
            self.toh((n - 1, f, v, t))
            self.move(f, t)
            self.show()
            self.toh((n - 1, v, t, f))


if __name__ == "__main__":
    
    import sys, string

    n = 3; t = 2; g = 0; s = 1
    try:
        n = string.atoi(sys.argv[1])
        t = string.atoi(sys.argv[2])
        g = string.atoi(sys.argv[3])
        s = string.atoi(sys.argv[4])
    except:
        pass

    towers = Towers(n, t, g, s)
    towers()
