Here one solution it returns moves and prints out the changes to pos
Feel free to rename the variables to one letter names if this is what is required for your exercise. I personally prefer longer variable names.
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)
The output will look like:
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]}
Below my previous answers, which might be interesting for some people.
One way to do such kind of book keeping would be to add one parameter with a persistent object, for example a dict.
This solution is implemented such, that one does not have to pass the state if one is not interested in getting information about the number of moves.
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"])
In this particular case I could have written:
def playHanoi(pos,a,b,c,n,state={"moves": 0})
and removed the if statement, that assigns a dict to state if None,
but in general this is not good practice as changes to the dict persist
Optional parameters in Python functions and their default values
Knowing, that quite some code from SO is copy pasted into real apps I didn't want to do that as out of context this can be dangerous.
Simple version without book keeping of disks (pos)
Here a simple version of hanoi, that prints out what disk to move and returns the total number of disks being moved
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)
The output would look like:
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
Another (hopefully the final) solution after the ongoing discussion:
pos and j (the number of moves) are returned.
Only one function is used instead of two.
Just remove the print()
inside the function if you do not want it.
It helps to understand how the code works, but is perhaps not needed in your case.
Another note. Exactly as in your initial code the dict, that has been passed to the playHanoi function is also modified.
In some situations this is not desirable.
If interested I'm able to provide a version, where initial_pos will not be modified.
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)