|
目录汉诺塔游戏1.抓取颜色2.绘制圆盘3.九层汉塔4.绘制塔架5.叠加圆盘6.游戏框架 汉诺塔游戏汉诺塔(TowerofHanoi),是一个源于印度古老传说的益智玩具。这个传说讲述了大梵天创造世界的时候,他做了三根金刚石柱子,并在其中一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门将这些圆盘从下面开始按大小顺序重新摆放在另一根柱子上,并规定在小圆盘上不能放大圆盘,同时在三根柱子之间一次只能移动一个圆盘。当盘子的数量增加时,移动步骤的数量会呈指数级增长,圆盘数为n时,总步骤数steps为2^n-1。n=64,steps=2^64-1=18446744073709551616≈1.845x10^19汉诺塔问题是一个递归问题,也可以使用非递归法来解决,例如使用栈来模拟递归过程。这个问题不仅是一个数学和逻辑问题,也是一个很好的教学工具,可以用来教授递归、算法和逻辑思考等概念。同时,汉诺塔游戏也具有一定的娱乐性,人们可以通过解决不同规模的汉诺塔问题来挑战自己的智力和耐心。1.抓取颜色本篇将展示如何用pythonpyglet库制作这个小游戏,首先在上图中抓取出需要用到的颜色RGB值,每种颜色画一个矩形块:Rectangle(x,y,width,height,color=color)代码:importpygletwindow=pyglet.window.Window(800,500,caption='汉诺塔')pyglet.gl.glClearColor(1,1,1,1)batch=pyglet.graphics.Batch()Color=(182,128,18),(25,65,160),(56,170,210),(16,188,78),(20,240,20),(240,240,20),(255,128,20),(240,20,20),(245,60,138)classRect:def__init__(self,x,y,color=(0,0,0),width=180,height=60):self.rect=pyglet.shapes.Rectangle(x,y,width,height,color=color,batch=batch)@window.eventdefon_draw():window.clear()batch.draw()rectangle=[None]*9fori,colorinenumerate(Color):rectangle[i]=Rect(110+i//3*200,120+i%3*100,color)pyglet.app.run()2.绘制圆盘圆盘用矩形加2个半圆表示,半圆用扇形控件绘制:Sector(x, y,radius=R,angle=pi,start_angle=-pi/2,color=color)注意圆盘类中的矩形的宽度和坐标需要调整,整个圆盘类的宽度是矩形宽度加2倍扇形半径,圆盘的中心是矩形的中心而不是矩形左下角。importpygletwindow=pyglet.window.Window(800,500,caption='汉诺塔')pyglet.gl.glClearColor(1,1,1,1)batch=pyglet.graphics.Batch()pi=3.141592653589793Color=(182,128,18),(25,65,160),(56,170,210),(16,188,78),(20,240,20),(240,240,20),(255,128,20),(240,20,20),(245,60,138)classBead:def__init__(self,x,y,width=180,height=60):self.sec1=pyglet.shapes.Sector(x+width/2-height/2,y,radius=height/2,angle=pi,start_angle=-pi/2,color=Color[5],batch=batch)self.sec2=pyglet.shapes.Sector(x-width/2+height/2,y,radius=height/2,angle=pi,start_angle=pi/2,color=Color[5],batch=batch)self.rect=pyglet.shapes.Rectangle(x-width/2+height/2,y-height/2,width-height,height,color=Color[1],batch=batch)@window.eventdefon_draw():window.clear()batch.draw()ead1=Bead(window.width/2,window.height/2)pyglet.app.run()3.九层汉塔叠加多个圆盘,绘制出汉诺塔的样子:代码:importpygletwindow=pyglet.window.Window(800,500,caption='汉诺塔')pyglet.gl.glClearColor(1,1,1,1)batch=pyglet.graphics.Batch()pi=3.141592653589793Color=(182,128,18),(25,65,160),(56,170,210),(16,188,78),(20,240,20),(240,240,20),(255,128,20),(240,20,20),(245,60,138)classDisk:def__init__(self,x,y,color=(0,0,0),width=200,height=20):self.sec1=pyglet.shapes.Sector(x+width/2-height/2,y,radius=height/2,angle=pi,start_angle=-pi/2,color=color,batch=batch)self.sec2=pyglet.shapes.Sector(x-width/2+height/2,y,radius=height/2,angle=pi,start_angle=pi/2,color=color,batch=batch)self.rect=pyglet.shapes.Rectangle(x-width/2+height/2,y-height/2,width-height,height,color=color,batch=batch)assert(width>heightandx-width/2+height/2>0)@window.eventdefon_draw():window.clear()batch.draw()x,y=window.width/2,window.height/2width,height=200,40disk=[]foriinrange(9):disk.append(Disk(x,y+height*(i-4),Color[i],width=width-20*(i-1),height=height))pyglet.app.run()4.绘制塔架把圆盘变簿(高度换成厚度),再加一条粗直线(直线的宽度等于圆盘的厚度)表示出“竖杆”,就画出叠放的架子来: self.pole=pyglet.shapes.Line(x,y,x,y+height,width=thickness,color=color) self.disk=Disk(x,y,color=color,width=width,height=thickness)代码:importpygletwindow=pyglet.window.Window(800,500,caption='汉诺塔')pyglet.gl.glClearColor(1,1,1,1)batch=pyglet.graphics.Batch()pi=3.141592653589793Color=(182,128,18),(25,65,160),(56,170,210),(16,188,78),(20,240,20),(240,240,20),(255,128,20),(240,20,20),(245,60,138)classDisk:def__init__(self,x,y,color=(0,0,0),width=200,height=20):self.sec1=pyglet.shapes.Sector(x+width/2-height/2,y,radius=height/2,angle=pi,start_angle=-pi/2,color=color,batch=batch)self.sec2=pyglet.shapes.Sector(x-width/2+height/2,y,radius=height/2,angle=pi,start_angle=pi/2,color=color,batch=batch)self.rect=pyglet.shapes.Rectangle(x-width/2+height/2,y-height/2,width-height,height,color=color,batch=batch)assert(width>heightandx-width/2+height/2>0)classHann:def__init__(self,x,y,color=(0,0,0),width=220,height=300,thickness=20):self.pole=pyglet.shapes.Line(x,y,x,y+height,width=thickness,color=color,batch=batch)self.disk=Disk(x,y,color=color,width=width,height=thickness)@window.eventdefon_draw():window.clear()batch.draw()pole1=Hann(window.width/2-250,100)pole2=Hann(window.width/2,100,color=Color[0])pole3=Hann(window.width/2+250,100,color=Color[1])pyglet.app.run()5.叠加圆盘把多个圆盘叠加磊在塔架上,圆盘数至少为2。注意Color颜色列表共有9种颜色,Color[i%8+1]只取后8种颜色,Color[0]仅用于塔架的涂色。Hann类中各控件的坐标计算有点复杂,以下方案可以解决问题但未必是最佳方案: self.x,self.y=x,y self.width=width self.height=(height-thickness*2)/order self.step=(width-thickness)/(order+1) self.beads=[] self.coordinates=[] foriinrange(order): self.coordinates.append([self.x,self.y+(i+1)*self.height-(self.height-thickness)/2]) 代码:importpygletwindow=pyglet.window.Window(800,500,caption='汉诺塔')pyglet.gl.glClearColor(1,1,1,1)batch=pyglet.graphics.Batch()pi=3.141592653589793Color=(182,128,18),(25,65,160),(56,170,210),(16,188,78),(20,240,20),(240,240,20),(255,128,20),(240,20,20),(245,60,138)classDisk:def__init__(self,x,y,color=(0,0,0),width=200,height=20):self.sec1=pyglet.shapes.Sector(x+width/2-height/2,y,radius=height/2,angle=pi,start_angle=-pi/2,color=color,batch=batch)self.sec2=pyglet.shapes.Sector(x-width/2+height/2,y,radius=height/2,angle=pi,start_angle=pi/2,color=color,batch=batch)self.rect=pyglet.shapes.Rectangle(x-width/2+height/2,y-height/2,width-height,height,color=color,batch=batch)assert(width>heightandx-width/2+height/2>0)classHann:def__init__(self,x,y,order=2,thickness=20,width=220,height=300):assert(order>1)self.pole=pyglet.shapes.Line(x,y,x,y+height,width=thickness,color=Color[0],batch=batch)self.disk=Disk(x,y,color=Color[0],width=width+thickness,height=thickness)self.x,self.y=x,yself.width=widthself.height=(height-thickness*2)/orderself.step=(width-thickness)/(order+1)self.beads=[]self.coordinates=[]foriinrange(order):self.coordinates.append([self.x,self.y+(i+1)*self.height-(self.height-thickness)/2])self.fillup()deffillup(self):fori,xyinenumerate(self.coordinates):self.beads.append(Disk(*xy,Color[i%8+1],width=self.width-i*self.step,height=self.height))@window.eventdefon_draw():window.clear()batch.draw()hann1=Hann(window.width/2-260,100,2)hann2=Hann(window.width/2-22,180,5,25)hann3=Hann(window.width/2+230,80,10,15,300,380)pyglet.app.run()6.游戏框架画三个相同的塔架,左边的磊放好圆盘。另外用两个圆代替两个扇形,效果一样却省了pi常量。Circle(x+width/2-height/2,y,radius=height/2,color=color)代码: importpygletwindow=pyglet.window.Window(800,500,caption='汉诺塔')pyglet.gl.glClearColor(1,1,1,1)batch=pyglet.graphics.Batch()Color=(182,128,18),(25,65,160),(56,170,210),(16,188,78),(20,240,20),(240,240,20),(255,128,20),(240,20,20),(245,60,138)classDisk:def__init__(self,x,y,color=(0,0,0),width=200,height=20):self.cir1=pyglet.shapes.Circle(x+width/2-height/2,y,radius=height/2,color=color,batch=batch)self.cir2=pyglet.shapes.Circle(x-width/2+height/2,y,radius=height/2,color=color,batch=batch)self.rect=pyglet.shapes.Rectangle(x-width/2+height/2,y-height/2,width-height,height,color=color,batch=batch)assert(width>heightandx-width/2+height/2>0)classHann:def__init__(self,x,y,order=2,thickness=20,width=200,height=300):assert(order>1)self.pole=pyglet.shapes.Line(x,y,x,y+height,width=thickness,color=Color[0],batch=batch)self.disk=Disk(x,y,color=Color[0],width=width+thickness,height=thickness)self.x,self.y=x,yself.width=widthself.height=(height-thickness*2)/orderself.step=(width-thickness)/(order+1)self.beads=[]self.coordinates=[]foriinrange(order):self.coordinates.append([self.x,self.y+(i+1)*self.height-(self.height-thickness)/2])deffillup(self):fori,xyinenumerate(self.coordinates):self.beads.append(Disk(*xy,Color[i%8+1],width=self.width-i*self.step,height=self.height))classGame:def__init__(self,x,y,order=2,space=250):self.x,self.y=x,yself.space=spaceself.order=orderself.hanns=Hann(x-space,y,order),Hann(x,y,order),Hann(x+space,y,order)self.hanns[0].fillup()@window.eventdefon_draw():window.clear()batch.draw()hann=Game(window.width/2,100,8)pyglet.app.run()接下来就要添加鼠标和键盘事件,用于操作在塔架上移动圆盘。本篇完,下期继续......
|
|