Python作业-汉诺塔

设计要求:
设计 GUI 界面的 Hannoi 塔,用户可以通过拖动鼠标移动各个
塔上的盘子,程序也可以自动演示盘子的移动过程。选择自动演示时程序将以动
画形式演示把 A 塔上的盘子全部移到 C 塔的过程,并将移动过程以文本形式显
示在一个文本区中
复制代码
import tkinter as tk
import time

root = tk.Tk()
root.title('Hannoi塔')
root.geometry('800x400')

# 创建画布,并绘制3个柱子
canvas = tk.Canvas(root, bg='white', width=600, height=300)
canvas.pack(side='left')
canvas.create_rectangle(200, 50, 210, 250, width=0, fill='black')
canvas.create_rectangle(300, 50, 310, 250, width=0, fill='black')
canvas.create_rectangle(400, 50, 410, 250, width=0, fill='black')

# 创建文本区域
text = tk.Text(root, width=30, height=10)
text.pack(side='right')

# 初始化盘子状态
disk_size = [3, 2, 1]
towers = [[], [], []]
for i in range(len(disk_size)):
    towers[0].append(disk_size[i])

# 创建盘子列表
disks = []
colors = ['red', 'blue', 'green']
for i in range(len(disk_size)):
    disk = canvas.create_rectangle(0, 0, 0, 0, width=0, fill=colors[i])
    disks.append(disk)

# 记录鼠标位置
x, y = 0, 0
moving_disk = None
moving_tower = None

# 鼠标拖拽盘子事件处理函数
def on_press(event):
    global moving_disk, x, y, moving_tower
    x, y = event.x, event.y
    tags = canvas.gettags(tk.CURRENT)
    if len(tags) > 0:
        index = int(tags[0])
        tower = int(tags[1])
        if len(towers[tower]) > 0 and towers[tower][-1] == disk_size[index]:
            moving_disk = disks[index]
            moving_tower = tower
            canvas.tag_raise(moving_disk)

def on_move(event):
    global moving_disk
    if moving_disk:
        dx, dy = event.x - x, event.y - y
        canvas.move(moving_disk, dx, dy)
        x, y = event.x, event.y

def on_release(event):
    global moving_disk, x, y, moving_tower, towers
    if moving_disk:
        cy = canvas.coords(moving_disk)[1] + 20
        tx = int((event.x - 200) / 100)
        if tx != moving_tower and (len(towers[tx]) == 0 or towers[tx][-1] > towers[moving_tower][-1]):
            moving_disk_x = canvas.coords(moving_disk)[0] + 10
            moving_disk_y = canvas.coords(moving_disk)[1] + 10
            canvas.coords(moving_disk, moving_disk_x, cy - 10, moving_disk_x + 100 - disk_size.index(towers[moving_tower][-1]) * 20, cy + 10)
            towers[tx].append(towers[moving_tower].pop())
            text.insert(tk.END, f'将盘子{disk_size.index(towers[tx][-1]) + 1}从柱子{moving_tower+1}移动到柱子{tx+1}\n')
            if check_win():
                text.insert(tk.END, '游戏胜利!\n')
        else:
            canvas.coords(moving_disk, 200 + moving_tower * 100 + 10 - disk_size.index(towers[moving_tower][-1]) * 20, cy - 10, 200 + moving_tower * 100 + 10 + 100 - disk_size.index(towers[moving_tower][-1]) * 20, cy + 10)
        moving_disk = None
        moving_tower = None

# 检查游戏是否胜利
def check_win():
    if len(towers[0]) == 0 and len(towers[1]) == 0:
        if towers[2] == [3, 2, 1]:
            return True
    return False

# 移动盘子的递归函数
def move_disc(canvas, size, source, target, spare, n):
    if n == 0:
        return
    move_disc(canvas, size, source, spare, target, n - 1)
    draw_disc(canvas, size[n - 1], source[n - 1], source.index + 1)
    draw_disc(canvas, size[n - 1], 0, target.index + 1)
    target.append(source.pop())
    root.update()
    canvas.after(500)
    move_disc(canvas, size, spare, target, source, n - 1)

# 绘制盘子
def draw_disc(canvas, size, pos, pole):
    global towers
    x1, y1, x2, y2 = 0, 0, 0, 0
    if pole == 1:
        x1, y1, x2, y2 = 180 - size * 10, 250 - pos * 20, 220 + size * 10, 260 - pos * 20
    elif pole == 2:
        x1, y1, x2, y2 = 280 - size * 10, 250 - pos * 20, 320 + size * 10, 260 - pos * 20
    else:
        x1, y1, x2, y2 = 380 - size * 10, 250 - pos * 20, 420 + size * 10, 260 - pos * 20
    for i in range(len(towers[pole-1])):
        if towers[pole-1][i] == size:
            canvas.coords(disks[size-1], x1, y1 + (len(towers[pole-1])-1-i)*20, x2, y2 + (len(towers[pole-1])-1-i)*20)
            break

# 自动演示移动过程
def animate():
    global disks
    size, source, target, spare = [3, 2, 1], [], [], []
    source, target, spare = source[::-1], target[::-1], spare[::-1]
    for i in range(len(size)):
        source.append(i)
    move_disc(canvas, size, source, target, spare, len(size))

# 鼠标拖拽事件绑定
canvas.tag_bind('disc', '<ButtonPress-1>', on_press)
canvas.tag_bind('disc', '<B1-Motion>', on_move)
canvas.tag_bind('disc', '<ButtonRelease-1>', on_release)

# 开始自动演示
animate()

root.mainloop()
复制代码

 

posted @   cojames  阅读(63)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示