Use Python to implement visual animation of the Tower of Hanoi:

1. Realization effect

Video demonstration

2. Complete code (Github)

After searching for a long time on Github, I found the source code of the topic.

from tkinter import *
from turtle import TurtleScreen, RawTurtle


class Disc(RawTurtle):
    """Hanoi disc, a RawTurtle object on a TurtleScreen."""

    def __init__(self, cv):
        RawTurtle.__init__(self, cv, shape="square", visible=False)
        self.pu()
        self.goto(-140, 200)

    def config(self, k, n):
        self.hideturtle()
        f = float(k + 1) / n
        self.shapesize(0.5, 1.5 + 5 * f)  # square-->rectangle
        self.fillcolor(f, 0, 1 - f)
        self.showturtle()


class Tower(list):
    "Hanoi tower, a subclass of built-in type list"

    def __init__(self, x):
        "create an empty tower. x is x-position of peg"
        super().__init__()
        self.x = x

    def push(self, d):
        d.setx(self.x)
        d.sety(-70 + 10 * len(self))
        self.append(d)

    def pop(self, y=90):
        d = list.pop(self)
        d.sety(y)
        return d


class HanoiEngine:
    """Play the Hanoi-game on a given TurtleScreen."""

    def __init__(self, canvas, nrOfDiscs, speed, moveCntDisplay=None):
        # 设置一个画布控制盘及其速度
        self.ts = canvas
        self.ts.tracer(False)  # tracer()回调函数
        # setup scene
        self.designer = RawTurtle(canvas, shape="square")
        self.designer.penup()
        self.designer.shapesize(0.5, 21)
        self.designer.goto(0, -80)
        self.designer.stamp()
        self.designer.shapesize(7, 0.5)
        self.designer.fillcolor('darkgreen')
        for x in -140, 0, 140:
            self.designer.goto(x, -5)
            self.designer.stamp()

        self.nrOfDiscs = nrOfDiscs
        self.speed = speed  # 为简便定义一些常用的变量
        self.moveDisplay = moveCntDisplay
        self.running = False
        self.moveCnt = 0
        self.discs = [Disc(canvas) for i in range(10)]  # 设计盘子的上下限制
        self.towerA = Tower(-140)  # 设计三个塔的位置
        self.towerB = Tower(0)
        self.towerC = Tower(140)
        self.ts.tracer(True)

    def setspeed(self):
        for disc in self.discs:
            disc.speed(self.speed)

    def hanoi(self, n, src, dest, temp):
        # 用递归实现汉诺塔
        if n > 0:
            for x in self.hanoi(n - 1, src, temp, dest):
                yield None
            yield self.move(src, dest)
            for x in self.hanoi(n - 1, temp, dest, src):
                yield None

    def move(self, src_tower, dest_tower):
        # 移动最上面的盘
        dest_tower.push(src_tower.pop())
        self.moveCnt += 1
        self.moveDisplay(self.moveCnt)

    def reset(self):
        """Setup of (a new) game."""
        self.ts.tracer(False)
        self.moveCnt = 0
        self.moveDisplay(0)
        for t in self.towerA, self.towerB, self.towerC:
            while t:
                t.pop(200)
        for k in range(self.nrOfDiscs - 1, -1, -1):
            self.discs[k].config(k, self.nrOfDiscs)
            self.towerA.push(self.discs[k])
        self.ts.tracer(True)
        self.HG = self.hanoi(self.nrOfDiscs,
                             self.towerA, self.towerC, self.towerB)

    def run(self):
        """run game ;-)
        return True if game is over, else False"""
        global result
        self.running = True
        try:
            while self.running:
                result = self.step()
            return result  # True iff done
        except StopIteration:  # game over
            return True

    def step(self):
        """perform one single step of the game,
        returns True if finished, else False"""
        try:
            next(self.HG)
            return 2 ** self.nrOfDiscs - 1 == self.moveCnt
        except TclError:
            return False

    def stop(self):
        """ ;-) """
        self.running = False


