Python 一步一步教你用pyglet制作汉诺塔游戏(终篇)_用python编汉诺塔

最后

不知道你们用的什么环境,我一般都是用的Python3.6环境和pycharm解释器,没有软件,或者没有资料,没人解答问题,都可以免费领取(包括今天的代码),过几天我还会做个视频教程出来,有需要也可以领取~

给大家准备的学习资料包括但不限于:

Python 环境、pycharm编辑器/永久激活/翻译插件

python 零基础视频教程

Python 界面开发实战教程

Python 爬虫实战教程

Python 数据分析实战教程

python 游戏开发实战教程

Python 电子书100本

Python 学习路线规划

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

info1.text = f’恭喜您完成 {hanns.order} 层汉诺塔!任意点击层数加一!’
            else:
                info1.text = f’太棒了!您已完成 {hanns.order} 层汉诺塔,游戏结束!’
                gamecompleted = True
                return
    elif not gamecompleted:
        hanns = Hann(window.width/2, 120, hanns.order+1)
        info1.text = f’ {hanns.order} 层汉诺塔,游戏开始!’
        info2.text = f’当前层数:{hanns.order}\t最佳步数:{2**hanns.order-1}\t当前步数:{hanns.steps}’

Hann 类中增加一个改色的方法,用于标注被点击的要移动的源塔架:

def setdiskcolor(self, n, color=Color[0]):
        self.disk[n].cir1.color = color
        self.disk[n].cir2.color = color
        self.disk[n].rect.color = color

完整代码:

import pyglet
 
window = 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)
 
class Disk:
    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)
    def move(self, dx, dy):
        self.cir1.x += dx; self.cir1.y += dy
        self.cir2.x += dx; self.cir2.y += dy
        self.rect.x += dx; self.rect.y += dy
 
class Hann:
    def __init__(self, x, y, order=2, space=250, thickness=20, width=200, height=300):
        assert(order>1)
        self.pole = [pyglet.shapes.Line(x-i*space, y, x-i*space, y+height, width=thickness, color=Color[0], batch=batch) for i in range(-1,2)]
        self.disk = [Disk(x+i*space, y, color=Color[0], width=width+thickness, height=thickness) for i in range(-1,2)]
        self.x, self.y = x, y
        self.order = order
        self.space = space
        self.thickness = thickness
        self.width = width
        self.poleheight = height
        self.beadheight = (height-thickness*2)/order
        self.step = (width-thickness)/(order+1)
        self.steps = 0
        self.macro = []
        coordinates = [(self.x-space, self.y+(i+1)*self.beadheight-(self.beadheight-thickness)/2) for i in range(order)]
        self.beads = [Disk(*xy, Color[i%8+1], width=self.width-i*self.step, height=self.beadheight) for i,xy in enumerate(coordinates)]
        self.array = [[*range(order)], [], []]
    def move(self, pole1, pole2):
        if self.array[pole1]:
            bead = self.array[pole1].pop()
            if self.array[pole2] and bead<self.array[pole2][-1]:
                self.array[pole1].append(bead)
                return False
        else:
            return None
        self.beads[bead].move((pole2-pole1)*self.space, (len(self.array[pole2])-len(self.array[pole1]))*self.beadheight)
        self.array[pole2].append(bead)
        self.steps += 1
        self.macro.append((pole1, pole2))
        return True
    def setdiskcolor(self, n, color=Color[0]):
        self.disk[n].cir1.color = color
        self.disk[n].cir2.color = color
        self.disk[n].rect.color = color
    def on_mouse_over(self, x, y):
        for i in range(-1,2):
            if hanns.x-hanns.width/2 < x-i*hanns.space < hanns.x+hanns.width/2 and hanns.y-hanns.thickness/2 < y < hanns.y+hanns.poleheight:
                return i+1
    def success(self):
        return len(self.array[2]) == self.order
 
@window.event
def on_draw():
    window.clear()
    batch.draw()
 
@window.event
def on_mouse_press(x, y, dx, dy):
    global xy, hanns, gamecompleted
    if not hanns.success():
        pole = hanns.on_mouse_over(x, y)
        if pole is not None:
            xy.append(pole)
            if len(xy)==1:
                hanns.setdiskcolor(xy[0], (255,0,0))
                if not hanns.array[pole]:
                    hanns.setdiskcolor(xy[0])
                    xy.pop()
                    return
        if len(xy)==2:
            if xy[0]!=xy[1]:
                info = hanns.move(*xy)
                hanns.setdiskcolor(xy[0])
                if info is False:
                    info1.text = '起始圆盘大于目标位置的圆盘'
                elif info is None:
                    info1.text = '所选起始位置的塔架不能为空'
                else:
                    info1.text = f'{hanns.order-hanns.array[xy[1]][-1]}号圆盘从{xy[0]+1}号塔架移动到{xy[1]+1}号塔架'
            hanns.setdiskcolor(xy[0])
            xy.clear()
            info2.text = f'当前层数:{hanns.order}\t最佳步数:{2**hanns.order-1}\t当前步数:{hanns.steps}'
        if hanns.success():
            if hanns.order<24:
                info1.text = f'恭喜您完成 {hanns.order} 层汉诺塔!任意点击层数加一!'
            else:
                info1.text = f'太棒了!您已完成 {hanns.order} 层汉诺塔,游戏结束!'
                gamecompleted = True
                return
    elif not gamecompleted:
        hanns = Hann(window.width/2, 120, hanns.order+1)
        info1.text = f' {hanns.order} 层汉诺塔,游戏开始!'
        info2.text = f'当前层数:{hanns.order}\t最佳步数:{2**hanns.order-1}\t当前步数:{hanns.steps}'
 
