Python使用pyglet庫(kù)完整實(shí)現(xiàn)漢諾塔游戲流程詳解
前言
漢諾塔(Tower of Hanoi),是一個(gè)源于印度古老傳說(shuō)的益智玩具。這個(gè)傳說(shuō)講述了大梵天創(chuàng)造世界的時(shí)候,他做了三根金剛石柱子,并在其中一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門將這些圓盤從下面開(kāi)始按大小順序重新擺放在另一根柱子上,并規(guī)定在小圓盤上不能放大圓盤,同時(shí)在三根柱子之間一次只能移動(dòng)一個(gè)圓盤。當(dāng)盤子的數(shù)量增加時(shí),移動(dòng)步驟的數(shù)量會(huì)呈指數(shù)級(jí)增長(zhǎng),圓盤數(shù)為n時(shí),總步驟數(shù)steps為2^n - 1。
n = 64, steps = 2^64 - 1 = 18446744073709551616 ≈ 1.845 x 10^19
漢諾塔問(wèn)題是一個(gè)遞歸問(wèn)題,也可以使用非遞歸法來(lái)解決,例如使用棧來(lái)模擬遞歸過(guò)程。這個(gè)問(wèn)題不僅是一個(gè)數(shù)學(xué)和邏輯問(wèn)題,也是一個(gè)很好的教學(xué)工具,可以用來(lái)教授遞歸、算法和邏輯思考等概念。同時(shí),漢諾塔游戲也具有一定的娛樂(lè)性,人們可以通過(guò)解決不同規(guī)模的漢諾塔問(wèn)題來(lái)挑戰(zhàn)自己的智力和耐心。
抓取顏色
本篇將展示如何用python pyglet庫(kù)制作這個(gè)小游戲,首先在上圖中抓取出需要用到的顏色RGB值,每種顏色畫一個(gè)矩形塊:
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個(gè)半圓表示,半圓用扇形控件繪制:
Sector(x,y, radius=R, angle=pi, start_angle=-pi/2, color=color)
注意圓盤類中的矩形的寬度和坐標(biāo)需要調(diào)整,整個(gè)圓盤類的寬度是矩形寬度加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()
九層漢塔
疊加多個(gè)圓盤,繪制出漢諾塔的樣子:
代碼:
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()
繪制塔架
把圓盤變簿(高度換成厚度),再加一條粗直線(直線的寬度等于圓盤的厚度)表示出“豎桿”,就畫出疊放的架子來(lái):
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()
疊加圓盤
把多個(gè)圓盤疊加磊在塔架上,圓盤數(shù)至少為2。 注意Color顏色列表共有9種顏色,Color[i%8+1]只取后8種顏色,Color[0]僅用于塔架的涂色。
Hann類中各控件的坐標(biāo)計(jì)算有點(diǎn)復(fù)雜,以下方案可以解決問(wèn)題但未必是最佳方案:
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()
游戲框架
畫三個(gè)相同的塔架,左邊的磊放好圓盤。另外用兩個(gè)圓代替兩個(gè)扇形,效果一樣卻省了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()
接下來(lái)就要添加鼠標(biāo)和鍵盤事件,用于操作在塔架上移動(dòng)圓盤。
以上就是Python使用pyglet庫(kù)完整實(shí)現(xiàn)漢諾塔游戲流程詳解的詳細(xì)內(nèi)容,更多關(guān)于Python pyglet漢諾塔的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python Web開(kāi)發(fā)你要理解的WSGI & uwsgi詳解
這篇文章主要給大家介紹了關(guān)于python Web開(kāi)發(fā)你一定要理解的WSGI & uwsgi的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08Pytorch實(shí)現(xiàn)簡(jiǎn)單自定義網(wǎng)絡(luò)層的方法
這篇文章主要給大家介紹了關(guān)于Pytorch實(shí)現(xiàn)簡(jiǎn)單自定義網(wǎng)絡(luò)層的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-05-05將Django項(xiàng)目部署到CentOs服務(wù)器中
今天小編就為大家分享一篇關(guān)于將Django項(xiàng)目部署到CentOs服務(wù)器中的文章,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10Python?from?import導(dǎo)包ModuleNotFoundError?No?module?named
最近在執(zhí)行python腳本時(shí),from?import的模塊沒(méi)有被加載進(jìn)來(lái),找不到module,這篇文章主要給大家介紹了關(guān)于Python?from?import導(dǎo)包ModuleNotFoundError?No?module?named找不到模塊問(wèn)題的解決辦法,需要的朋友可以參考下2022-08-08Python實(shí)現(xiàn)字符串與數(shù)組相互轉(zhuǎn)換功能示例
這篇文章主要介紹了Python實(shí)現(xiàn)字符串與數(shù)組相互轉(zhuǎn)換功能,結(jié)合具體實(shí)例形式分析了Python字符串與數(shù)組相關(guān)轉(zhuǎn)換功能的相關(guān)實(shí)現(xiàn)技巧與注意事項(xiàng),需要的朋友可以參考下2017-09-09python中24小時(shí)制轉(zhuǎn)換為12小時(shí)制的方法
最近需要實(shí)現(xiàn)一個(gè)需求,求用戶輸入24小時(shí)制的時(shí)間,然后顯示12小時(shí)制的時(shí)間。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06Python使用Web框架Flask開(kāi)發(fā)項(xiàng)目
本文詳細(xì)講解了Python使用Web框架Flask開(kāi)發(fā)項(xiàng)目的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05Python實(shí)現(xiàn)模擬時(shí)鐘代碼推薦
本文給大家匯總介紹了下使用Python實(shí)現(xiàn)模擬時(shí)鐘的代碼,一共3個(gè)例子,后兩個(gè)是基于QT實(shí)現(xiàn),有需要的小伙伴可以參考下2015-11-11Python中os.system()、subprocess.run()、call()、check_output()的使用
這篇文章主要介紹了Python中os.system()、subprocess.run()、call()、check_output()的使用案例,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07python3實(shí)現(xiàn)猜數(shù)字游戲
這篇文章主要為大家詳細(xì)介紹了python3實(shí)現(xiàn)猜數(shù)字游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06