class Hanoi:
    """GUI for animated towers-of-Hanoi-game with upto 10 discs:"""

    def displayMove(self, move):
        """method to be passed to the Hanoi-engine as a callback
        to report move-count"""
        self.moveCntLbl.configure(text="move:\n%d" % move)

    def adjust_nr_of_discs(self, e):
        """callback function for nr-of-discs-scale-widget"""
        self.hEngine.nrOfDiscs = self.discs.get()
        self.reset()  # 重置已编辑的字符串

    def adjust_speed(self, e):
        """callback function for speeds-scale-widget"""
        self.hEngine.speed = self.tempo.get() % 10
        self.hEngine.setspeed()

    def setState(self, STATE):
        """most simple implementation of a finite state machine"""
        self.state = STATE
        try:  # 捕获异常信息
            if STATE == "START":
                self.discs.configure(state=NORMAL)
                self.discs.configure(fg="black")
                self.discsLbl.configure(fg="black")
                self.resetBtn.configure(state=DISABLED)
                self.startBtn.configure(text="start", state=NORMAL)
                self.stepBtn.configure(state=NORMAL)
            elif STATE == "RUNNING":
                self.discs.configure(state=DISABLED)
                self.discs.configure(fg="gray70")
                self.discsLbl.configure(fg="gray70")
                self.resetBtn.configure(state=DISABLED)
                self.startBtn.configure(text="pause", state=NORMAL)
                self.stepBtn.configure(state=DISABLED)
            elif STATE == "PAUSE":
                self.discs.configure(state=NORMAL)
                self.discs.configure(fg="black")
                self.discsLbl.configure(fg="black")
                self.resetBtn.configure(state=NORMAL)
                self.startBtn.configure(text="resume", state=NORMAL)
                self.stepBtn.configure(state=NORMAL)
            elif STATE == "DONE":
                self.discs.configure(state=NORMAL)
                self.discs.configure(fg="black")
                self.discsLbl.configure(fg="black")
                self.resetBtn.configure(state=NORMAL)
                self.startBtn.configure(text="start", state=DISABLED)
                self.stepBtn.configure(state=DISABLED)
            elif STATE == "TIMEOUT":
                self.discs.configure(state=DISABLED)
                self.discs.configure(fg="gray70")
                self.discsLbl.configure(fg="gray70")
                self.resetBtn.configure(state=DISABLED)
                self.startBtn.configure(state=DISABLED)
                self.stepBtn.configure(state=DISABLED)
        except TclError:
            pass

    def reset(self):
        """restore state "START" for a new game"""
        self.hEngine.reset()
        self.setState("START")

    def start(self):
        """callback function for start button, which also serves as
        pause button. Makes hEngine running until done or interrupted"""
        if self.state in ["START", "PAUSE"]:
            self.setState("RUNNING")
            if self.hEngine.run():
                self.setState("DONE")
            else:
                self.setState("PAUSE")
        elif self.state == "RUNNING":
            self.setState("TIMEOUT")
            self.hEngine.stop()

    def step(self):
        """callback function for step button.
        makes hEngine perform a single step"""
        self.setState("TIMEOUT")
        if self.hEngine.step():
            self.setState("DONE")
        else:
            self.setState("PAUSE")

    def __init__(self, nrOfDiscs, speed):
        """construct Hanoi-engine, build GUI and set STATE to "START"
        then launch mainloop()"""
        root = Tk()
        root.title("TOWERS OF HANOI")
        cv = Canvas(root, width=440, height=210, bg="gray90")
        cv.pack()
        cv = TurtleScreen(cv)
        self.hEngine = HanoiEngine(cv, nrOfDiscs, speed, self.displayMove)
        fnt = ("Arial", 12, "bold")
        # set attributes: nr of discs, speed; display move count
        attrFrame = Frame(root)  # contains scales to adjust game's attributes
        self.discsLbl = Label(attrFrame, width=7, height=2, font=fnt,
                              text="盘数:\n")
        self.discs = Scale(attrFrame, from_=1, to_=10, orient=HORIZONTAL,
                           font=fnt, length=75, showvalue=1, repeatinterval=10,
                           command=self.adjust_nr_of_discs)
        self.discs.set(nrOfDiscs)
        self.tempoLbl = Label(attrFrame, width=8, height=2, font=fnt,
                              text="速度:\n")
        self.tempo = Scale(attrFrame, from_=1, to_=10, orient=HORIZONTAL,
                           font=fnt, length=100, showvalue=1, repeatinterval=10,
                           command=self.adjust_speed)
        self.tempo.set(speed)
        self.moveCntLbl = Label(attrFrame, width=5, height=2, font=fnt,
                                padx=20, text="移动:\n", anchor=CENTER)
        for widget in (self.discsLbl, self.discs, self.tempoLbl, self.tempo,
                       self.moveCntLbl):
            widget.pack(side=LEFT)
        attrFrame.pack(side=TOP)
        # control buttons: reset, step, start/pause/resume
        ctrlFrame = Frame(root)  # contains Buttons to control the game
        self.resetBtn = Button(ctrlFrame, width=11, text="重置", font=fnt,
                               state=DISABLED, padx=15, command=self.reset)
        self.stepBtn = Button(ctrlFrame, width=11, text="单步", font=fnt,
                              state=NORMAL, padx=15, command=self.step)
        self.startBtn = Button(ctrlFrame, width=11, text="开始", font=fnt,
                               state=NORMAL, padx=15, command=self.start)
        for widget in self.resetBtn, self.stepBtn, self.startBtn:
            widget.pack(side=LEFT)
        ctrlFrame.pack(side=TOP)

        self.state = "START"
        root.mainloop()


