一、实现效果
视频演示
二、完整代码(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`)作为辅助。