# L-18 MCS 275 Mon 22 Feb 2010 : Towers of Hanoi 2 # We extended the program lecture 10 with an iterative version. # The IterativeHanoi maintains a stack of calls and moves. # The InvertedHanoi gives control to the writing def Piles2String(s,A,B,C): """ Returns the string representation of the piles A, B, and C, with the string s in front. """ sA = ' %s = %s' % (A[0],A[1]) sB = ' %s = %s' % (B[0],B[1]) sC = ' %s = %s' % (C[0],C[1]) return s + sA + sB + sC def Write_Piles(s,A,B,C): """ Writes contents of the piles A, B, and C, after printing the string s. """ print Piles2String(s,A,B,C) def Write(k,m,n,A,B,C): """ Writes contents of piles at level k, move m, for some given value of n. """ s = k*' ' s = s + 'move %d, n = %d :' % (m,n) Write_Piles(s,A,B,C) def Write_Stack(S): """ Writes the stack, one line per item. """ print '*** the stack : ***' for item in S: print str(item) def Hanoi(n,A,B,C,k,m): """ moves n disks from A to B, C is auxiliary k is recursion level, m counts # moves writes status of piles after each move returns the tuple (A,B,C,m) """ #print k*' ' + 'Hanoi n = %d, m = %d, k = %d' % (n,m,k) if n == 1: # move disk from A to B m = m + 1 B[1].insert(0,A[1].pop(0)) Write(k,m,n,A,B,C) else: # move n-1 disks from A to C, B is auxiliary (A,C,B,m) = Hanoi(n-1,A,C,B,k+1,m) # move n-th disk from A to B m = m + 1 B[1].insert(0,A[1].pop(0)) Write(k,m,n,A,B,C) # move n-1 disks from C to B, A is auxiliary (C,B,A,m) = Hanoi(n-1,C,B,A,k+1,m) return (A,B,C,m) def Iterative_Hanoi(n,A,B,C,k): """ The iterative version uses a stack of function calls. On the stack are symbols for the piles, not the actual piles! We can count the number of moves more easily in while loop. """ S = [(n,'A','B','C',k)] m = 0 while len(S) > 0: # Write_Stack(S) t = S.pop(0) if type(t) == str: eval(t) if t[0] != 'W': m = m + 1 # we have a move, not a write else: (n,sA,sB,sC,k) = t move = sB + '[1].insert(0,' + sA + '[1].pop(0))' if n == 1: # move disk from A to B eval(move) m = m + 1 Write(k,m,n,A,B,C) else: # observe that we swap order of moves! # move n-1 disks from C to B, A is auxiliary S.insert(0,(n-1,sC,sB,sA,k+1)) # move n-th disk from A to B S.insert(0,("Write(%d,m,%d,A,B,C)" % (k,n))) S.insert(0,move) # move n-1 disks from A to C, B is auxiliary S.insert(0,(n-1,sA,sC,sB,k+1)) def Get_Next_Move(S,A,B,C): """ Computes the next move, changes the stack S, and returns the next move to the calling routine. """ while len(S) > 0: t = S.pop(0) if type(t) == str: eval(t) return t else: (n,sA,sB,sC,k) = t move = sB + '[1].insert(0,' + sA + '[1].pop(0))' if n == 1: # move disk from A to B eval(move) return move else: # observe that we swap order of moves! # move n-1 disks from C to B, A is auxiliary S.insert(0,(n-1,sC,sB,sA,k+1)) # move n-th disk from A to B S.insert(0,move) # move n-1 disks from A to C, B is auxiliary S.insert(0,(n-1,sA,sC,sB,k+1)) return '' def Inverted_Hanoi(n,A,B,C,k): """ This inverted version of the towers of Hanoi gives the control to the writing of the piles. """ S = [(n,'A','B','C',k)] m = 0 while True: move = Get_Next_Move(S,A,B,C) if move == '': break m = m + 1 p = 'after move %d :' % m Write_Piles(p,A,B,C) def main(): """ Prompts user for the number of disks, initializes the stacks and calls Hanoi. """ n = input('Give number of disks : ') A = ('A',range(1,n+1)) B = ('B',[]) C = ('C',[]) m = 0 print '\nMENU for testing Towers of Hanoi :' print ' 0. basic recursive function' print ' 1. iterative version with stack' print ' 2. inverted version with state stack' ans = input('Type 0, 1, or 2 : ') print '\nRunning Towers of Hanoi for %d disks...' % n Write_Piles('at start :',A,B,C) if ans == 0: (A,B,C,m) = Hanoi(n,A,B,C,0,0) elif ans == 1: Iterative_Hanoi(n,A,B,C,0) else: Inverted_Hanoi(n,A,B,C,0) Write_Piles(' at end :',A,B,C) if __name__ == "__main__": main()