Python使用pyglet库完整实现汉诺塔游戏流程详解

 更新时间:2024年04月01日 16:55:19   作者:Hann Yang  
这篇文章主要介绍了Python使用pyglet库完整实现汉诺塔游戏流程,汉诺塔问题是一个递归问题,也可以使用非递归法来解决,这个问题不仅是一个数学和逻辑问题,也是一个很好的教学工具,可以用来教授递归、算法和逻辑思考等概念,需要的朋友可以参考下

前言

汉诺塔(Tower of Hanoi),是一个源于印度古老传说的益智玩具。这个传说讲述了大梵天创造世界的时候,他做了三根金刚石柱子,并在其中一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门将这些圆盘从下面开始按大小顺序重新摆放在另一根柱子上,并规定在小圆盘上不能放大圆盘,同时在三根柱子之间一次只能移动一个圆盘。当盘子的数量增加时,移动步骤的数量会呈指数级增长,圆盘数为n时,总步骤数steps为2^n - 1。

n = 64, steps = 2^64 - 1 = 18446744073709551616 ≈ 1.845 x 10^19

汉诺塔问题是一个递归问题,也可以使用非递归法来解决,例如使用栈来模拟递归过程。这个问题不仅是一个数学和逻辑问题,也是一个很好的教学工具,可以用来教授递归、算法和逻辑思考等概念。同时,汉诺塔游戏也具有一定的娱乐性,人们可以通过解决不同规模的汉诺塔问题来挑战自己的智力和耐心。

抓取颜色

本篇将展示如何用python pyglet库制作这个小游戏,首先在上图中抓取出需要用到的颜色RGB值,每种颜色画一个矩形块:

Rectangle(x, y, width, height, 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 Rect:
    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.event
def on_draw():
    window.clear()
    batch.draw()
rectangle = [None]*9
for i,color in enumerate(Color):
    rectangle[i] = Rect(110+i//3*200, 120+i%3*100, color)
pyglet.app.run()

绘制圆盘

圆盘用矩形加2个半圆表示,半圆用扇形控件绘制:

Sector(x,y, radius=R, angle=pi, start_angle=-pi/2, color=color)

注意圆盘类中的矩形的宽度和坐标需要调整,整个圆盘类的宽度是矩形宽度加2倍扇形半径,圆盘的中心是矩形的中心而不是矩形左下角。

import pyglet
window = pyglet.window.Window(800, 500, caption='汉诺塔')
pyglet.gl.glClearColor(1, 1, 1, 1)
batch = pyglet.graphics.Batch()
pi = 3.141592653589793
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 Bead:
    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.event
def on_draw():
    window.clear()
    batch.draw()
ead1 = Bead(window.width/2, window.height/2)
pyglet.app.run()

九层汉塔

叠加多个圆盘,绘制出汉诺塔的样子:

代码:

import pyglet
window = pyglet.window.Window(800, 500, caption='汉诺塔')
pyglet.gl.glClearColor(1, 1, 1, 1)
batch = pyglet.graphics.Batch()
pi = 3.141592653589793
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.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>height and x-width/2+height/2>0)
@window.event
def on_draw():
    window.clear()
    batch.draw()
x, y = window.width/2, window.height/2
width, height = 200, 40
disk = []
for i in range(9):
    disk.append(Disk(x, y+height*(i-4), Color[i], width=width-20*(i-1), height=height))
pyglet.app.run()

绘制塔架

把圆盘变簿(高度换成厚度),再加一条粗直线(直线的宽度等于圆盘的厚度)表示出“竖杆”,就画出叠放的架子来:

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)

代码:

import pyglet
window = pyglet.window.Window(800, 500, caption='汉诺塔')
pyglet.gl.glClearColor(1, 1, 1, 1)
batch = pyglet.graphics.Batch()
pi = 3.141592653589793
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.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>height and x-width/2+height/2>0)
class Hann:
    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.event
def on_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()

叠加圆盘

把多个圆盘叠加磊在塔架上,圆盘数至少为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 = []
for i in range(order):
    self.coordinates.append([self.x, self.y+(i+1)*self.height-(self.height-thickness)/2])

代码:

