您现在的位置是:首页 > 技术教程 正文

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

admin 阅读: 2024-03-25
后台-插件-广告管理-内容页头部广告(手机)

目录

汉诺塔游戏

7. 汉诺塔类

8. 移动圆盘

9. 移动演示

10. 递归问题

11. 任意展示

12. 鼠标操作


汉诺塔游戏

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

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

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

本篇接着上期讲下去,这次争取把圆盘移动起来,前篇的链接地址:

Python 一步一步教你用pyglet制作汉诺塔游戏-CSDN博客

7. 汉诺塔类

前篇的最后已经初步把汉诺塔的架子搭好了,可以显示但移动的描述很复杂。所以得改造一下,把三个塔架设计到一个类中,方便圆盘的移动,运行后效果不变:

代码:

  1. import pyglet
  2. window = pyglet.window.Window(800, 500, caption='汉诺塔')
  3. pyglet.gl.glClearColor(1, 1, 1, 1)
  4. batch = pyglet.graphics.Batch()
  5. 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)
  6. class Disk:
  7. def __init__(self, x, y, color=(0,0,0), width=200, height=20):
  8. self.cir1 = pyglet.shapes.Circle(x+width/2-height/2, y, radius=height/2, color=color, batch=batch)
  9. self.cir2 = pyglet.shapes.Circle(x-width/2+height/2, y, radius=height/2, color=color, batch=batch)
  10. self.rect = pyglet.shapes.Rectangle(x-width/2+height/2, y-height/2, width-height, height, color=color, batch=batch)
  11. class Hann:
  12. def __init__(self, x, y, order=2, space=250, thickness=20, width=200, height=300):
  13. assert(order>1)
  14. 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)]
  15. self.disk = [Disk(x+i*space, y, color=Color[0], width=width+thickness, height=thickness) for i in range(-1,2)]
  16. self.x, self.y = x, y
  17. self.order = order
  18. self.space = space
  19. self.thickness = thickness
  20. self.width = width
  21. self.height = (height-thickness*2)/order
  22. self.step = (width-thickness)/(order+1)
  23. coordinates = [(self.x-space, self.y+(i+1)*self.height-(self.height-thickness)/2) for i in range(order)]
  24. self.beads = [Disk(*xy, Color[i%8+1], width=self.width-i*self.step, height=self.height) for i,xy in enumerate(coordinates)]
  25. @window.event
  26. def on_draw():
  27. window.clear()
  28. batch.draw()
  29. hann = Hann(window.width/2, 120, 8)
  30. pyglet.app.run()

8. 移动圆盘

给圆盘类和汉诺塔类各设计一个.move()方法,主旨思想是圆盘的相对位置移动,不需要在调用时计算各种控件的具体坐标值。

