用Python实现可视化汉诺塔动画:

目录

一、实现效果

二、完整代码(Github)

三、完整代码(自己写的,还有很多Bug)


一、实现效果

视频演示

二、完整代码(Github)

在Github上找了很久,找到了题目的源码。

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. 导入所需的Tkinter库和Turtle库,并定义了一个名为`Disc`的类,以及`Tower`和`HanoiEngine`类。

2. `Disc`类是`RawTurtle`对象的子类,用于表示汉诺塔游戏中的盘子。它的构造函数`__init__`初始化盘子的属性,包括形状、位置和颜色等。

3. `Tower`类是`list`内置类型的子类,表示汉诺塔游戏中的塔。它的构造函数`__init__`初始化塔的属性,并包含`push`和`pop`方法用于在塔上添加和移除盘子。

4. `HanoiEngine`类是用于执行汉诺塔游戏逻辑的引擎。它的构造函数`__init__`初始化游戏的属性和状态,并包含`hanoi`、`move`、`reset`、`run`、`step`和`stop`方法来执行游戏的不同操作。

5. `Hanoi`类是游戏的图形界面,它继承了`Tkinter`的`Tk`类。它包含了用户界面元素,如滑动条、按钮等,以及与游戏逻辑交互的方法。

6. 在`__main__`块中,创建了一个`Hanoi`类的实例,启动了汉诺塔游戏,并设置了初始的盘子数量和速度。

整个代码的功能是在图形界面中展示一个具有可调节盘子数量和速度的汉诺塔游戏。用户可以通过按钮来开始、暂停、单步执行和重置游戏。游戏中的盘子通过不同颜色和大小进行区分,每次移动都会更新移动步数。用户可以根据需要调整盘子数量和速度,观察汉诺塔的解决过程。

三、完整代码(自己写的,还有很多Bug)

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()

让我们分解代码及其功能:

1. 代码导入Tkinter库,并创建一个名为`Start`的类。
2. 在`Start`类内部,有几个实例变量,包括三个列表(`A_tp_list`、`B_tp_list`和`C_tp_list`),它们分别表示三个塔,还有一个`flag`变量、`count_num`用于计算移动步数、`con`用于确定是单步模式还是连续模式,以及`key_list`用于存储移动序列。
3. `__init__`方法初始化Tkinter窗口,设置图形元素,并处理用户界面交互(按钮和输入字段)。
4. `prepare`方法根据用户提供的盘子数量,在第一个塔(`A`)上创建相应数量的盘子(矩形)。盘子有不同的颜色,并添加到`A_tp_list`列表中。该方法还生成并存储移动序列在`key_list`中。
5. `step`方法根据存储在`key_list`中的移动序列执行汉诺塔游戏的一个步骤。
6. `start`方法根据移动序列连续执行汉诺塔游戏。
7. 有六个辅助方法(`A_B`、`A_C`、`B_A`、`B_C`、`C_A`和`C_B`),用于根据汉诺塔的规则在塔之间移动盘子。
8. `reset`方法通过清除盘子和重置步数来重新设置游戏。
9. `get_key`方法是一个递归函数,使用标准递归算法生成汉诺塔问题的移动序列。

运行代码时,会弹出一个图形窗口,其中有三个塔和输入字段用于输入盘子数量和动画速度。您可以通过点击"放盘子"、"单步"和"连续"按钮来移动盘子。"重置"按钮将清除盘子并重置步数。程序将根据您提供的盘子数量和速度来显示盘子移动的动画。目标是将所有盘子从第一个塔(`A`)移动到第三个塔(`C`),并使用第二个塔(`B`)作为辅助。

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我来回答你的问题。首先,让我们来了解一下tkinter是什么。Tkinter是Python标准库中的一个图形用户界面(GUI)工具包,它可以用于创建各种窗口、按钮、标签等GUI元素。在这个项目中,我们将使用Tkinter来创建一个文档安全工具。 接下来,我们将使用Pycharm作为Python开发环境来完成这个项目。首先,创建一个新的Python文件,并导入Tkinter模块。然后,我们需要创建一个主窗口,用于容纳所有的GUI元素。代码如下: ```python import tkinter as tk # 创建主窗口 root = tk.Tk() # 设置窗口标题 root.title("文档安全工具") # 设置窗口大小 root.geometry("500x500") # 运行主窗口 root.mainloop() ``` 接下来,我们需要添加一些GUI元素,例如按钮、文本框等。我们将创建一个简单的GUI,用户可以输入一个文档的名称,然后点击一个按钮来加密该文档。代码如下: ```python # 创建标签 label = tk.Label(root, text="请输入文档名称:") label.pack() # 创建文本框 entry = tk.Entry(root) entry.pack() # 创建按钮 button = tk.Button(root, text="加密文档") button.pack() # 运行主窗口 root.mainloop() ``` 现在,我们需要添加一些功能来处理用户输入的文档名称,并加密该文档。我们将使用Python的加密模块来实现文档加密。完整的代码如下: ```python import tkinter as tk import hashlib # 创建主窗口 root = tk.Tk() # 设置窗口标题 root.title("文档安全工具") # 设置窗口大小 root.geometry("500x500") # 处理加密按钮点击事件 def encrypt_file(): # 获取文本框输入的文档名称 filename = entry.get() # 使用SHA256加密算法加密文档 hasher = hashlib.sha256() with open(filename, 'rb') as f: data = f.read() hasher.update(data) encrypted_data = hasher.digest() # 将加密后的文档写入新文件 with open(filename + ".encrypted", 'wb') as f: f.write(encrypted_data) # 显示加密完成的消息框 tk.messagebox.showinfo("加密完成", "文档已成功加密!") # 创建标签 label = tk.Label(root, text="请输入文档名称:") label.pack() # 创建文本框 entry = tk.Entry(root) entry.pack() # 创建按钮 button = tk.Button(root, text="加密文档", command=encrypt_file) button.pack() # 运行主窗口 root.mainloop() ``` 这个程序将读取用户输入的文档名称,使用SHA256加密算法加密该文档,并将加密后的文档写入新文件。然后,它将显示一个消息框,告诉用户加密完成。 希望这个示例能够帮助你完成你的项目!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值