import pyglet
window = pyglet.window.Window(800, 500, caption='汉诺塔')
pyglet.gl.glClearColor(1, 1, 1, 1)
batch = pyglet.graphics.Batch()
pi = 3.141592653589793
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.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>height and x-width/2+height/2>0)
class Hann:
    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, y
        self.width = width
        self.height = (height-thickness*2)/order
        self.step = (width-thickness)/(order+1)
        self.beads = []
        self.coordinates = []
        for i in range(order):
            self.coordinates.append([self.x, self.y+(i+1)*self.height-(self.height-thickness)/2])
        self.fillup()
    def fillup(self):
        for i,xy in enumerate(self.coordinates):
            self.beads.append(Disk(*xy, Color[i%8+1], width=self.width-i*self.step, height=self.height))
@window.event
def on_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()

游戏框架

画三个相同的塔架,左边的磊放好圆盘。另外用两个圆代替两个扇形,效果一样却省了pi常量。

Circle(x+width/2-height/2, y, radius=height/2, 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)
        assert(width>height and x-width/2+height/2>0)
class Hann:
    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, y
        self.width = width
        self.height = (height-thickness*2)/order
        self.step = (width-thickness)/(order+1)
        self.beads = []
        self.coordinates = []
        for i in range(order):
            self.coordinates.append([self.x, self.y+(i+1)*self.height-(self.height-thickness)/2])
    def fillup(self):
        for i,xy in enumerate(self.coordinates):
            self.beads.append(Disk(*xy, Color[i%8+1], width=self.width-i*self.step, height=self.height))
class Game:
    def __init__(self, x, y, order=2, space=250):
        self.x, self.y = x, y
        self.space = space
        self.order = order
        self.hanns = Hann(x-space, y, order), Hann(x, y, order), Hann(x+space, y, order)
        self.hanns[0].fillup()
@window.event
def on_draw():
    window.clear()
    batch.draw()
hann = Game(window.width/2, 100, 8)
pyglet.app.run()

接下来就要添加鼠标和键盘事件,用于操作在塔架上移动圆盘。

以上就是Python使用pyglet库完整实现汉诺塔游戏流程详解的详细内容,更多关于Python pyglet汉诺塔的资料请关注脚本之家其它相关文章!

相关文章

  • 使用TensorFlow实现二分类的方法示例

    使用TensorFlow实现二分类的方法示例

    这篇文章主要介绍了使用TensorFlow实现二分类的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-02-02
  • python strip() 函数和 split() 函数的详解及实例

    python strip() 函数和 split() 函数的详解及实例

    这篇文章主要介绍了 python strip() 函数和 split() 函数的详解及实例的相关资料,需要的朋友可以参考下
    2017-02-02
  • 上手简单,功能强大的Python爬虫框架——feapder

    上手简单,功能强大的Python爬虫框架——feapder

    这篇文章主要介绍了上手简单,功能强大的Python爬虫框架——feapder的使用教程,帮助大家更好的利用python进行爬虫,感兴趣的朋友可以了解下
    2021-04-04
  • Python中实现变量赋值传递时的引用和拷贝方法

    Python中实现变量赋值传递时的引用和拷贝方法

    下面小编就为大家分享一篇Python中实现变量赋值传递时的引用和拷贝方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-04-04
  • 新手入门Python编程的8个实用建议

    新手入门Python编程的8个实用建议

    这篇文章主要介绍了Python编程的8个实用建议,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • Python中使用 zipfile创建文件压缩工具

    Python中使用 zipfile创建文件压缩工具

    这篇文章主要介绍了Python中使用zipfile创建文件压缩工具,通过使用 wxPython 模块,我们创建了一个简单而实用的文件压缩工具,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的ca参考借鉴价值,需要的朋友可以参考下
    2023-09-09
  • python中匿名函数的应用方法

    python中匿名函数的应用方法

    这篇文章主要介绍了python中匿名函数的应用方法,匿名函数是无需使用def定义的函数,只需使用关键字lambda进行声明,且只可使用一次,只有一个返回值,需要的朋友可以参考下
    2023-07-07
  • Python Coroutine池化的实现详解

    Python Coroutine池化的实现详解

    在当今计算机科学和软件工程的领域中,池化技术如线程池、连接池和对象池等已经成为优化资源利用率和提高软件性能的重要工具,所以下面我们就来看看Coroutine池化的具体实现吧
    2024-01-01
  • python3 线性回归验证方法

    python3 线性回归验证方法

    今天小编就为大家分享一篇python3 线性回归验证方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • 利用Python检测URL状态

    利用Python检测URL状态

    最近小编接到这样的需求,Python检测URL状态,并追加保存200的URL。接下来通过实例代码给大家分析讲解,需要的朋友跟随小编一起看看吧
    2019-07-07

最新评论