代码:

  1. import pyglet
  2. window = pyglet.window.Window(800, 500, caption='汉诺塔')
  3. pyglet.gl.glClearColor(1, 1, 1, 1)
  4. batch = pyglet.graphics.Batch()
  5. 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)
  6. class Disk:
  7. def __init__(self, x, y, color=(0,0,0), width=200, height=20):
  8. self.cir1 = pyglet.shapes.Circle(x+width/2-height/2, y, radius=height/2, color=color, batch=batch)
  9. self.cir2 = pyglet.shapes.Circle(x-width/2+height/2, y, radius=height/2, color=color, batch=batch)
  10. self.rect = pyglet.shapes.Rectangle(x-width/2+height/2, y-height/2, width-height, height, color=color, batch=batch)
  11. def move(self, dx, dy):
  12. self.cir1.x += dx; self.cir1.y += dy
  13. self.cir2.x += dx; self.cir2.y += dy
  14. self.rect.x += dx; self.rect.y += dy
  15. class Hann:
  16. def __init__(self, x, y, order=2, space=250, thickness=20, width=200, height=300):
  17. assert(order>1)
  18. 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)]
  19. self.disk = [Disk(x+i*space, y, color=Color[0], width=width+thickness, height=thickness) for i in range(-1,2)]
  20. self.x, self.y = x, y
  21. self.order = order
  22. self.space = space
  23. self.thickness = thickness
  24. self.width = width
  25. self.height = (height-thickness*2)/order
  26. self.step = (width-thickness)/(order+1)
  27. coordinates = [(self.x-space, self.y+(i+1)*self.height-(self.height-thickness)/2) for i in range(order)]
  28. self.beads = [Disk(*xy, Color[i%8+1], width=self.width-i*self.step, height=self.height) for i,xy in enumerate(coordinates)]
  29. self.array = [[*range(order)], [], []]
  30. def move(self, pole1, pole2):
  31. if self.array[pole1]:
  32. bead = self.array[pole1].pop()
  33. if self.array[pole2] and bead1]:
  34. print('大盘不能搬到小盘上')
  35. return False
  36. else:
  37. print('所选择的塔架为空!')
  38. return None
  39. self.beads[bead].move((pole2-pole1)*self.space, (len(self.array[pole2])-len(self.array[pole1]))*self.height)
  40. self.array[pole2].append(bead)
  41. return True
  42. @window.event
  43. def on_draw():
  44. window.clear()
  45. batch.draw()
  46. hann = Hann(window.width/2, 100, 7)
  47. hann.move(0,1)
  48. hann.move(0,2)
  49. hann.move(1,2)
  50. hann.move(0,1)
  51. hann.move(2,0)
  52. hann.move(2,1)
  53. hann.move(0,1)
  54. hann.move(0,2)
  55. pyglet.app.run()

9. 移动演示

pyglet.clock.schedule_interval(function,  seconds) 是 Pyglet 库中的一个函数调用,用于定期调度另一个函数function在指定的时间间隔seconds内执行。

pyglet.clock.unschedule(function) 任务完成后使用此函数来取消调度,以避免不必要的资源消耗。

以下展示一个四层汉诺塔的移动演示:

代码: 

  1. import pyglet
  2. window = pyglet.window.Window(800, 500, caption='汉诺塔')
  3. pyglet.gl.glClearColor(1, 1, 1, 1)
  4. batch = pyglet.graphics.Batch()
  5. 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)
  6. class Disk:
  7. def __init__(self, x, y, color=(0,0,0), width=200, height=20):
  8. self.cir1 = pyglet.shapes.Circle(x+width/2-height/2, y, radius=height/2, color=color, batch=batch)
  9. self.cir2 = pyglet.shapes.Circle(x-width/2+height/2, y, radius=height/2, color=color, batch=batch)
  10. self.rect = pyglet.shapes.Rectangle(x-width/2+height/2, y-height/2, width-height, height, color=color, batch=batch)
  11. def move(self, dx, dy):
  12. self.cir1.x += dx; self.cir1.y += dy
  13. self.cir2.x += dx; self.cir2.y += dy
  14. self.rect.x += dx; self.rect.y += dy
  15. class Hann:
  16. def __init__(self, x, y, order=2, space=250, thickness=20, width=200, height=300):
  17. assert(order>1)
  18. 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)]
  19. self.disk = [Disk(x+i*space, y, color=Color[0], width=width+thickness, height=thickness) for i in range(-1,2)]
  20. self.x, self.y = x, y
  21. self.order = order
  22. self.space = space
  23. self.thickness = thickness
  24. self.width = width
  25. self.height = (height-thickness*2)/order
  26. self.step = (width-thickness)/(order+1)
  27. coordinates = [(self.x-space, self.y+(i+1)*self.height-(self.height-thickness)/2) for i in range(order)]
  28. self.beads = [Disk(*xy, Color[i%8+1], width=self.width-i*self.step, height=self.height) for i,xy in enumerate(coordinates)]
  29. self.array = [[*range(order)], [], []]
  30. def move(self, pole1, pole2):
  31. if self.array[pole1]:
  32. bead = self.array[pole1].pop()
  33. if self.array[pole2] and bead1]:
  34. print('大盘不能搬到小盘上')
  35. return False
  36. else:
  37. print('所选择的塔架为空!')
  38. return None
  39. self.beads[bead].move((pole2-pole1)*self.space, (len(self.array[pole2])-len(self.array[pole1]))*self.height)
  40. self.array[pole2].append(bead)
  41. return True
  42. @window.event
  43. def on_draw():
  44. window.clear()
  45. batch.draw()
  46. def on_move(event):
  47. global moves
  48. if moves:
  49. x, y = moves.pop(0)
  50. hann.move(x, y)
  51. label.text = f'盘架{x+1}的圆盘移到盘架{y+1}上'
  52. else:
  53. label.text = '演示完毕!'
  54. pyglet.clock.unschedule(on_move)
  55. hann = Hann(window.width/2, 120, 4)
  56. moves = [(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)]
  57. label = pyglet.text.Label('汉诺塔圆盘自动移动演示', font_size=24, color=(0,0,0,255), x=window.width/2, y=50, anchor_x='center', batch=batch)
  58. pyglet.clock.schedule_interval(on_move, 1)
  59. pyglet.app.run()

