先看效果吧:
1. 汉诺塔递归
如果需要把 n 个 plates 从 A 柱移到 C 柱:
- 先将上面的 n-1 个 plates 从 A 移到 B
- 将 A 最后一个 plates 移到 C
- 再将 n-1 个 plates 从 B 移到 C
def hano(n, A, B, C):
if n == 1:
print(A + ' -> ' + C)
else:
hano(n-1, A, C, B)
print(A + ' -> ' + C)
hano(n-1, B, A, C)
hano(3, 'A', 'B', 'C')
结果如下:
A -> C
A -> B
C -> B
A -> C
B -> A
B -> C
A -> C
2. 绘制柱子
使用 Turtle 库绘制三跟柱子 poles:
# 绘制三跟柱子
def drawpoles():
t = turtle.Turtle()
t.hideturtle()
t.color('gray')
for i in range(3):
t.up()
t.pensize(10)
t.speed('fast')
t.goto(250*(i-1), 100)
t.down()
t.goto(250*(i-1), -100)
t.goto(250*(i-1)-100, -100)
t.goto(250*(i-1)+100, -100)
调用后结果如下:
3. 创建圆盘
创建若干圆盘,所有圆盘都是一个 Turtle()
对象
所有圆盘存放在三个栈上,对应 A B 和 C 三跟柱子
3.1 创建 Stack 类
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return len(self.items) == 0
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[len(self.items) - 1]
def size(self):
return len(self.items)
3.2 生成圆盘
先创建若干圆盘:
# 生成 plates
HEIGHT = 25
colors = ['peru', 'tomato', 'darkorange',
'gold', 'palegreen', 'paleturquoise', 'skyblue', 'plum']
def create_plates(n):
plates = [turtle.Turtle() for i in range(n)]
for i in range(n):
plates[i].speed(5)
plates[i].hideturtle()
c = colors[i]
plates[i].color(c)
plates[i].up()
plates[i].hideturtle()
plates[i].shape('square')
plates[i].shapesize(1.2, 8-1.1*i)
plates[i].goto(-250, -82 + HEIGHT*i)
plates[i].showturtle()
return plates
通过下面的语句调用函数创建 plates,将 plates 装载到第一个栈 Stack 中:
plates_num = 5
plates = create_plates(plates_num)
poles = [Stack() for i in range(3)]
for plate in plates:
poles[0].push(plate)
4. 移动操作
如何将一个盘移动呢?
- 获取要移动的盘所在柱子最顶部的盘(对应柱子的栈弹栈)
- 将盘先搬起来,再移动到目标柱顶部,再下落
- 盘放到目标柱后,目标柱对应的栈压栈
# 一次移动
def moveDisk(poles, fromPole, toPole):
plate = poles[fromPole].pop()
plate.goto((fromPole - 1) * 250, 120)
plate.goto((toPole - 1) * 250, 120)
y = poles[toPole].size() * HEIGHT - 82
plate.goto((toPole - 1) * 250, y)
poles[toPole].push(plate)
5. 动起来
对原来的汉诺塔递归程序修改,就可以得到动画:
def hano(n, poles, fromPole, withPole, toPole):
if n == 1:
moveDisk(poles, fromPole, toPole)
else:
hano(n-1, poles, fromPole, toPole, withPole)
moveDisk(poles, fromPole, toPole)
hano(n-1, poles, withPole, fromPole, toPole)
接着在主程序中调用函数:
myscreen = turtle.Screen()
drawpoles()
plates_num = 5
plates = create_plates(plates_num)
poles = [Stack() for i in range(3)]
for plate in plates:
poles[0].push(plate)
hano(plates_num, poles, 0, 1, 2)
turtle.done()
大功告成 🍻
源代码丢进 github 啦