这里有一个解决方案,它返回移动并打印出对 pos 的更改
如果这是您的练习所需要的,请随意将变量重命名为一个字母名称。我个人更喜欢更长的变量名。
def hanoi(pos, p_from, p_to, p_help, n_disks, moves=0):
if n_disks == 1:
disk = pos[p_from].pop()
pos[p_to].append(disk)
moves += 1
print("move %d: move a disk from %s to %s: pos: %s" % (moves, p_from, p_to, pos))
return moves
moves = hanoi(pos, p_from, p_help, p_to, n_disks-1, moves)
moves = hanoi(pos, p_from, p_to, p_help,1 , moves)
moves = hanoi(pos, p_help, p_to, p_from, n_disks-1, moves)
return moves
if __name__ == '__main__':
pos = {1: [5,4,3,2,1], 2: [], 3: []}
moves = hanoi(pos, 1,3,2,5,0)
print("Total moves = %d" % moves)
print("Final pos = ", pos)
输出将如下所示:
move 1: move a disk from 1 to 3: pos: {1: [5, 4, 3, 2], 2: [], 3: [1]}
move 2: move a disk from 1 to 2: pos: {1: [5, 4, 3], 2: [2], 3: [1]}
move 3: move a disk from 3 to 2: pos: {1: [5, 4, 3], 2: [2, 1], 3: []}
move 4: move a disk from 1 to 3: pos: {1: [5, 4], 2: [2, 1], 3: [3]}
move 5: move a disk from 2 to 1: pos: {1: [5, 4, 1], 2: [2], 3: [3]}
move 6: move a disk from 2 to 3: pos: {1: [5, 4, 1], 2: [], 3: [3, 2]}
move 7: move a disk from 1 to 3: pos: {1: [5, 4], 2: [], 3: [3, 2, 1]}
move 8: move a disk from 1 to 2: pos: {1: [5], 2: [4], 3: [3, 2, 1]}
move 9: move a disk from 3 to 2: pos: {1: [5], 2: [4, 1], 3: [3, 2]}
move 10: move a disk from 3 to 1: pos: {1: [5, 2], 2: [4, 1], 3: [3]}
move 11: move a disk from 2 to 1: pos: {1: [5, 2, 1], 2: [4], 3: [3]}
move 12: move a disk from 3 to 2: pos: {1: [5, 2, 1], 2: [4, 3], 3: []}
move 13: move a disk from 1 to 3: pos: {1: [5, 2], 2: [4, 3], 3: [1]}
move 14: move a disk from 1 to 2: pos: {1: [5], 2: [4, 3, 2], 3: [1]}
move 15: move a disk from 3 to 2: pos: {1: [5], 2: [4, 3, 2, 1], 3: []}
move 16: move a disk from 1 to 3: pos: {1: [], 2: [4, 3, 2, 1], 3: [5]}
move 17: move a disk from 2 to 1: pos: {1: [1], 2: [4, 3, 2], 3: [5]}
move 18: move a disk from 2 to 3: pos: {1: [1], 2: [4, 3], 3: [5, 2]}
move 19: move a disk from 1 to 3: pos: {1: [], 2: [4, 3], 3: [5, 2, 1]}
move 20: move a disk from 2 to 1: pos: {1: [3], 2: [4], 3: [5, 2, 1]}
move 21: move a disk from 3 to 2: pos: {1: [3], 2: [4, 1], 3: [5, 2]}
move 22: move a disk from 3 to 1: pos: {1: [3, 2], 2: [4, 1], 3: [5]}
move 23: move a disk from 2 to 1: pos: {1: [3, 2, 1], 2: [4], 3: [5]}
move 24: move a disk from 2 to 3: pos: {1: [3, 2, 1], 2: [], 3: [5, 4]}
move 25: move a disk from 1 to 3: pos: {1: [3, 2], 2: [], 3: [5, 4, 1]}
move 26: move a disk from 1 to 2: pos: {1: [3], 2: [2], 3: [5, 4, 1]}
move 27: move a disk from 3 to 2: pos: {1: [3], 2: [2, 1], 3: [5, 4]}
move 28: move a disk from 1 to 3: pos: {1: [], 2: [2, 1], 3: [5, 4, 3]}
move 29: move a disk from 2 to 1: pos: {1: [1], 2: [2], 3: [5, 4, 3]}
move 30: move a disk from 2 to 3: pos: {1: [1], 2: [], 3: [5, 4, 3, 2]}
move 31: move a disk from 1 to 3: pos: {1: [], 2: [], 3: [5, 4, 3, 2, 1]}
Total moves = 31
Final pos = {1: [], 2: [], 3: [5, 4, 3, 2, 1]}
在我之前的答案下面,这可能对某些人来说很有趣。
进行此类簿记的一种方法是添加一个带有持久对象的参数,例如字典。
该解决方案的实现方式是,如果对获取有关移动次数的信息不感兴趣,则不必传递状态。
def playHanoi(pos,a,b,c,n,state=None):
if state is None:
state = {"moves": 0}
if n == 0:
return pos
if n == 1:
return move(pos, a, b)
else:
return playHanoi(move(playHanoi(pos,a,c,b,n-1, state),a,b, state),c,b,a,n-1, state)
def move(pos, a, b, state):
state["moves"] += 1
if pos[a] == []:
return pos
elif pos[b] == [] or pos[b][-1] >= pos[a][-1]:
pos[b].append(pos[a].pop(-1))
return pos
else:
raise ValueError('This is an illegal move')
state = { "moves": 0 }
pos = playHanoi({1: [5,4,3,2,1], 2: [], 3: []}, 1,3,2,5, state)
print("I needed %d moves" % state["moves"])
在这种特殊情况下,我可以写:
def playHanoi(pos,a,b,c,n,state={"moves": 0})
并删除了 if 语句,该语句将 dict 分配给状态 if None,
但总的来说,这不是一个好习惯,因为对 dict 的更改仍然存在
Optional parameters in Python functions and their default values
知道,来自 SO 的相当多的代码被复制粘贴到真正的应用程序中,我不想这样做,因为脱离上下文这可能很危险。
没有磁盘簿记的简单版本(pos)
这是一个简单版本的 hanoi,它打印出要移动的磁盘并返回要移动的磁盘总数
def hanoi(n_disks, p_from, p_to, p_help, moves=0):
if n_disks == 1:
moves += 1
print("move %d: move a disk from %s to %s" % (moves, p_from, p_to))
return moves
moves = hanoi(n_disks-1, p_from, p_help, p_to, moves)
moves = hanoi(1, p_from, p_to, p_help, moves)
moves = hanoi(n_disks-1, p_help, p_to, p_from, moves)
return moves
moves = hanoi(5, "stackA", "stackB", "stackC")
print("Total moves = %d" % moves)
输出如下:
move a disk from stackA to stackB
move a disk from stackA to stackC
move a disk from stackB to stackC
move a disk from stackA to stackB
move a disk from stackC to stackA
move a disk from stackC to stackB
move a disk from stackA to stackB
move a disk from stackA to stackC
move a disk from stackB to stackC
move a disk from stackB to stackA
move a disk from stackC to stackA
move a disk from stackB to stackC
move a disk from stackA to stackB
move a disk from stackA to stackC
move a disk from stackB to stackC
move a disk from stackA to stackB
move a disk from stackC to stackA
move a disk from stackC to stackB
move a disk from stackA to stackB
move a disk from stackC to stackA
move a disk from stackB to stackC
move a disk from stackB to stackA
move a disk from stackC to stackA
move a disk from stackC to stackB
move a disk from stackA to stackB
move a disk from stackA to stackC
move a disk from stackB to stackC
move a disk from stackA to stackB
move a disk from stackC to stackA
move a disk from stackC to stackB
move a disk from stackA to stackB
Total moves = 31
经过持续讨论后的另一个(希望是最终的)解决方案:
pos 和 j(移动次数)被返回。
只使用了一个函数而不是两个函数。
如果您不想要它,只需删除函数内的print()。
它有助于理解代码的工作原理,但在您的情况下可能不需要。
另一个注释。就像在您的初始代码中一样,已传递给 playHanoi 函数的 dict 也被修改了。
在某些情况下,这是不可取的。
如果有兴趣,我可以提供一个不会修改 initial_pos 的版本。
def playHanoi(pos, a, b, c, n, j=0):
if n == 1:
disk = pos[a].pop()
pos[b].append(disk)
j += 1
print("move %d: move a disk from %s to %s: pos: %s" % (j, a, b, pos))
return pos, j
pos, j = playHanoi(pos, a, c, b, n-1, j)
pos, j = playHanoi(pos, a, b, c,1 , j)
pos, j = playHanoi(pos, c, b, a, n-1, j)
return pos, j
initial_pos = {1: [5,4,3,2,1], 2: [], 3: []}
pos, j = playHanoi(initial_pos, 1,3,2,5,0)
print("Final pos", pos)
print("Total j = %d" % j)
print("look even initial_pos has been modified", initial_pos)