Even though there's plenty of questions about this problem here, none of them have helped me clear this up. I understand what recursion is and I can easily solve Towers of Hanoi by myself in 2^n-1 moves, but I'm having trouble writing an algorithm for it in Python. The base case works but I can't seem to find a way to translate "move n-1 disks to the auxiliary peg and then the largest disk to the target peg" into array operations, and I don't understand why the last element isn't getting removed from the array when I pop it in the recursive call.
This is the programme:
peg_a = [1,0]
peg_b = []
peg_c = []
def hanoi(start,aux,target):
print(start,aux,target)
if len(start) == 1:
target.append(start.pop())
print(start,aux,target)
else:
hanoi(start[1:],target,aux)
target.append(start.pop())
print(start,aux,target)
hanoi(peg_a, peg_b, peg_c)
And this is what gets printed:
[1, 0] [] []
[0] [] []
[] [] [0]
[1] [0] [0]
Any help?
I think one problem is that your function does not return anything. You use lists to hold the contents of the bigs, which are modifyable objects, so you could see the function arguments as pointers to those objects. This might work, but the problem is that by making a slice with start[1:], you create a new list, so it is no longer a 'pointer' to the original list.
One workaround might be to still use the input arguments as pointers to the lists, but than add some extra integer function arguments, which indicate how many disks to move.
This is how I would do it:
def hanoi(pegs, start, target, n):
assert len(pegs[start]) >= n, 'not enough disks on peg'
if n == 1:
pegs[target].append(pegs[start].pop())
print '%i -> %i: %s' % (start, target, pegs)
else:
aux = 3 - start - target # start + target + aux = 3
hanoi(pegs, start, aux, n-1)
hanoi(pegs, start, target, 1)
hanoi(pegs, aux, target, n-1)
I do not use 3 different lists, since in your code they get swapped around, so it is hard to visualize what is happening. Instead, I have a single pegs variable, which is a list of lists. In my case, start and target are the indices of the pegs, which I swap around. The nice thing is that you can now print the individual steps. Quick demonstration:
pegs = [[4, 3, 2, 1], [], []]
hanoi(pegs, 0, 1, 4)
with result
0 -> 2: [[4, 3, 2], [], [1]]
0 -> 1: [[4, 3], [2], [1]]
2 -> 1: [[4, 3], [2, 1], []]
0 -> 2: [[4], [2, 1], [3]]
1 -> 0: [[4, 1], [2], [3]]
1 -> 2: [[4, 1], [], [3, 2]]
0 -> 2: [[4], [], [3, 2, 1]]
0 -> 1: [[], [4], [3, 2, 1]]
2 -> 1: [[], [4, 1], [3, 2]]
2 -> 0: [[2], [4, 1], [3]]
1 -> 0: [[2, 1], [4], [3]]
2 -> 1: [[2, 1], [4, 3], []]
0 -> 2: [[2], [4, 3], [1]]
0 -> 1: [[], [4, 3, 2], [1]]
2 -> 1: [[], [4, 3, 2, 1], []]
There are two problems with your code:
start[1:] does not work, as you are creating a copy of the list and thus not modifying the original list any more (see Bas' answer).else part, stacking the discs from the aux peg to the target peg.To fix the first problem, the easiest way would be to add an aditional parameter, indicating the number of discs to relocate from start to target:
def hanoi(n, start, aux, target):
if n == 1:
target.append(start.pop())
else:
hanoi(n - 1, start, target, aux)
target.append(start.pop())
hanoi(n - 1, aux, start, target)
Or shorter:
def hanoi(n, start, aux, target):
if n > 0:
hanoi(n - 1, start, target, aux)
target.append(start.pop())
hanoi(n - 1, aux, start, target)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With