if __name__ == "__main__":
    Hanoi(7, 3)

1. Import the required Tkinter library and Turtle library, and define a class named `Disc`, as well as the `Tower` and `HanoiEngine` classes.

2. The `Disc` class is a subclass of the `RawTurtle` object and is used to represent the plates in the Tower of Hanoi game. Its constructor `__init__` initializes the properties of the plate, including shape, position and color.

3. The `Tower` class is a subclass of the `list` built-in type and represents the tower in the Tower of Hanoi game. Its constructor `__init__` initializes the tower's properties and contains `push` and `pop` methods for adding and removing plates from the tower.

4. The `HanoiEngine` class is the engine used to execute the Tower of Hanoi game logic. Its constructor `__init__` initializes the game's properties and state, and contains `hanoi`, `move`, `reset`, `run`, `step` and `stop` methods to perform different operations of the game.

5. The `Hanoi` class is the graphical interface of the game, which inherits the `Tk` class of `Tkinter`. It contains user interface elements such as sliders, buttons, etc., as well as methods for interacting with game logic.

6. In the `__main__` block, create an instance of the `Hanoi` class, start the Tower of Hanoi game, and set the initial number of plates and speed.

The function of the entire code is to display a Tower of Hanoi game with adjustable number of plates and speed in a graphical interface. Users can start, pause, step through, and reset the game with buttons. The plates in the game are distinguished by different colors and sizes, and the number of moves is updated with each move. Users can adjust the number of plates and speed as needed and watch the Tower of Hanoi being solved.

3. Complete code (written by myself, there are still many bugs)

from tkinter import *

# 定义一些常用变量
fnt = ("Arial", 12, "bold")


