Python实现汉诺塔问题的可视化(以动画的形式展示移动过程)
学习Python已经有一段时间了,也学习了递归的方法,而能够实践该方法的当然就是汉诺塔问题了,但是这次我们不只是要完成对汉诺塔过程的计算,还要通过turtle库来体现汉诺塔中每一层移动的过程。
一、设计一个类(Class)
类(Class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
下面是此程序需用到的类(Class)代码:
1 class Stack: 2 def __init__(self): 3 self.items = [] 4 def isEmpty(self): 5 return len(self.items) == 0 6 def push(self, item): 7 self.items.append(item) 8 def pop(self): 9 return self.items.pop() 10 def peek(self): 11 if not self.isEmpty(): 12 return self.items[len(self.items) - 1] 13 def size(self): 14 return len(self.items)
二、设计汉诺塔的底座
为了还原汉诺塔的移动过程,增强可视化程度,我们给它加上三个底座,代码如下:
1 def drawpole_3():#画出汉诺塔的poles 2 t = turtle.Turtle() 3 t.hideturtle() 4 def drawpole_1(k): 5 t.up() 6 t.pensize(10) 7 t.speed(100) 8 t.goto(400*(k-1), 100) 9 t.down() 10 t.goto(400*(k-1), -100) 11 t.goto(400*(k-1)-20, -100) 12 t.goto(400*(k-1)+20, -100) 13 drawpole_1(0)#画出汉诺塔的poles[0] 14 drawpole_1(1)#画出汉诺塔的poles[1] 15 drawpole_1(2)#画出汉诺塔的poles[2]
三、制造汉诺塔的盘子
汉诺塔当然少不了盘子了,我们要写一段代码来绘制若干个盘子,代码如下:
1 def creat_plates(n):#制造n个盘子 2 plates=[turtle.Turtle() for i in range(n)] 3 for i in range(n): 4 plates[i].up() 5 plates[i].hideturtle() 6 plates[i].shape("square") 7 plates[i].shapesize(1,8-i) 8 plates[i].goto(-400,-90+20*i) 9 plates[i].showturtle() 10 return plates
四、制造一个底座的栈
栈:栈作为一种数据结构,是一种只能在一端进行插入和删除操作。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
此处使用的栈并非Python中真正意义上的栈,而是与之意思相仿的说法,我们都知道,汉诺塔必须将最上的盘子取走方可移动第二层的盘子,以此类推,不移动上方的盘子,就无法移动下方的盘子,废话不多说,来看看这个代码吧:
1 def pole_stack():#制造poles的栈 2 poles=[Stack() for i in range(3)] 3 return poles
五、设计移动盘子的代码
准备完前面的工作,现在就要开始移动盘子了,代码如下:
1 def moveDisk(plates,poles,fp,tp):#把poles[fp]顶端的盘子plates[mov]从poles[fp]移到poles[tp] 2 mov=poles[fp].peek() 3 plates[mov].goto((fp-1)*400,150) 4 plates[mov].goto((tp-1)*400,150) 5 l=poles[tp].size()#确定移动到底部的高度(恰好放在原来最上面的盘子上面) 6 plates[mov].goto((tp-1)*400,-90+20*l)
六、设计操控盘子移动方向的代码
可以移动盘子了当然还不够,只是胡乱地移动无法解决汉诺塔问题,我们要让盘子向着能够解决问题的方向移动,代码如下:
1 def moveTower(plates,poles,height,fromPole, toPole, withPole):#递归放盘子 2 if height >= 1: 3 moveTower(plates,poles,height-1,fromPole,withPole,toPole) 4 moveDisk(plates,poles,fromPole,toPole) 5 poles[toPole].push(poles[fromPole].pop()) 6 moveTower(plates,poles,height-1,withPole,toPole,fromPole)
七、调用
终于完成了全部准备工作,现在就来调用函数,让他们一起发挥作用吧!
1 import turtle 2 3 class Stack: 4 def __init__(self): 5 self.items = [] 6 def isEmpty(self): 7 return len(self.items) == 0 8 def push(self, item): 9 self.items.append(item) 10 def pop(self): 11 return self.items.pop() 12 def peek(self): 13 if not self.isEmpty(): 14 return self.items[len(self.items) - 1] 15 def size(self): 16 return len(self.items) 17 18 def drawpole_3():#画出汉诺塔的poles 19 t = turtle.Turtle() 20 t.hideturtle() 21 def drawpole_1(k): 22 t.up() 23 t.pensize(10) 24 t.speed(100) 25 t.goto(400*(k-1), 100) 26 t.down() 27 t.goto(400*(k-1), -100) 28 t.goto(400*(k-1)-20, -100) 29 t.goto(400*(k-1)+20, -100) 30 drawpole_1(0)#画出汉诺塔的poles[0] 31 drawpole_1(1)#画出汉诺塔的poles[1] 32 drawpole_1(2)#画出汉诺塔的poles[2] 33 34 def creat_plates(n):#制造n个盘子 35 plates=[turtle.Turtle() for i in range(n)] 36 for i in range(n): 37 plates[i].up() 38 plates[i].hideturtle() 39 plates[i].shape("square") 40 plates[i].shapesize(1,8-i) 41 plates[i].goto(-400,-90+20*i) 42 plates[i].showturtle() 43 return plates 44 45 def pole_stack():#制造poles的栈 46 poles=[Stack() for i in range(3)] 47 return poles 48 49 def moveDisk(plates,poles,fp,tp):#把poles[fp]顶端的盘子plates[mov]从poles[fp]移到poles[tp] 50 mov=poles[fp].peek() 51 plates[mov].goto((fp-1)*400,150) 52 plates[mov].goto((tp-1)*400,150) 53 l=poles[tp].size()#确定移动到底部的高度(恰好放在原来最上面的盘子上面) 54 plates[mov].goto((tp-1)*400,-90+20*l) 55 56 def moveTower(plates,poles,height,fromPole, toPole, withPole):#递归放盘子 57 if height >= 1: 58 moveTower(plates,poles,height-1,fromPole,withPole,toPole) 59 moveDisk(plates,poles,fromPole,toPole) 60 poles[toPole].push(poles[fromPole].pop()) 61 moveTower(plates,poles,height-1,withPole,toPole,fromPole) 62 63 myscreen=turtle.Screen() 64 drawpole_3() 65 n=int(input("请输入汉诺塔的层数并回车:\n")) 66 plates=creat_plates(n) 67 poles=pole_stack() 68 for i in range(n): 69 poles[0].push(i) 70 moveTower(plates,poles,n,0,2,1) 71 myscreen.exitonclick()
八、效果
首先输入一下我们想测试的汉诺塔层数,为节省时间我就选择了3层
下面是移动过程
看来效果还不错,这样汉诺塔的可视化就实现啦!