Python 一步一步教你用pyglet制作汉诺塔游戏

目录

汉诺塔游戏

1. 抓取颜色

2. 绘制圆盘

3. 九层汉塔

4. 绘制塔架

5. 叠加圆盘

6. 游戏框架


 

汉诺塔游戏

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

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

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

1. 抓取颜色

本篇将展示如何用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. 绘制圆盘

圆盘用矩形加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()

3. 九层汉塔

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

代码:

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()

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)

代码:

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()

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 = []
        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()

6. 游戏框架

画三个相同的塔架,左边的磊放好圆盘。另外用两个圆代替两个扇形,效果一样却省了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()

接下来就要添加鼠标和键盘事件,用于操作在塔架上移动圆盘。本篇完,下期继续......

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/445981.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【刷题】Leetcode 415 字符串相加 和 34 字符串相乘

刷题 Leetcode 415 字符串相加题目描述 思路一(模拟大法版!!!)Leetcode 34 字符串相乘题目描述 思路一(模拟大法版)Thanks♪(・ω・)ノ谢谢阅读!&…

Angular基础---HelloWorld---Day3

文章目录 0.ng-model 的几种不同的class属性1.ng-model 的引用与属性的调用2.表单验证: (模版引用变量、ngModel 、ngif一起使用)3.根据class属性的值ng-invalid ,设置动态变化的样式 0.ng-model 的几种不同的class属性 引用ng-model 元素的c…

2024年软件测试怎么自我提升?“我“该如何做?

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 1、掌握基本的测试…

【C#图解教程】笔记

文章目录 1. C#和.NET框架.NET框架的组成.NET框架的特点CLRCLICLI的重要组成部分各种缩写 2. C#编程概括标识符命名规则: 多重标记和值格式化数字字符串对齐说明符格式字段标准数字格式说明符标准数字格式说明符 表 3. 类型、存储和变量数据成员和函数成员预定义类型…

有什么针对新闻媒体行业的安全解决方案

对媒体行业而言,门户网站是最易受到攻击的地方。常见的攻击方式有网页篡改、挂马和被植入暗链等。门户网站作为新闻媒体对外的第一扇门,通常承载了大量的流量,一旦遭到攻击,造成的影响会更具有可怕的“传播力”。那么我们应该如何…

车载诊断协议DoIP系列 —— AL IPv6地址分配通用DoIP报头结构

车载诊断协议DoIP系列 —— AL IPv6地址分配&通用DoIP报头结构 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自…

Python栅格数据克里金插值

目录 结果输入文件核心代码 结果 输入文件 1、需要有经纬度信息以及对应的单点值 2、还要用到一个研究区的矢量文件,当然上面点的经纬度信息要在该矢量文件以内 核心代码 file_path workspace1# Attempt to read the Excel filedf readDataFile(file_path)dat…

vxe-table配合Export2Excel导出object类型数据{type,count}。表格数据呈现是利用插槽,导出只要count该怎么做

先贴一张数据来: 一、然后是vxe-grid的columns配置: 然后就正常用封装好的Export2Excel就行。 碰到一次在控制台报错: 没复现出来,大概就说是count咋样咋样。 以后碰到的话再说,各位要用的话也注意看看 二、或者 用js…

适配器模式已经在SpringMVC中的源码实现

介绍: 1、适配器模式将某个类的接口转换成客户端期望的另一种接口表示 2、目的:兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为:包装器。 3、属于:结构型模式 4、分3类:1&#xff0…

ESP8266开发板 + DHT11+远程开关+ThingsCloud+APP+QQ邮件推送告警

ESP32 是乐鑫公司推出的 WiFi 芯片,它不仅支持 WiFi 和 BLE,还可以作为可编程的 MCU,通过 Espressif IDF、Arduino 等框架编写固件,用于非常广泛的物联网场景。 这个教程我们分享如何在 Arduino IDE 中使用 ThingsCloud ESP SDK&…

ElasticSearch之排序,fielddata和docvalue

写在前面 es搜索返回结果的排序默认是按照得分的高低来排的,本文来看下如何按照字段来排序,实现类似于MySQL的order by xxx的效果。 1:什么是fileddata和doc_value 参考ElasticSearch之零碎知识点 和一文带你彻底弄懂ES中的doc_values和fi…

Igraph入门指南 5

2、graph_from系列,将其他R数据结构转换成图 2-1 邻接矩阵转图:graph_from_adjacency_matrix 可以接受Matrix包创建的稀疏矩阵作为参数 邻接矩阵中行的顺序被保留,并作为图中顶点的顺序。 本函数几个重要的参数: weighted&am…

【组合递归】【StringBuilder】Leetcode 17. 电话号码的字母组合

【组合递归】【StringBuilde】Leetcode 17. 电话号码的字母组合 StringBulider常用方法!!!!!!!!!!!!!!17. 电…

Java宝典-抽象类和接口

目录 1. 抽象类1.1 抽象类的概念1.2 抽象类的语法1.3 抽象类的特点 2. 接口2.1 接口的概念2.2 接口的语法2.3 接口的特点2.4 实现多个接口2.5 接口的继承 3. 接口使用案例 铁汁们好,今天我们学习抽象类和接口~ 1. 抽象类 1.1 抽象类的概念 什么是抽象类?在面向对象中,如果一…

【Leetcode】top 100 双指针

283 移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 分析:双指针初始为0;left指针找零值,right指针找非零值;由于需要保持非零元素的相对顺序&#xff0c…

02-组件化编程与Vu额 Click脚手架

1.Vue组件化编程(只有1个数字是一级标题) 1.1 模块与组件、模块化与组件化(两个数字组成是二级标题) 1.1.1模块(三个数字是三级标题 依次类推) 理解:向外提供特定功能的 js 程序,一般就是一个 js 文件为什么:js 文件很多很复杂作用&#xf…

【性能测试】性能测试各知识第1篇:性能测试大纲【附代码文档】

性能测试完整教程(附代码资料)主要内容讲述:性能测试大纲。。。。。。。。。。。。。。 全套笔记资料代码移步: 前往gitee仓库查看 感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~ 性能测试大纲 |序号|阶段|概述| |--…

【C++】三大特性之继承

1 继承的概念及定义 1.1 继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展、增加功能,这样产生新的类,称派生类(或子类)。而被继承的…

【NR 定位】3GPP NR Positioning 5G定位标准解读(九)-增强的小区ID定位

前言 3GPP NR Positioning 5G定位标准:3GPP TS 38.305 V18 3GPP 标准网址:Directory Listing /ftp/ 【NR 定位】3GPP NR Positioning 5G定位标准解读(一)-CSDN博客 【NR 定位】3GPP NR Positioning 5G定位标准解读(…

云服务器python版本冲突解决(awd平台搭建)

文章目录 yum和apt-getdockerpython环境问题 大家在使用python时,难免会使用他人的代码,自己是python3,而别人的是python2.我们直接运行会报错(比如print函数括号的问题)。但是去修改代码又很麻烦。这里给大家推荐conda。我以我搭建awd平台为…