class Start:
    def __init__(self):
        # 设置三个列表代表三个塔
        self.A_tp_list = []
        self.B_tp_list = []
        self.C_tp_list = []
        self.flag = 0
        self.count_num = 0  # 计算移动步数
        self.con = 0  # 判断是单步还是连续
        self.key_list = []

        # 创建窗口
        self.win = Tk()
        self.win.title("Tower_of_Hanoi")
        win_x = self.win.winfo_screenwidth() / 2 - 400
        win_y = self.win.winfo_screenheight() / 2 - 300
        self.win.geometry(f'800x550+{int(win_x)}+{int(win_y)}')
        self.canvas = Canvas(self.win, width=700, height=350, bg="white")
        self.canvas.place(relx=0.5, rely=0.35, anchor=CENTER)
        # 底盘
        self.canvas.create_rectangle(10, 310, 690, 330, fill="black")
        # 杆
        for i in range(3):
            self.canvas.create_rectangle(105 + i * 240, 80, 115 + i * 240, 310, fill="green")
        l1 = Label(self.win, text="盘数:", font=fnt)
        l2 = Label(self.win, text="速度:", font=fnt)
        l3 = Label(self.win, text="步数:0", font=fnt)
        l1.place(relx=0.2, rely=0.7, anchor=CENTER)
        l2.place(relx=0.57, rely=0.7, anchor=CENTER)
        l3.place(relx=0.87, rely=0.7, anchor=CENTER)
        self.P_num = StringVar()
        self.speed = StringVar()
        e1 = Entry(self.win, width=5, font=fnt, textvariable=self.P_num)
        e2 = Entry(self.win, width=5, font=fnt, textvariable=self.speed)
        e1.place(relx=0.37, rely=0.705, anchor=CENTER)
        e2.place(relx=0.742, rely=0.705, anchor=CENTER)

        self.resetBtn = Button(self.win, width=11, text="放盘子", font=fnt,
                               state=NORMAL, padx=15, command=self.prepare)
        self.resetBtn.place(relx=0.2, rely=0.8, anchor=CENTER)
        self.stepBtn = Button(self.win, width=11, text="单步", font=fnt,
                              state=NORMAL, padx=15, command=self.step)
        self.stepBtn.place(relx=0.4, rely=0.8, anchor=CENTER)
        self.startBtn = Button(self.win, width=11, text="连续", font=fnt,
                               state=NORMAL, padx=15, command=self.start)
        self.startBtn.place(relx=0.6, rely=0.8, anchor=CENTER)
        self.prepareBtn = Button(self.win, width=11, text="重置", font=fnt,
                                 state=NORMAL, padx=15, command=self.reset)
        self.prepareBtn.place(relx=0.8, rely=0.8, anchor=CENTER)
        self.win.mainloop()

    def prepare(self):
        # 制造盘子
        if 0 < int(self.P_num.get()) < 10:
            color = ['red', 'yellow', 'cyan', 'pink', "#DDA0DD", "#35b1c0", "#5835c0", "#FFC0CB", "#EE82EE"]
            for i in range(int(self.P_num.get())):
                plates = self.canvas.create_rectangle(20 + i * 12, 280 - i * 30, 200 - i * 12, 310 - i * 30,
                                                      fill=color[i])
                self.A_tp_list.append(plates)
            # 更新列表中汉诺塔的数据
            self.get_key(int(self.P_num.get()), "a", "b", "c")

    def step(self):
        key = self.key_list[self.count_num]
        if key == "a b":
            self.A_B()
        elif key == "a c":
            self.A_C()
        elif key == "b a":
            self.B_A()
        elif key == "b c":
            self.B_C()
        elif key == "c a":
            self.C_A()
        elif key == "c b":
            self.C_B()

    def start(self):
        self.con = 1
        key = self.key_list[self.count_num]
        if key == "a b":
            self.A_B()
        elif key == "a c":
            self.A_C()
        elif key == "b a":
            self.B_A()
        elif key == "b c":
            self.B_C()
        elif key == "c a":
            self.C_A()
        elif key == "c b":
            self.C_B()

    def A_B(self):
        POS = self.canvas.coords(self.A_tp_list[len(self.A_tp_list) - 1])
        if POS[3] > 60 and self.flag == 0:
            self.canvas.move(self.A_tp_list[len(self.A_tp_list) - 1], 0, -1)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.A_B)
        elif (POS[0] + POS[2]) / 2 < 350 and self.flag == 0:
            self.canvas.move(self.A_tp_list[len(self.A_tp_list) - 1], 1, 0)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.A_B)
        else:
            self.flag = 1
            if len(self.B_tp_list) == 0:
                if POS[3] < 310:
                    self.canvas.move(self.A_tp_list[len(self.A_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.A_B)
                else:
                    self.B_tp_list.append(self.A_tp_list[len(self.A_tp_list) - 1])
                    self.A_tp_list.pop(len(self.A_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()
            else:
                if POS[3] < 310 - len(self.B_tp_list) * 30:
                    self.canvas.move(self.A_tp_list[len(self.A_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.A_B)
                else:
                    self.B_tp_list.append(self.A_tp_list[len(self.A_tp_list) - 1])
                    self.A_tp_list.pop(len(self.A_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()

    def A_C(self):
        POS = self.canvas.coords(self.A_tp_list[len(self.A_tp_list) - 1])
        if POS[3] > 60 and self.flag == 0:
            self.canvas.move(self.A_tp_list[len(self.A_tp_list) - 1], 0, -1)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.A_C)
        elif (POS[0] + POS[2]) / 2 < 590 and self.flag == 0:
            self.canvas.move(self.A_tp_list[len(self.A_tp_list) - 1], 1, 0)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.A_C)
        else:
            self.flag = 1
            if len(self.C_tp_list) == 0:
                if POS[3] < 310:
                    self.canvas.move(self.A_tp_list[len(self.A_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.A_C)
                else:
                    self.C_tp_list.append(self.A_tp_list[len(self.A_tp_list) - 1])
                    self.A_tp_list.pop(len(self.A_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()
            else:
                if POS[3] < 310 - len(self.C_tp_list) * 30:
                    self.canvas.move(self.A_tp_list[len(self.B_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.A_C)
                else:
                    self.C_tp_list.append(self.A_tp_list[len(self.A_tp_list) - 1])
                    self.A_tp_list.pop(len(self.A_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()

    def B_A(self):
        POS = self.canvas.coords(self.B_tp_list[len(self.B_tp_list) - 1])
        if POS[3] > 60 and self.flag == 0:
            self.canvas.move(self.B_tp_list[len(self.B_tp_list) - 1], 0, -1)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.B_A)
        elif (POS[0] + POS[2]) / 2 > 110 and self.flag == 0:
            self.canvas.move(self.B_tp_list[len(self.B_tp_list) - 1], -1, 0)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.B_A)
        else:
            self.flag = 1
            if len(self.A_tp_list) == 0:
                if POS[3] < 310:
                    self.canvas.move(self.B_tp_list[len(self.B_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.B_A)
                else:
                    self.A_tp_list.append(self.B_tp_list[len(self.B_tp_list) - 1])
                    self.B_tp_list.pop(len(self.B_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()
            else:
                if POS[3] < 310 - len(self.A_tp_list) * 30:
                    self.canvas.move(self.B_tp_list[len(self.B_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.B_A)
                else:
                    self.A_tp_list.append(self.B_tp_list[len(self.B_tp_list) - 1])
                    self.B_tp_list.pop(len(self.B_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()

    def B_C(self):
        POS = self.canvas.coords(self.B_tp_list[len(self.B_tp_list) - 1])
        if POS[3] > 61 and self.flag == 0:
            self.canvas.move(self.B_tp_list[len(self.B_tp_list) - 1], 0, -1)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.B_C)
        elif (POS[0] + POS[2]) / 2 < 590 and self.flag == 0:
            self.canvas.move(self.B_tp_list[len(self.B_tp_list) - 1], 1, 0)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.B_C)
        else:
            self.flag = 1
            if len(self.C_tp_list) == 0:
                if POS[3] < 310:
                    self.canvas.move(self.B_tp_list[len(self.B_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.B_C)
                else:
                    self.C_tp_list.append(self.B_tp_list[len(self.B_tp_list) - 1])
                    self.B_tp_list.pop(len(self.B_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()
            else:
                if POS[3] < 310 - len(self.C_tp_list) * 30:
                    self.canvas.move(self.B_tp_list[len(self.B_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.B_C)
                else:
                    self.C_tp_list.append(self.B_tp_list[len(self.B_tp_list) - 1])
                    self.B_tp_list.pop(len(self.B_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()

    def C_A(self):
        POS = self.canvas.coords(self.C_tp_list[len(self.C_tp_list) - 1])
        if POS[3] > 60 and self.flag == 0:
            self.canvas.move(self.C_tp_list[len(self.C_tp_list) - 1], 0, -1)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.C_A)
        elif (POS[0] + POS[2]) / 2 > 110 and self.flag == 0:
            self.canvas.move(self.C_tp_list[len(self.C_tp_list) - 1], -1, 0)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.C_A)
        else:
            self.flag = 1
            if len(self.A_tp_list) == 0:
                if POS[3] < 310:
                    self.canvas.move(self.C_tp_list[len(self.C_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.C_A)
                else:
                    self.A_tp_list.append(self.C_tp_list[len(self.C_tp_list) - 1])
                    self.C_tp_list.pop(len(self.C_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()
            else:
                if POS[3] < 310 - len(self.A_tp_list) * 30:
                    self.canvas.move(self.C_tp_list[len(self.C_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.C_A)
                else:
                    self.A_tp_list.append(self.C_tp_list[len(self.C_tp_list) - 1])
                    self.C_tp_list.pop(len(self.C_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()

    def C_B(self):
        POS = self.canvas.coords(self.C_tp_list[len(self.C_tp_list) - 1])
        if POS[3] > 60 and self.flag == 0:
            self.canvas.move(self.C_tp_list[len(self.C_tp_list) - 1], 0, -1)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.C_B)
        elif (POS[0] + POS[2]) / 2 > 350 and self.flag == 0:
            self.canvas.move(self.C_tp_list[len(self.C_tp_list) - 1], -1, 0)
            self.canvas.after(16 - int(self.speed.get()) * 3, self.C_B)
        else:
            self.flag = 1
            if len(self.B_tp_list) == 0:
                if POS[3] < 310:
                    self.canvas.move(self.C_tp_list[len(self.C_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.C_B)
                else:
                    self.B_tp_list.append(self.C_tp_list[len(self.C_tp_list) - 1])
                    self.C_tp_list.pop(len(self.C_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()
            else:
                if POS[3] < 310 - len(self.B_tp_list) * 30:
                    self.canvas.move(self.C_tp_list[len(self.C_tp_list) - 1], 0, 1)
                    self.canvas.after(16 - int(self.speed.get()) * 3, self.C_B)
                else:
                    self.B_tp_list.append(self.C_tp_list[len(self.B_tp_list) - 1])
                    self.C_tp_list.pop(len(self.C_tp_list) - 1)
                    self.flag = 0
                    self.count_num += 1
                    l3 = Label(self.win, text=f"步数:{self.count_num}", font=fnt)
                    l3.place(relx=0.87, rely=0.7, anchor=CENTER)
                    if self.con == 1:
                        self.start()

    def reset(self):
        self.P_num.set("")
        self.speed.set("")
        l3 = Label(self.win, text="步数:0", font=fnt)
        l3.place(relx=0.87, rely=0.7, anchor=CENTER)
        for key in self.A_tp_list:
            self.canvas.delete(key)
        for key in self.B_tp_list:
            self.canvas.delete(key)
        for key in self.C_tp_list:
            self.canvas.delete(key)

    def get_key(self, n, a, b, c):
        if n == 1:
            self.key_list.append(f"{a} {c}")
            return
        self.get_key(n - 1, a, c, b)
        self.get_key(1, a, b, c)
        self.get_key(n - 1, b, a, c)


if __name__ == '__main__':
    Start()

Let's break down the code and what it does:

1. The code imports the Tkinter library and creates a class named `Start`.
2. Inside the `Start` class, there are several instance variables, including three lists (`A_tp_list`, `B_tp_list` and `C_tp_list`), which represent three towers respectively, and a `flag` variable, `count_num ` is used to calculate the number of moving steps, `con` is used to determine whether it is single-step mode or continuous mode, and `key_list` is used to store the moving sequence.
3. The `__init__` method initializes the Tkinter window, sets graphic elements, and handles user interface interaction (buttons and input fields).
4. The `prepare` method creates a corresponding number of plates (rectangles) on the first tower (`A`) based on the number of plates provided by the user. The plates are given different colors and added to the `A_tp_list` list. This method also generates and stores the move sequence in `key_list`.
5. The `step` method executes a step of the Tower of Hanoi game based on the sequence of moves stored in `key_list`.
6. The `start` method continuously executes the Tower of Hanoi game according to the movement sequence.
7. There are six helper methods (`A_B`, `A_C`, `B_A`, `B_C`, `C_A` and `C_B`) for moving plates between towers according to the rules of the Tower of Hanoi.
8. The `reset` method resets the game by clearing the plate and resetting the number of moves.
9. The `get_key` method is a recursive function that uses a standard recursive algorithm to generate the movement sequence of the Tower of Hanoi problem.

When you run the code, a graphics window pops up with three towers and input fields for the number of plates and animation speed. You can move the plates by clicking on the "Place Plate", "Single Step" and "Continuous" buttons. The "Reset" button will clear the plate and reset the step count. The program will animate the movement of the plates based on the number and speed of plates you provide. The goal is to move all the plates from the first tower (`A`) to the third tower (`C`), using the second tower (`B`) as a support.

Guess you like

Origin blog.csdn.net/weixin_64890968/article/details/131873362