10. 递归问题

虽然解决了自动演示的功能,但继续增加层数怎么办?还是要自己解决这个问题,本篇前言里就说了汉诺塔问题就是一个递归问题,所以就用递归函数来解决,通常写法:

  1. def hanoi(n, start, mid, end):
  2. if n == 1:
  3. print('Move disk 1 from', start, 'to', end)
  4. else:
  5. hanoi(n-1, start, end, mid)
  6. print('Move disk', n, 'from', start, 'to', end)
  7. hanoi(n-1, mid, start, end)
  8. hanoi(4, 0, 1, 2)

运行的打印结果为: 

Move disk 1 from 0 to 1
Move disk 2 from 0 to 2
Move disk 1 from 1 to 2
Move disk 3 from 0 to 1
Move disk 1 from 2 to 0
Move disk 2 from 2 to 1
Move disk 1 from 0 to 1
Move disk 4 from 0 to 2
Move disk 1 from 1 to 2
Move disk 2 from 1 to 0
Move disk 1 from 2 to 0
Move disk 3 from 1 to 2
Move disk 1 from 0 to 1
Move disk 2 from 0 to 2
Move disk 1 from 1 to 2

移动的坐标刚好与上一步指定的相同,但要改造这个函数,我们需要的是坐标返回值不是打印信息,所以指定一列表用于存放这些坐标,改造后的函数:

  1. def hanoi(n, start, mid, end, moves=None):
  2. if moves is None:
  3. moves = []
  4. if n == 1:
  5. moves.append((start, end))
  6. else:
  7. hanoi(n-1, start, end, mid, moves)
  8. moves.append((start, end))
  9. hanoi(n-1, mid, start, end, moves)
  10. return moves
  11. for order in (4,7,8):
  12. moves = hanoi(order, 0, 1, 2)
  13. print(len(moves)==2**order-1)
  14. print(moves)

运行结果:

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

由此,也验证了总步骤数 steps = 2^n - 1,n为层数。

11. 任意展示

解决递归问题后,就可以展示任意层数的移动演示了,就用上一步得到的7层汉诺塔的移动坐标来展示一下它的移动过程:

