?
目錄
漢諾塔游戲
完整游戲
后期展望
漢諾塔游戲
漢諾塔(Tower of Hanoi),是一個(gè)源于印度古老傳說的益智玩具。這個(gè)傳說講述了大梵天創(chuàng)造世界的時(shí)候,他做了三根金剛石柱子,并在其中一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門將這些圓盤從下面開始按大小順序重新擺放在另一根柱子上,并規(guī)定在小圓盤上不能放大圓盤,同時(shí)在三根柱子之間一次只能移動(dòng)一個(gè)圓盤。當(dāng)盤子的數(shù)量增加時(shí),移動(dòng)步驟的數(shù)量會(huì)呈指數(shù)級增長,圓盤數(shù)為n時(shí),總步驟數(shù)steps為2^n - 1。
n = 64, steps = 2^64 - 1 = 18446744073709551616 ≈ 1.845 x 10^19
漢諾塔問題是一個(gè)遞歸問題,也可以使用非遞歸法來解決,例如使用棧來模擬遞歸過程。這個(gè)問題不僅是一個(gè)數(shù)學(xué)和邏輯問題,也是一個(gè)很好的教學(xué)工具,可以用來教授遞歸、算法和邏輯思考等概念。同時(shí),漢諾塔游戲也具有一定的娛樂性,人們可以通過解決不同規(guī)模的漢諾塔問題來挑戰(zhàn)自己的智力和耐心。
本篇接著上期講下去,前2篇的鏈接地址:
Python 一步一步教你用pyglet制作漢諾塔游戲(續(xù))-CSDN博客
Python 一步一步教你用pyglet制作漢諾塔游戲-CSDN博客
完整游戲
前2期代碼的基礎(chǔ)上,添加了完整的提示功能,一個(gè)漢諾塔游戲作品終于完工了,效果如下:
信息提示功能都放在了鼠標(biāo)事件中:
@window.event
def on_mouse_press(x, y, dx, dy):
? ? global xy, hanns, gamecompleted
? ? if not hanns.success():
? ? ? ? pole = hanns.on_mouse_over(x, y)
? ? ? ? if pole is not None:
? ? ? ? ? ? xy.append(pole)
? ? ? ? ? ? if len(xy)==1:
? ? ? ? ? ? ? ? hanns.setdiskcolor(xy[0], (255,0,0))
? ? ? ? ? ? ? ? if not hanns.array[pole]:
? ? ? ? ? ? ? ? ? ? hanns.setdiskcolor(xy[0])
? ? ? ? ? ? ? ? ? ? xy.pop()
? ? ? ? ? ? ? ? ? ? return
? ? ? ? if len(xy)==2:
? ? ? ? ? ? if xy[0]!=xy[1]:
? ? ? ? ? ? ? ? info = hanns.move(*xy)
? ? ? ? ? ? ? ? hanns.setdiskcolor(xy[0])
? ? ? ? ? ? ? ? if info is False:
? ? ? ? ? ? ? ? ? ? info1.text = '起始圓盤大于目標(biāo)位置的圓盤'
? ? ? ? ? ? ? ? elif info is None:
? ? ? ? ? ? ? ? ? ? info1.text = '所選起始位置的塔架不能為空'
? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? info1.text = f'{hanns.order-hanns.array[xy[1]][-1]}號圓盤從{xy[0]+1}號塔架移動(dòng)到{xy[1]+1}號塔架'
? ? ? ? ? ? hanns.setdiskcolor(xy[0])
? ? ? ? ? ? xy.clear()
? ? ? ? ? ? info2.text = f'當(dāng)前層數(shù):{hanns.order}\t最佳步數(shù):{2**hanns.order-1}\t當(dāng)前步數(shù):{hanns.steps}'
? ? ? ? if hanns.success():
? ? ? ? ? ? if hanns.order<24:
? ? ? ? ? ? ? ? info1.text = f'恭喜您完成 {hanns.order} 層漢諾塔!任意點(diǎn)擊層數(shù)加一!'
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? info1.text = f'太棒了!您已完成 {hanns.order} 層漢諾塔,游戲結(jié)束!'
? ? ? ? ? ? ? ? gamecompleted = True
? ? ? ? ? ? ? ? return
? ? elif not gamecompleted:
? ? ? ? hanns = Hann(window.width/2, 120, hanns.order+1)
? ? ? ? info1.text = f' {hanns.order} 層漢諾塔,游戲開始!'
? ? ? ? info2.text = f'當(dāng)前層數(shù):{hanns.order}\t最佳步數(shù):{2**hanns.order-1}\t當(dāng)前步數(shù):{hanns.steps}'
Hann 類中增加一個(gè)改色的方法,用于標(biāo)注被點(diǎn)擊的要移動(dòng)的源塔架:
? def setdiskcolor(self, n, color=Color[0]):
? ? ? ? self.disk[n].cir1.color = color
? ? ? ? self.disk[n].cir2.color = color
? ? ? ? self.disk[n].rect.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)
def move(self, dx, dy):
self.cir1.x += dx; self.cir1.y += dy
self.cir2.x += dx; self.cir2.y += dy
self.rect.x += dx; self.rect.y += dy
class Hann:
def __init__(self, x, y, order=2, space=250, thickness=20, width=200, height=300):
assert(order>1)
self.pole = [pyglet.shapes.Line(x-i*space, y, x-i*space, y+height, width=thickness, color=Color[0], batch=batch) for i in range(-1,2)]
self.disk = [Disk(x+i*space, y, color=Color[0], width=width+thickness, height=thickness) for i in range(-1,2)]
self.x, self.y = x, y
self.order = order
self.space = space
self.thickness = thickness
self.width = width
self.poleheight = height
self.beadheight = (height-thickness*2)/order
self.step = (width-thickness)/(order+1)
self.steps = 0
self.macro = []
coordinates = [(self.x-space, self.y+(i+1)*self.beadheight-(self.beadheight-thickness)/2) for i in range(order)]
self.beads = [Disk(*xy, Color[i%8+1], width=self.width-i*self.step, height=self.beadheight) for i,xy in enumerate(coordinates)]
self.array = [[*range(order)], [], []]
def move(self, pole1, pole2):
if self.array[pole1]:
bead = self.array[pole1].pop()
if self.array[pole2] and bead<self.array[pole2][-1]:
self.array[pole1].append(bead)
return False
else:
return None
self.beads[bead].move((pole2-pole1)*self.space, (len(self.array[pole2])-len(self.array[pole1]))*self.beadheight)
self.array[pole2].append(bead)
self.steps += 1
self.macro.append((pole1, pole2))
return True
def setdiskcolor(self, n, color=Color[0]):
self.disk[n].cir1.color = color
self.disk[n].cir2.color = color
self.disk[n].rect.color = color
def on_mouse_over(self, x, y):
for i in range(-1,2):
if hanns.x-hanns.width/2 < x-i*hanns.space < hanns.x+hanns.width/2 and hanns.y-hanns.thickness/2 < y < hanns.y+hanns.poleheight:
return i+1
def success(self):
return len(self.array[2]) == self.order
@window.event
def on_draw():
window.clear()
batch.draw()
@window.event
def on_mouse_press(x, y, dx, dy):
global xy, hanns, gamecompleted
if not hanns.success():
pole = hanns.on_mouse_over(x, y)
if pole is not None:
xy.append(pole)
if len(xy)==1:
hanns.setdiskcolor(xy[0], (255,0,0))
if not hanns.array[pole]:
hanns.setdiskcolor(xy[0])
xy.pop()
return
if len(xy)==2:
if xy[0]!=xy[1]:
info = hanns.move(*xy)
hanns.setdiskcolor(xy[0])
if info is False:
info1.text = '起始圓盤大于目標(biāo)位置的圓盤'
elif info is None:
info1.text = '所選起始位置的塔架不能為空'
else:
info1.text = f'{hanns.order-hanns.array[xy[1]][-1]}號圓盤從{xy[0]+1}號塔架移動(dòng)到{xy[1]+1}號塔架'
hanns.setdiskcolor(xy[0])
xy.clear()
info2.text = f'當(dāng)前層數(shù):{hanns.order}\t最佳步數(shù):{2**hanns.order-1}\t當(dāng)前步數(shù):{hanns.steps}'
if hanns.success():
if hanns.order<24:
info1.text = f'恭喜您完成 {hanns.order} 層漢諾塔!任意點(diǎn)擊層數(shù)加一!'
else:
info1.text = f'太棒了!您已完成 {hanns.order} 層漢諾塔,游戲結(jié)束!'
gamecompleted = True
return
elif not gamecompleted:
hanns = Hann(window.width/2, 120, hanns.order+1)
info1.text = f' {hanns.order} 層漢諾塔,游戲開始!'
info2.text = f'當(dāng)前層數(shù):{hanns.order}\t最佳步數(shù):{2**hanns.order-1}\t當(dāng)前步數(shù):{hanns.steps}'
xy = []
order = 2
hanns = Hann(window.width/2, 120, order)
info1 = pyglet.text.Label('操作方法:鼠標(biāo)先后點(diǎn)擊起始和目標(biāo)位置就能移動(dòng)圓盤', font_size=21, color=(0,0,0,255), x=window.width/2, y=50, anchor_x='center', batch=batch)
info2 = pyglet.text.Label(f'當(dāng)前層數(shù):{order}\t最佳步數(shù):{2**order-1}\t當(dāng)前步數(shù):0', font_size=18, color=(0,0,0,255), x=80, y=450, batch=batch)
gamecompleted = False
pyglet.app.run()
后期展望
之后有空再優(yōu)化一下代碼,再添加上音效、回放等功能,游戲效果會(huì)理想些。還能把上期的自動(dòng)演示功能也加進(jìn)去,就更加完美了。
本文完,以下僅為湊字?jǐn)?shù),請忽略:
自動(dòng)演示功能,即把以下遞歸函數(shù)的結(jié)果展現(xiàn)出來即可:
def hanoi(n, start, mid, end, moves=None):
? ? if moves is None:
? ? ? ? moves = []
? ? if n == 1:
? ? ? ? moves.append((start, end))
? ? else:
? ? ? ? hanoi(n-1, start, end, mid, moves)
? ? ? ? moves.append((start, end))
? ? ? ? hanoi(n-1, mid, start, end, moves)
? ? return moves
?
for order in (4,7,8):
? ? moves = hanoi(order, 0, 1, 2)
? ? print(len(moves)==2**order-1)
? ? print(moves)
運(yùn)行結(jié)果:文章來源:http://www.zghlxwxcb.cn/news/detail-840218.html
True
[(0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2)]
True
[(0, 2), (0, 1), (2, 1), (0, 2), (1, 0), (1, 2), (0, 2), (0, 1), (2, 1), (2, 0), (1, 0), (2, 1), (0, 2), (0, 1), (2, 1), (0, 2), (1, 0), (1, 2), (0, 2), (1, 0), (2, 1), (2, 0), (1, 0), (1, 2), (0, 2), (0, 1), (2, 1), (0, 2), (1, 0), (1, 2), (0, 2), (0, 1), (2, 1), (2, 0), (1, 0), (2, 1), (0, 2), (0, 1), (2, 1), (2, 0), (1, 0), (1, 2), (0, 2), (1, 0), (2, 1), (2, 0), (1, 0), (2, 1), (0, 2), (0, 1), (2, 1), (0, 2), (1, 0), (1, 2), (0, 2), (0, 1), (2, 1), (2, 0), (1, 0), (2, 1), (0, 2), (0, 1), (2, 1), (0, 2), (1, 0), (1, 2), (0, 2), (1, 0), (2, 1), (2, 0), (1, 0), (1, 2), (0, 2), (0, 1), (2, 1), (0, 2), (1, 0), (1, 2), (0, 2), (1, 0), (2, 1), (2, 0), (1, 0), (2, 1), (0, 2), (0, 1), (2, 1), (2, 0), (1, 0), (1, 2), (0, 2), (1, 0), (2, 1), (2, 0), (1, 0), (1, 2), (0, 2), (0, 1), (2, 1), (0, 2), (1, 0), (1, 2), (0, 2), (0, 1), (2, 1), (2, 0), (1, 0), (2, 1), (0, 2), (0, 1), (2, 1), (0, 2), (1, 0), (1, 2), (0, 2), (1, 0), (2, 1), (2, 0), (1, 0), (1, 2), (0, 2), (0, 1), (2, 1), (0, 2), (1, 0), (1, 2), (0, 2)]
True
[(0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (2, 1), (0, 1), (2, 0), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2), (0, 1), (2, 0), (2, 1), (0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (1, 2), (0, 1), (0, 2), (1, 2)]文章來源地址http://www.zghlxwxcb.cn/news/detail-840218.html
到了這里,關(guān)于Python 一步一步教你用pyglet制作漢諾塔游戲(終篇)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!