import tkinter as tk
from tkinter import messagebox, ttk
import time
class HanoiTower:
def __init__(self, root):
self.root = root
self.root.title("汉诺塔")
self.root.geometry("800x600")
self.root.resizable(False, False)
# 设置中文字体
self.font = ('SimHei', 12)
# 游戏参数
self.num_disks = 3
self.towers = [[], [], []]
self.selected_tower = None
self.animation_speed = 0.05 # 动画速度
self.is_animating = False
self.moves = 0
# 创建界面
self.create_widgets()
self.reset_game()
def create_widgets(self):
# 顶部控制面板
control_frame = ttk.Frame(self.root)
control_frame.pack(fill=tk.X, padx=10, pady=10)
ttk.Label(control_frame, text="圆盘数量:", font=self.font).pack(side=tk.LEFT, padx=5)
self.disk_var = tk.IntVar(value=self.num_disks)
disk_scale = ttk.Scale(control_frame, from_=3, to=8, orient=tk.HORIZONTAL,
variable=self.disk_var, command=self.on_disk_scale)
disk_scale.pack(side=tk.LEFT, padx=5)
self.disk_label = ttk.Label(control_frame, text=f"{self.num_disks}", font=self.font)
self.disk_label.pack(side=tk.LEFT, padx=5)
ttk.Label(control_frame, text="移动次数:", font=self.font).pack(side=tk.LEFT, padx=20)
self.move_label = ttk.Label(control_frame, text="0", font=self.font)
self.move_label.pack(side=tk.LEFT, padx=5)
ttk.Button(control_frame, text="重置游戏", command=self.reset_game,
style='Accent.TButton').pack(side=tk.RIGHT, padx=5)
ttk.Button(control_frame, text="自动演示", command=self.auto_solve,
style='Accent.TButton').pack(side=tk.RIGHT, padx=5)
# 游戏画布
self.canvas = tk.Canvas(self.root, bg="white", width=800, height=500)
self.canvas.pack(pady=10)
# 绑定点击事件
self.canvas.bind("<Button-1>", self.on_canvas_click)
# 设置主题样式
style = ttk.Style()
style.configure('Accent.TButton', font=self.font)
def on_disk_scale(self, value):
self.num_disks = int(float(value))
self.disk_label.config(text=f"{self.num_disks}")
def reset_game(self):
if self.is_animating:
return
# 初始化塔
self.towers = [[i for i in range(self.num_disks, 0, -1)], [], []]
self.selected_tower = None
self.moves = 0
self.move_label.config(text="0")
self.draw_towers()
def draw_towers(self):
self.canvas.delete("all")
# 绘制底座
base_y = 450
self.canvas.create_rectangle(50, base_y, 750, base_y + 20, fill="brown")
# 绘制三个塔
tower_width = 20
tower_height = 200
tower_spacing = 200
for i in range(3):
tower_x = 200 + i * tower_spacing
self.canvas.create_rectangle(tower_x - tower_width / 2, base_y - tower_height,
tower_x + tower_width / 2, base_y, fill="gray")
# 绘制选中状态
if i == self.selected_tower:
self.canvas.create_oval(tower_x - 40, base_y + 30,
tower_x + 40, base_y + 50, fill="yellow")
# 绘制圆盘
disk_height = 20
max_disk_width = 160
for i in range(3):
tower_x = 200 + i * tower_spacing
for j, disk_size in enumerate(self.towers[i]):
disk_width = disk_size * (max_disk_width / self.num_disks)
disk_y = base_y - (j + 1) * disk_height
self.canvas.create_rectangle(tower_x - disk_width / 2, disk_y,
tower_x + disk_width / 2, disk_y + disk_height,
fill=self.get_disk_color(disk_size))
def get_disk_color(self, disk_size):
colors = ["#FF6B6B", "#FFD166", "#06D6A0", "#118AB2", "#073B4C",
"#EF476F", "#FFD166", "#06D6A0"]
return colors[(disk_size - 1) % len(colors)]
def on_canvas_click(self, event):
if self.is_animating:
return
# 确定点击的塔
tower_x_positions = [200, 400, 600]
tower_spacing = 150
clicked_tower = None
for i, x in enumerate(tower_x_positions):
if x - tower_spacing < event.x < x + tower_spacing:
clicked_tower = i
break
if clicked_tower is not None:
self.process_tower_click(clicked_tower)
def process_tower_click(self, tower_index):
if self.selected_tower is None:
# 如果没有选中的塔,且当前塔有圆盘,则选中它
if self.towers[tower_index]:
self.selected_tower = tower_index
self.draw_towers()
else:
# 如果已经选中了一个塔,尝试移动圆盘
if self.is_valid_move(self.selected_tower, tower_index):
self.move_disk(self.selected_tower, tower_index)
self.moves += 1
self.move_label.config(text=str(self.moves))
# 检查游戏是否完成
if self.check_win():
messagebox.showinfo("恭喜", f"你用了{self.moves}步完成了汉诺塔!")
self.selected_tower = None
self.draw_towers()
def is_valid_move(self, from_tower, to_tower):
if not self.towers[from_tower]:
return False
if not self.towers[to_tower]:
return True
return self.towers[from_tower][-1] < self.towers[to_tower][-1]
def move_disk(self, from_tower, to_tower):
disk = self.towers[from_tower].pop()
self.towers[to_tower].append(disk)
self.animate_move(disk, from_tower, to_tower)
def animate_move(self, disk, from_tower, to_tower):
self.is_animating = True
self.root.update()
# 圆盘动画参数
base_y = 450
disk_height = 20
max_disk_width = 160
disk_width = disk * (max_disk_width / self.num_disks)
# 从源塔移除圆盘
self.draw_towers()
# 获取起始和目标位置
start_x = 200 + from_tower * 200
end_x = 200 + to_tower * 200
start_y = base_y - len(self.towers[from_tower]) * disk_height - disk_height
end_y = base_y - (len(self.towers[to_tower]) - 1) * disk_height - disk_height
# 创建动画圆盘
disk_id = self.canvas.create_rectangle(start_x - disk_width / 2, start_y,
start_x + disk_width / 2, start_y + disk_height,
fill=self.get_disk_color(disk))
# 动画过程
# 上升
while self.canvas.coords(disk_id)[1] > base_y - 250:
self.canvas.move(disk_id, 0, -5)
self.root.update()
time.sleep(self.animation_speed)
# 水平移动
direction = 1 if end_x > start_x else -1
while (direction == 1 and self.canvas.coords(disk_id)[0] < end_x - disk_width / 2) or
(direction == -1 and self.canvas.coords(disk_id)[2] > end_x + disk_width / 2):
self.canvas.move(disk_id, direction * 5, 0)
self.root.update()
time.sleep(self.animation_speed)
# 下降
while self.canvas.coords(disk_id)[3] < end_y + disk_height:
self.canvas.move(disk_id, 0, 5)
self.root.update()
time.sleep(self.animation_speed)
# 移除动画圆盘并更新显示
self.canvas.delete(disk_id)
self.draw_towers()
self.is_animating = False
def check_win(self):
return len(self.towers[0]) == 0 and len(self.towers[1]) == 0 and len(self.towers[2]) > 0
def auto_solve(self):
if self.is_animating:
return
# 复制当前游戏状态
original_towers = [tower.copy() for tower in self.towers]
original_selected = self.selected_tower
original_moves = self.moves
# 重置游戏
self.reset_game()
# 使用递归方法解决汉诺塔问题
def hanoi(n, source, target, auxiliary):
if n == 0:
return
hanoi(n - 1, source, auxiliary, target)
self.move_disk(source, target)
self.root.update()
time.sleep(0.5)
hanoi(n - 1, auxiliary, target, source)
# 开始自动解决
self.is_animating = True
hanoi(self.num_disks, 0, 2, 1)
self.is_animating = False
# 恢复原始游戏状态
# self.towers = original_towers
# self.selected_tower = original_selected
# self.moves = original_moves
# self.move_label.config(text=str(self.moves))
# self.draw_towers()
if __name__ == "__main__":
root = tk.Tk()
app = HanoiTower(root)
root.mainloop()
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END



















暂无评论内容