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

news2024/11/18 11:37:19

目录

汉诺塔游戏

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【深度学习笔记】7_2 梯度下降和随机梯度下降

注:本文为《动手学深度学习》开源内容,部分标注了个人理解,仅为个人学习记录,无抄袭搬运意图 7.2 梯度下降和随机梯度下降 在本节中,我们将介绍梯度下降(gradient descent)的工作原理。虽然梯度…

Vue 监听器:让你的应用实时响应变化

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Kibana二次开发环境搭建

1 kibana环境搭建 1.1 搭建后端服务 (1)java环境安装 ElasticSearch运行需要java jdk支持。所以要先安装JAVA环境。由于ElasticSearch 5.x 往后依赖于JDK 1.8的,所以现在我们下载JDK 1.8或者更高版本。下载JDK1.8,下载完成后安装&#xff…

计算机设计大赛 疲劳驾驶检测系统 python

文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.2 打哈欠检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 🔥 优质竞赛项目系列&#x…

ai+模型选择+过拟合和欠拟合

ai模型选择过拟合和欠拟合 1模型选择1训练误差和泛化误差2验证数据集和测试数据集3k-折交叉验证4总结 2过拟合和欠拟合1模型容量2估计模型容量3VC维4数据复杂度5总结 3代码 1模型选择 1训练误差和泛化误差 训练误差(Training Error)和泛化误差&#xff…

STM32(19)I2C模块 主机发数据

发送数据: 等待空闲: 发送起始位: 发送地址: 发送数据:

day16_购物车(添加购物车,购物车列表查询,删除购物车商品,更新选中商品状态,完成购物车商品的全选,清空购物车)

文章目录 购物车模块1 需求说明2 环境搭建3 添加购物车3.1 需求说明3.2 远程调用接口开发3.2.1 ProductController3.2.2 ProductService 3.3 openFeign接口定义3.3.1 环境搭建3.3.2 接口定义3.3.3 降级类定义 3.4 业务后端接口开发3.4.1 添加依赖3.4.2 修改启动类3.4.3 CartInf…

Docker:部署微服务集群

1. 部署微服务集群 实现思路: ① 查看课前资料提供的cloud-demo文件夹,里面已经编写好了docker-compose文件 ② 修改自己的cloud-demo项目,将数据库、nacos地址都命名为docker-compose中的服务名 ③ 使用maven打包工具,将项目…

linux信号的概念

目录 1.预备 2.信号如何产生 1.引入 2.原理 3.总结 3.接口 1.singal函数 2.kill函数 3.raise函数(给自己发信号) 4.abort函数(给自己发送6号信号) 4.异常 1.现象 2.原理 5.core和term区别 6.由软件条件产生信号 3.…

P8661 [蓝桥杯 2018 省 B] 日志统计

[P8661 蓝桥杯 2018 省 B] 日志统计 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路:双指针,对日志按时间从小到大进行排序。快指针指向的 i d id id点赞数加一,快慢指针做差得到之间的时间间隔,大于等于 k k k将慢指针指向…

preg_replace漏洞e模式函数执行

关于PHP函数preg_replace \e 模式函数执行漏洞 preg_replace: ​ 该函数执行一个正则表达式的搜索和替换。 ​ 语法: mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit -1 [, int &$count ]] )​ 搜索…

摘花生c++

题目 Hello Kitty想摘点花生送给她喜欢的米老鼠。 她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。 地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的…

【海贼王的数据航海:利用数据结构成为数据海洋的霸主】探究二叉树的奥秘

目录 1 -> 树的概念及结构 1.1 -> 树的概念 1.2 -> 树的相关概念 1.3 -> 树的表示 1.4 -> 树在实际中的运用(表示文件系统的目录树结构) 2 -> 二叉树概念及结构 2.1 -> 二叉树的概念 2.2 -> 现实中的二叉树 2.3 -> 特殊的二叉树 2.4 ->…

【软考】单元测试

目录 1. 概念2. 测试内容2.1 说明2.2 模块接口2.3 局部数据结构2.4 重要的执行路径 3. 测试过程2.1 说明2.2 单元测试环境图2.3 驱动模块2.4 桩模块 4. 模块接口测试与局部数据结构测试的区别 1. 概念 1.单元测试也称为模块测试,在模块编写完成且无编译错误后就可以…

数据库(mysql)-新手笔记(主外键,视图)

数据库基本知识点- http://t.csdnimg.cn/CVa9e 主外键 主键(唯一性,非空性) 主键是数据库表中的一个或多个字段,其值唯一标识表中的每一行/记录。 唯一性: 主键字段中的每个值都必须是唯一的,不能有两个或更多的记录具有相同的主键值 非空性&#x…

Ajax (1)

什么是Ajax&#xff1a; 浏览器与服务器进行数据通讯的技术&#xff0c;动态数据交互 axios库地址&#xff1a; <script src"https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> 如何使用呢&#xff1f; 我们现有个感性的认识 <scr…

【Python-Docx库】Word与Python的完美结合

今天给大家分享Python处理Word的第三方库&#xff1a;Python-Docx。 什么是Python-Docx&#xff1f; Python-Docx是用于创建和更新Microsoft Word&#xff08;.docx&#xff09;文件的Python库。 日常需要经常处理Word文档&#xff0c;用Python的免费第三方包&#xff1a;Pyt…

【自制操作系统】系统启动流程,工具使用和启动区的制作

&#x1f4dd;本文介绍 本文主要从系统系统的启动流程开始&#xff0c;中间介绍一些所用工具的使用方法&#xff0c;最后将完成一个启动区的制作。此次的启动区只涉及到汇编代码。 &#x1f44b;作者简介&#xff1a;一个正在积极探索的本科生 &#x1f4f1;联系方式&#xff1…

《MySQL实战45讲》课程大纲

1MySQL实战45讲-01基础架构&#xff1a;一条SQL查询语句是如何执行的&#xff1f;2MySQL实战45讲-02日志系统&#xff1a;一条SQL更新语句是如何执行的&#xff1f;3MySQL实战45讲-03事务隔离&#xff1a;为什么你改了我还看不见&#xff1f;4MySQL实战45讲-04深入浅出索引&…

vue3 ref获取子组件显示 __v_skip : true 获取不到组件的方法 怎么回事怎么解决

看代码 问题出现了 当我想要获取这个组件上的方法时 为什么获取不到这个组件上的方法呢 原來&#xff1a; __v_skip: true 是 Vue 3 中的一个特殊属性&#xff0c;用于跳过某些组件的渲染。当一个组件被标记为 __v_skip: true 时&#xff0c;Vue 将不会对该组件进行渲染&am…