完整代码:

  1. import pyglet
  2. window = pyglet.window.Window(800, 500, caption='汉诺塔')
  3. pyglet.gl.glClearColor(1, 1, 1, 1)
  4. batch = pyglet.graphics.Batch()
  5. 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)
  6. class Disk:
  7. def __init__(self, x, y, color=(0,0,0), width=200, height=20):
  8. self.cir1 = pyglet.shapes.Circle(x+width/2-height/2, y, radius=height/2, color=color, batch=batch)
  9. self.cir2 = pyglet.shapes.Circle(x-width/2+height/2, y, radius=height/2, color=color, batch=batch)
  10. self.rect = pyglet.shapes.Rectangle(x-width/2+height/2, y-height/2, width-height, height, color=color, batch=batch)
  11. def move(self, dx, dy):
  12. self.cir1.x += dx; self.cir1.y += dy
  13. self.cir2.x += dx; self.cir2.y += dy
  14. self.rect.x += dx; self.rect.y += dy
  15. class Hann:
  16. def __init__(self, x, y, order=2, space=250, thickness=20, width=200, height=300):
  17. assert(order>1)
  18. 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)]
  19. self.disk = [Disk(x+i*space, y, color=Color[0], width=width+thickness, height=thickness) for i in range(-1,2)]
  20. self.x, self.y = x, y
  21. self.order = order
  22. self.space = space
  23. self.thickness = thickness
  24. self.width = width
  25. self.height = (height-thickness*2)/order
  26. self.step = (width-thickness)/(order+1)
  27. coordinates = [(self.x-space, self.y+(i+1)*self.height-(self.height-thickness)/2) for i in range(order)]
  28. self.beads = [Disk(*xy, Color[i%8+1], width=self.width-i*self.step, height=self.height) for i,xy in enumerate(coordinates)]
  29. self.array = [[*range(order)], [], []]
  30. def move(self, pole1, pole2):
  31. if self.array[pole1]:
  32. bead = self.array[pole1].pop()
  33. if self.array[pole2] and bead1]:
  34. self.array[pole1].append(bead)
  35. print('大盘不能搬到小盘上')
  36. return False
  37. else:
  38. print('所选择的塔架为空!')
  39. return None
  40. self.beads[bead].move((pole2-pole1)*self.space, (len(self.array[pole2])-len(self.array[pole1]))*self.height)
  41. self.array[pole2].append(bead)
  42. return True
  43. @window.event
  44. def on_draw():
  45. window.clear()
  46. batch.draw()
  47. @window.event
  48. def on_key_press(symbol, modifiers):
  49. global start
  50. if not start:
  51. start = True
  52. pyglet.clock.schedule_interval(on_move, 0.3)
  53. @window.event
  54. def on_mouse_press(x, y, button, modifier):
  55. global start
  56. if not start:
  57. start = True
  58. pyglet.clock.schedule_interval(on_move, 0.3)
  59. def hanoi(n, start, mid, end, moves=None):
  60. if moves is None:
  61. moves = []
  62. if n == 1:
  63. moves.append((start, end))
  64. else:
  65. hanoi(n-1, start, end, mid, moves)
  66. moves.append((start, end))
  67. hanoi(n-1, mid, start, end, moves)
  68. return moves
  69. def on_move(event):
  70. global moves,steps
  71. if moves:
  72. x, y = moves.pop(0)
  73. hanns.move(x, y)
  74. label.text = f'盘架{x+1}的圆盘移到盘架{y+1}上'
  75. message.text = f'总步骤数:{steps}\t当前步数:{steps-len(moves)}'
  76. else:
  77. label.text = '演示完毕!'
  78. pyglet.clock.unschedule(on_move)
  79. order = 7
  80. start = False
  81. hanns = Hann(window.width/2, 120, order)
  82. label = pyglet.text.Label('汉诺塔圆盘自动移动演示,任意按键开始......', font_size=24, color=(0,0,0,255), x=window.width/2, y=50, anchor_x='center', batch=batch)
  83. moves = hanoi(order, 0, 1, 2)
  84. steps = len(moves)
  85. message = pyglet.text.Label(f'总步骤数:{steps}\t当前步数:{steps-len(moves)}', font_size=24, color=(0,0,0,255), x=100, y=450, batch=batch)
  86. pyglet.app.run()

12. 鼠标操作

