有个朋友在捣鼓汉诺塔,来了点兴趣,想自己来实现,看了网上博客,基本都是递归,感觉看的很懵,于是自己也折腾了一天,挺不聪明的,搞好了留个底
python3版本
# -*- coding: utf-8 -*-
"""
汉诺塔游戏
@author: lzh997
@create_time: 2021-09-19 16:29
@updater:
@update_time:
"""
import time
class Plate(object):
"""
塔盘类
"""
def __init__(self, name, value, pre_position=None):
"""
:param name: 盘名称
:param value: 盘的数值,用于比较大小
:param pre_position: 上一个存放该盘的塔的名称
"""
self.name = name
self.value = value
self.pre_position = pre_position
def __repr__(self):
"""
对象打印信息
:return:
"""
return f'({self.name}, {self.pre_position})'
class Tower(object):
"""
汉诺塔的塔类
"""
def __init__(self, name, empty_value):
"""
plates存放盘的列表
empty_value代表塔没有盘的值,盘的最大值 + 1
:param name: 塔名称
:param empty_value: 塔没有盘的时候的值
"""
self.plates = []
self.name = name
self.empty_value = empty_value
def remove(self):
"""
移除最上面的盘
:return:
"""
return self.plates.pop()
def add(self, plate):
"""
在塔上添加盘
:param plate:
:return:
"""
self.plates.append(plate)
def first(self):
"""
获取塔最上面盘的数值
:return:
"""
return self.plates[-1].value if self.plates else self.empty_value
def __str__(self):
"""
塔信息打印
"""
return f'{[plate.name for plate in self.plates]}'
class TowerOfHanoi(object):
"""
汉诺塔
"""
def __init__(self, plate_number):
"""
:param plate_number: 开始的盘数量
"""
self.plate_number = plate_number
self.tower_1 = None
self.tower_2 = None
self.tower_3 = None
self.init_tower()
def init_tower(self):
"""
创建塔1/2/3对象,将所有盘按升序存放在塔1内
:return:
"""
empty_value = self.plate_number + 1
self.tower_1 = Tower('t1', empty_value)
for i in range(self.plate_number, 0, -1):
self.tower_1.add(Plate('plate' + str(i), i, None))
self.tower_2 = Tower('t2', empty_value)
self.tower_3 = Tower('t3', empty_value)
print(f'*'*80 + '\n' +
f'create tower of Hanoi:' + '\n' +
f'\ttower 1: {self.tower_1}, ' + '\n' +
f'\ttower 2: {self.tower_2}, ' + '\n' +
f'\ttower 3: {self.tower_3}' + '\n' +
f'*'*80)
def play(self):
"""
启动游戏
:return:
"""
# 盘要移动到指定塔的优先级
action_priority = {
't1': [self.tower_3, self.tower_2],
't2': [self.tower_1, self.tower_3],
't3': [self.tower_2, self.tower_1]
}
# 完成状态信息
completion_status = [plate.name for plate in self.tower_1.plates]
while True:
# 遍历塔
for tower in [self.tower_1, self.tower_2, self.tower_3]:
# 当前塔是否移动过盘
plate_move = False
# 从上到下遍历当前塔的存放的所有盘,因为塔存放盘是先进后出的
# 所有需要反转盘顺序
for plate in tower.plates[::-1]:
# 如果当前遍历的盘的值小于移动目标塔第一个盘的值
# 以及上一次不是从移动目标塔移动过来的,则将该盘子移动到这个塔上,
# 然后将该盘对象从当前遍历的塔中移除
action_towers = action_priority[tower.name]
move_tower_name = ''
if plate.value < action_towers[0].first() \
and plate.pre_position != action_towers[0].name:
plate.pre_position = tower.name
action_towers[0].add(plate)
tower.remove()
plate_move = True
move_tower_name = action_towers[0].name
elif plate.value < action_towers[1].first() \
and plate.pre_position != action_towers[1].name:
plate.pre_position = tower.name
action_towers[1].add(plate)
tower.remove()
plate_move = True
move_tower_name = action_towers[1].name
# 如果当前遍历盘没有被移动,代表当前塔没有可以继续移动的盘,
# 退出盘的遍历
if plate_move is False:
break
# 所有盘以及按顺序存放在塔3,完成游戏
if [plate.name for plate in self.tower_3.plates] \
== completion_status:
print(
f'done done! '
f't1: {self.tower_1}, '
f't2: {self.tower_2}, '
f't3: {self.tower_3}')
return
print(
f'{tower.name} {plate.name} move to '
f'{move_tower_name}:\n'
f'\tt1: {self.tower_1},\n'
f'\tt2: {self.tower_2},\n'
f'\tt3: {self.tower_3}.\n' +
f'*'*80
)
time.sleep(1)
if __name__ == '__main__':
hanoi = TowerOfHanoi(3)
hanoi.play()
|