How does python handle tower of hanoi recursion code?

Question:

def move_disks(n, from_tower, to_tower, aux_tower):
    result = []
    ###BEGIN SOLUTION
    # base case
    if n == 1:
        return [f"Move disk {n:} from {from_tower:} to {to_tower:}."]
    # recursive case
    else:
        # move n-1 disks from src to an aux tower
        result = move_disks(n-1, from_tower, aux_tower, to_tower)
        # move nth disk src to dest tower
        result += [f"Move disk {n:} from {from_tower:} to {to_tower:}."]
        # move n-1 disks from aux to dest
        result += move_disks(n-1, aux_tower, to_tower, from_tower)
    
    ###END SOLUTION
    return result

#Test cases
result = move_disks(3, "A", "B", "C")
print(result)
assert result == ["Move disk 1 from A to B.", "Move disk 2 from A to C.", "Move disk 1 from B to C.", "Move disk 3 from A to B.", "Move disk 1 from C to A.", "Move disk 2 from C to B.", "Move disk 1 from A to B."]

My doubt is this. Why is the iteration when n=1 for move_disks (in following picture), A,B,C for "from_tower,to_tower and aux_tower" respectively. I feel it should be A,C,B respectively.

Please refer to the image attached below for seeing python tutor visualization.

enter image description here

Asked By: Yash Mehta

||

Answers:

Why is the iteration when n=1 for move_disks (in following picture), A,B,C for "from_tower,to_tower and aux_tower" respectively.

Because the goal of the whole problem is to move the whole stack from A to B. This can be seen from the top-level call: move_disks(3, "A", "B", "C"). In this call B is the target.

Now when the number of disks is odd, then the first move (when n==1) should be from A to B (with C being auxiliary). It is odd in this particular call move_disks(3, "A", "B", "C").

Be aware that each execution of move_disks has its own set of names. You have already understood that the value of n in one execution is not the same as in another execution, but the same principle applies to the other parameters: the caller may pass aux_tower as value for the recursive name to_tower, and so on.

Here is a visualisation of the first part of the process for 3 disks. Each box is an execution of the function. Each box has its own set of names:

move_disks(3, "A", "B", "C")
┌───────────────────────────────────────────────────────────────────┐
│ locals: n=3, from_tower="A", to_tower="B", aux_tower="C"          │
│ else-case                                                         │
│ result = move_disks(2, "A", "C", "B")                             │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ locals: n=2, from_tower="A", to_tower="C", aux_tower="B"      │ │ 
│ │ else-case                                                     │ │
│ │ result = move_disks(1, "A", "B", "C")                         │ │ 
│ │ ┌───────────────────────────────────────────────────────────┐ │ │
│ │ │ locals: n=1, from_tower="A", to_tower="B", aux_tower="C"  │ │ │
│ │ │ if-case                                                   │ │ │
│ │ │ return ["Move disk 1 from A to B."]                       │ │ │
│ │ └───────────────────────────────────────────────────────────┘ │ │
│ │ result += ["Move disk 2 from A to C."]                        │ │
│ │ result += move_disks(1, "B", "C", "A")                        │ │
│ │ ┌───────────────────────────────────────────────────────────┐ │ │
│ │ │ locals: n=1, from_tower="B", to_tower="C", aux_tower="A"  │ │ │
│ │ │ if-case                                                   │ │ │
│ │ │ return ["Move disk 1 from B to C."]                       │ │ │
│ │ └───────────────────────────────────────────────────────────┘ │ │
│ │ return result                                                 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ ...etc
Answered By: trincot