xy = []
order = 2
hanns = Hann(window.width/2, 120, order)
info1 = pyglet.text.Label('操作方法:鼠标先后点击起始和目标位置就能移动圆盘', font_size=21, color=(0,0,0,255), x=window.width/2, y=50, anchor_x='center', batch=batch)
info2 = pyglet.text.Label(f'当前层数:{order}\t最佳步数:{2**order-1}\t当前步数:0', font_size=18, color=(0,0,0,255), x=80, y=450, batch=batch)
gamecompleted = False

pyglet.app.run()

演示回放

优化代码,布局稍作调整,并加入帮助、演示和回放等功能。演示和回放的区别:演示功能是提供如何移动的教学帮助;回放功能则是展示用户自己的移动过程。

运行效果如下:

完整代码

import pyglet
from pyglet.window import key

Width, Height = 800, 500
window = pyglet.window.Window(Width, Height, caption='Tower of Hanoi')
screen = pyglet.canvas.Display().get_default_screen()
window.set_location((screen.width-Width)//2, (screen.height-Height)//2)
pyglet.gl.glClearColor(0.78, 0.88, 0.98, 1)
batch = pyglet.graphics.Batch()
group = pyglet.graphics.Group()

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)
 
class Disk:
    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)
    def move(self, dx, dy):
        self.cir1.x += dx; self.cir1.y += dy
        self.cir2.x += dx; self.cir2.y += dy
        self.rect.x += dx; self.rect.y += dy
 
class Hann:
    def __init__(self, order=2, x=window.width/2, y=110, space=250, thickness=20, width=200, height=300):
        assert(order>1)
        self.pole = [pyglet.shapes.Line(x+i*space, y, x+i*space, y+height, width=thickness, color=Color[0], batch=batch) for i in range(-1,2)]
        self.disk = [Disk(x+i*space, y, color=Color[0], width=width+thickness, height=thickness) for i in range(-1,2)]
        self.x, self.y = x, y
        self.order = order
        self.ordermax = 24
        self.space = space
        self.thickness = thickness
        self.width = width
        self.poleheight = height
        self.beadheight = (height-thickness*2)/order
        self.step = (width-thickness)/(order+1)
        self.steps = 0
        self.macro = []
        self.posxy = []
        self.click = False
        self.ctrlz = False
        self.playback = False
        coordinates = [(self.x-space, self.y+(i+1)*self.beadheight-(self.beadheight-thickness)/2) for i in range(order)]
        self.beads = [Disk(*pos, Color[i%8+1], width=self.width-i*self.step, height=self.beadheight) for i,pos in enumerate(coordinates)]
        self.array = [[*range(order)], [], []]
        self.arraymacro = []
    def move(self, pole1, pole2):
        if self.array[pole1]:
            bead = self.array[pole1].pop()
            if self.array[pole2] and bead<self.array[pole2][-1]:
                self.array[pole1].append(bead)
                return False
        else:
            return None
        self.beads[bead].move((pole2-pole1)*self.space, (len(self.array[pole2])-len(self.array[pole1]))*self.beadheight)
        self.array[pole2].append(bead)
        self.steps += 1
        self.click = True
        self.macro.append((pole1, pole2))
        self.arraymacro.append([array[:] for array in self.array])
        return True
    def set_color(self, n, color=Color[0]):
        self.click = color==Color[0]
        self.disk[n].cir1.color = color
        self.disk[n].cir2.color = color
        self.disk[n].rect.color = color
        self.pole[n].color = color
    def on_mouse_over(self, x, y):
        for i in range(-1,2):
            if hanns.x-hanns.width/2 < x-i*hanns.space < hanns.x+hanns.width/2 and hanns.y-hanns.thickness/2 < y < hanns.y+hanns.poleheight:
                return i+1
    def success(self):
        return len(self.array[2]) == self.order

def hanoi(n, start=0, mid=1, end=2, moves=None):
    if moves is None:
        moves = []
    if n == 1:
        moves.append((start, end))
    else:
        hanoi(n-1, start, end, mid, moves)
        moves.append((start, end))
        hanoi(n-1, mid, start, end, moves)
    return moves

def hanoimacro(n, start=0, mid=1, end=2, moves=None):
    global macro, array
    if moves is None:
        moves = []
        array = [[*range(n)],[],[]]
        macro = [[[*range(n)],[],[]]]
    if n == 1:
        moves.append((start, end))
        array[end].append(array[start].pop())
        macro.append([disk[:] for disk in array])
    else:
        hanoimacro(n-1, start, end, mid, moves)
        moves.append((start, end))
        array[end].append(array[start].pop())
        macro.append([disk[:] for disk in array])
        hanoimacro(n-1, mid, start, end, moves)
    return macro