增加一个新的属性.poleheight,把原来的.height属性改为.beadheight以示区别;再给塔类增加两个方法判断鼠标点击和是否成功:

    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_mouse_press(x, y, dx, dy):
    global moves
    if not hanns.success():
        pole = hanns.on_mouse_over(x, y)
        if pole is not None:
            print(pole)
            moves.append(pole)
        if len(moves)==2:
            hanns.move(*moves)
            moves.clear()
        if hanns.success():
            print('Success!')

完整代码: 

  1. import pyglet
  2. window = pyglet.window.Window(800, 500, caption='汉诺塔')
  3. pyglet.gl.glClearColor(1, 1, 1, 1)
  4. batch = pyglet.graphics.Batch()
  5. 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)
  6. class Disk:
  7. def __init__(self, x, y, color=(0,0,0), width=200, height=20):
  8. self.cir1 = pyglet.shapes.Circle(x+width/2-height/2, y, radius=height/2, color=color, batch=batch)
  9. self.cir2 = pyglet.shapes.Circle(x-width/2+height/2, y, radius=height/2, color=color, batch=batch)
  10. self.rect = pyglet.shapes.Rectangle(x-width/2+height/2, y-height/2, width-height, height, color=color, batch=batch)
  11. def move(self, dx, dy):
  12. self.cir1.x += dx; self.cir1.y += dy
  13. self.cir2.x += dx; self.cir2.y += dy
  14. self.rect.x += dx; self.rect.y += dy
  15. class Hann:
  16. def __init__(self, x, y, order=2, space=250, thickness=20, width=200, height=300):
  17. assert(order>1)
  18. 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)]
  19. self.disk = [Disk(x+i*space, y, color=Color[0], width=width+thickness, height=thickness) for i in range(-1,2)]
  20. self.x, self.y = x, y
  21. self.order = order
  22. self.space = space
  23. self.thickness = thickness
  24. self.width = width
  25. self.poleheight = height
  26. self.beadheight = (height-thickness*2)/order
  27. self.step = (width-thickness)/(order+1)
  28. coordinates = [(self.x-space, self.y+(i+1)*self.beadheight-(self.beadheight-thickness)/2) for i in range(order)]
  29. self.beads = [Disk(*xy, Color[i%8+1], width=self.width-i*self.step, height=self.beadheight) for i,xy in enumerate(coordinates)]
  30. self.array = [[*range(order)], [], []]
  31. def move(self, pole1, pole2):
  32. if self.array[pole1]:
  33. bead = self.array[pole1].pop()
  34. if self.array[pole2] and bead1]:
  35. self.array[pole1].append(bead)
  36. print('大盘不能搬到小盘上')
  37. return False
  38. else:
  39. print('所选择的塔架为空!')
  40. return None
  41. self.beads[bead].move((pole2-pole1)*self.space, (len(self.array[pole2])-len(self.array[pole1]))*self.beadheight)
  42. self.array[pole2].append(bead)
  43. return True
  44. def on_mouse_over(self, x, y):
  45. for i in range(-1,2):
  46. 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:
  47. return i+1
  48. def success(self):
  49. return len(self.array[2]) == self.order
  50. @window.event
  51. def on_draw():
  52. window.clear()
  53. batch.draw()
  54. @window.event
  55. def on_mouse_press(x, y, dx, dy):
  56. global moves
  57. if not hanns.success():
  58. pole = hanns.on_mouse_over(x, y)
  59. if pole is not None:
  60. print(pole)
  61. moves.append(pole)
  62. if len(moves)==2:
  63. hanns.move(*moves)
  64. moves.clear()
  65. if hanns.success():
  66. print('Success!')
  67. moves = []
  68. hanns = Hann(window.width/2, 120, 4)
  69. pyglet.app.run()

本篇至此暂时告一段落,下期会继续给游戏增加信息提示等等功能,敬请期待......

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索