首页 > Python资料 博客日记
Python 一步一步教你用pyglet制作汉诺塔游戏
2024-03-12 21:00:04Python资料围观138次
目录
汉诺塔游戏
汉诺塔(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()
接下来就要添加鼠标和键盘事件,用于操作在塔架上移动圆盘。本篇完,下期继续......
标签:
相关文章
最新发布
- 【Python】selenium安装+Microsoft Edge驱动器下载配置流程
- Python 中自动打开网页并点击[自动化脚本],Selenium
- Anaconda基础使用
- 【Python】成功解决 TypeError: ‘<‘ not supported between instances of ‘str’ and ‘int’
- manim边学边做--三维的点和线
- CPython是最常用的Python解释器之一,也是Python官方实现。它是用C语言编写的,旨在提供一个高效且易于使用的Python解释器。
- Anaconda安装配置Jupyter(2024最新版)
- Python中读取Excel最快的几种方法!
- Python某城市美食商家爬虫数据可视化分析和推荐查询系统毕业设计论文开题报告
- 如何使用 Python 批量检测和转换 JSONL 文件编码为 UTF-8
点击排行
- 版本匹配指南:Numpy版本和Python版本的对应关系
- 版本匹配指南:PyTorch版本、torchvision 版本和Python版本的对应关系
- Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO
- 相关性分析——Pearson相关系数+热力图(附data和Python完整代码)
- Python与PyTorch的版本对应
- Anaconda版本和Python版本对应关系(持续更新...)
- Python pyinstaller打包exe最完整教程
- Could not build wheels for llama-cpp-python, which is required to install pyproject.toml-based proj