@window.event
def on_draw():
    window.clear()
    batch.draw()
 
@window.event
def on_mouse_press(x, y, dx, dy):
    global hanns, gamestarting, gamecompleted
    if not gamestarting:
        gamestarting = True
        show_message(False)
        return
    elif hanns.playback:
        return
    if not hanns.success():
        pole = hanns.on_mouse_over(x, y)
        if pole is not None:
            hanns.posxy.append(pole)
            if len(hanns.posxy)==1:
                hanns.set_color(hanns.posxy[0], (200,150,0))
                if not hanns.array[pole]:
                    hanns.set_color(hanns.posxy[0])
                    hanns.posxy.pop()
                    return
        if len(hanns.posxy)==2:
            if hanns.posxy[0]!=hanns.posxy[1]:
                info = hanns.move(*hanns.posxy)
                hanns.set_color(hanns.posxy[0])
                if info:
                    info1.text = information(3)
                else:
                    info1.text = information(6)
            hanns.set_color(hanns.posxy[0])
            hanns.posxy.clear()
            info2.text = information()
        if hanns.success():
            if hanns.order<24:
                info1.text = information(4)
            else:
                info1.text = information(5)
                gamecompleted = True
                return
    elif not gamecompleted:
        hanns = Hann(hanns.order+1)
        info1.text = information(0)
        info2.text = information(2)

@window.event
def on_key_press(symbol, modifiers):
    global hanns, macro, gamestarting
    def show_how(event):
        if macro:
            hanns.move(*macro.pop(0))
            info2.text = information()
        else:
            info1.text = info1.text.replace('中......', '完成!')
            hanns.playback = False
            pyglet.clock.unschedule(show_how)
    if not gamestarting:
        gamestarting = True
        show_message(False)
        return
    if hanns.playback:
        if symbol in (key.B, key.BREAK) and modifiers & key.MOD_CTRL:
            macro.clear()
            info1.text = info1.text.replace('中......', '终止,')+'游戏继续!'
        return
    if hanns.macro and hanns.click and not hanns.success() and symbol==key.Z and modifiers & key.MOD_CTRL:
        hanns.ctrlz = not hanns.ctrlz
        hanns.posxy = hanns.macro.pop()[::-1]
        info = hanns.move(*hanns.posxy)
        hanns.steps -= 2*hanns.ctrlz
        hanns.posxy = []
    elif symbol == key.H and modifiers & key.MOD_CTRL:
        gamestarting = False
        show_message(True)
    elif symbol == key.R and modifiers & key.MOD_CTRL:
        if hanns.steps:
            hanns = Hann(hanns.order)
            info1.text = information(0)
    elif symbol == key.N and modifiers & (key.MOD_CTRL | key.MOD_SHIFT) and modifiers & key.MOD_SHIFT:
        if hanns.order>2:
            hanns = Hann(hanns.order-1)
            info1.text = information(0)
        else:
            info1.text = information(7)
    elif symbol == key.N and modifiers & key.MOD_CTRL and not modifiers & key.MOD_SHIFT:
        if hanns.order<24:
            hanns = Hann(hanns.order+1)
            info1.text = information(0)
        else:
            info1.text = information(8)
    elif symbol in (key.S, key.P) and modifiers & key.MOD_CTRL:
        macro = hanns.macro
        hanns = Hann(hanns.order)
        hanns.playback = True
        if symbol==key.S:
            task = '演示中......'
            macro = hanoi(hanns.order)
        elif symbol==key.P:
            task = '回放中......'
        info1.text = f'{hanns.order} 层汉诺塔{task}'
        pyglet.clock.schedule_interval(show_how, 9/(hanns.order**2+9))
    info2.text = information()

def show_message(visible=True):
    box1.visible = box2.visible = html.visible = visible
    info1.text = information(0)

def messagebox():
    global box1, box2, html
    rect = 150, 90, 500, 330
    box1 = pyglet.shapes.Rectangle(*rect, color=(255,255,255,200), batch=batch, group=group)
    box2 = pyglet.shapes.Box(*rect, color=(255,0,0,255), thickness=3, batch=batch, group=group)


**(1)Python所有方向的学习路线(新版)**  

这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

最近我才对这些路线做了一下新的更新,知识体系更全面了。



![在这里插入图片描述](https://img-blog.csdnimg.cn/1f807758e039481fa866130abf71d796.png#pic_center)



**(2)Python学习视频**



包含了Python入门、爬虫、数据分析和web开发的学习视频,总共100多个,虽然没有那么全面,但是对于入门来说是没问题的,学完这些之后,你可以按照我上面的学习路线去网上找其他的知识资源进行进阶。

![在这里插入图片描述](https://img-blog.csdnimg.cn/d66e3ad5592f4cdcb197de0dc0438ec5.png#pic_center)



**(3)100多个练手项目**

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。

![在这里插入图片描述](https://img-blog.csdnimg.cn/f5aeb4050ab547cf90b1a028d1aacb1d.png#pic_center)




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618317507)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值