pythonrecursionvisualizationtowers-of-hanoicode-visualization

Possible approach to visualize the Tower of Hanoi problem


I recently started learning more about recursion in Python and quickly got myself into the Tower of Hanoi problem.

I already have a recursive solution in Python, which prints the moves I should play to solve the problem, but I would like to visualize it and see the pieces moving.

What would be a possible approach to it?


Solution

  • If you model your pegs as a list of lists with the larger discs at the lower indices, it should be relatively simple to implement a printing function and a movement function (that also prints). You can then feed your movements to that function.

    def printHanoi(pegs):
        height = sum(map(len,pegs))
        for r in reversed(range(height)):
            for peg in pegs:
                disc = "-" * (0 if r>=len(peg) else peg[r])
                print(f"{disc:>{height}}|{disc:{height}}", end=" ")
            print()
        invalid = any(p[::-1]!=sorted(p) for p in pegs)
        print("="*(height*6+5),"INVALID"*invalid)        
        print()
    
    
    def moveHanoi(pegs,fromPeg,toPeg):
        pegs[toPeg].append(pegs[fromPeg].pop(-1))
        printHanoi(pegs)
    

    Output:

    pegs = [[3,2,1],[],[]]
    printHanoi(pegs)
    moveHanoi(pegs,0,2)
    moveHanoi(pegs,0,1)
    moveHanoi(pegs,2,1)
    moveHanoi(pegs,0,2)
    
      -|-      |       |   
     --|--     |       |   
    ---|---    |       |   
    =======================
    
       |       |       |   
     --|--     |       |   
    ---|---    |      -|-  
    =======================
    
       |       |       |   
       |       |       |   
    ---|---  --|--    -|-  
    =======================
    
       |       |       |   
       |      -|-      |   
    ---|---  --|--     |   
    =======================
    
       |       |       |   
       |      -|-      |   
       |     --|--  ---|---
    =======================
    

    This will work for any tower height and, if your algorithm makes illegal moves, it will illustrate them as well:

    pegs = [[5,4,3,2,1],[],[]]
    printHanoi(pegs)
    moveHanoi(pegs,0,2)
    moveHanoi(pegs,0,1)
    moveHanoi(pegs,0,2)
        
        -|-          |           |      
       --|--         |           |      
      ---|---        |           |      
     ----|----       |           |      
    -----|-----      |           |      
    ===================================
    
         |           |           |      
       --|--         |           |      
      ---|---        |           |      
     ----|----       |           |      
    -----|-----      |          -|-     
    ===================================
    
         |           |           |      
         |           |           |      
      ---|---        |           |      
     ----|----       |           |      
    -----|-----    --|--        -|-     
    ===================================
    
         |           |           |      
         |           |           |      
         |           |           |      
     ----|----       |        ---|---   
    -----|-----    --|--        -|-     
    =================================== INVALID
    

    If you build your Hanoi solver as a generator, you will be able to use it in a for-loop that simply calls the moveHanoi() function:

    def solveHanoi(count,fromPeg=0,toPeg=2,tempPeg=1):
        if not count: return
        yield from solveHanoi(count-1,fromPeg,tempPeg,toPeg)
        yield fromPeg,toPeg
        yield from solveHanoi(count-1,tempPeg,toPeg,fromPeg)
            
    pegs = [[3,2,1],[],[]]
    printHanoi(pegs)
    for f,t in solveHanoi(3):
        moveHanoi(pegs,f,t)