# L-10 MCS 275 Wed 1 Feb 2017 : hanoi.py
"""
An example of recursive problem solving is the problem
of the towers of Hanoi.
""" 

def hanoi0(nbr, apl, bpl, cpl):
    """
    Moves nbr disks from apl to bpl, cpl is auxiliary.
    """
    if nbr == 1:
        # move disk from apl to bpl
        bpl.insert(0, apl.pop(0))
    else:
        # move nbr-1 disks from apl to cpl, using bpl
        hanoi0(nbr-1, apl, cpl, bpl)
        # move nbr-th disk from apl to bpl
        bpl.insert(0, apl.pop(0))
        # move nbr-1 disks from cpl to bpl, using apl
        hanoi0(nbr-1, cpl, bpl, apl)

def main4hanoi0(nbr):
    """
    This the main function that calls the
    first version hanoi0 on nbr disks.
    """
    apl = [x for x in range(nbr)]
    bpl = []
    cpl = []
    print('A =', apl, 'B =', bpl, 'C =', cpl)
    hanoi0(nbr, apl, bpl, cpl)
    print('A =', apl, 'B =', bpl, 'C =', cpl)

def write_piles(pre, apl, bpl, cpl):
    """
    Writes the contents of the piles apl, bpl,
    and cpl, after writing the string pre.
    Every pile is a 2-tuple: the name
    of the pile, and a list of numbers.
    """
    sapl = '%s = %s' % apl
    sbpl = '%s = %s' % bpl
    scpl = '%s = %s' % cpl
    print(pre, sapl, sbpl, scpl)

def write(k, move, nbr, apl, bpl, cpl):
    """
    Writes contents of piles apl, bpl, cpl,
    preceded by k spaces, writing the move
    and the number of disks nbr.
    """
    pre = k*' '
    pre += 'move %d, n = %d :' % (move, nbr)
    write_piles(pre, apl, bpl, cpl)

def hanoi(nbr, apl, bpl, cpl, k, move):
    """
    Moves nbr disks from apl to bpl, cpl is auxiliary.
    The recursion depth is counted by k,
    move counts the number of moves.
    Writes the state of the piles after each move.
    Returns the number of moves.
    """
    if nbr == 1:
        # move disk from A to B
        bpl[1].insert(0, apl[1].pop(0))
        write(k, move+1, nbr, apl, bpl, cpl)
        return move+1
    else:
        # move nbr-1 disks from A to C, B is auxiliary
        move = hanoi(nbr-1, apl, cpl, bpl, k+1, move)
        # move nbr-th disk from A to B
        bpl[1].insert(0, apl[1].pop(0))
        write(k, move+1, nbr, apl, bpl, cpl)
        # move nbr-1 disks from C to B, A is auxiliary
        move = hanoi(nbr-1, cpl, bpl, apl, k+1, move+1)
        return move

def main():
    """
    Prompts user for the number of disks,
    initializes the stacks and calls hanoi.
    """
    nbr = int(input('Give number of disks : '))
    main4hanoi0(nbr)
    apl = ('A', list(range(1, nbr+1)))
    bpl = ('B', [])
    cpl = ('C', [])
    write_piles('at start :', apl, bpl, cpl)
    cnt = hanoi(nbr, apl, bpl, cpl, 0, 0)
    print('number of moves :', cnt)
    write_piles('  at end :', apl, bpl, cpl)

if __name__ == "__main__":
    main()
