Towers of Hanoi non-recursive function

跟風遠走 提交于 2021-01-04 07:14:43

问题


I'm trying to figure out how to implement a non-recursive algorithm for the Hanoi Towers problem in function hanoi_2 below, but I have no idea how to continue...

It throws an error: "can't pop from empty list". It works somehow when I input an odd number, however, when the third turn passes things go wrong. When an even number is input as the number of discs the program doesn't even start.

What is wrong?

from turtle import *
from tkinter import *  # used for the dialog box
from tkinter.simpledialog import askinteger  # used for the dialog box
from tkinter import ttk  # used for the progress bar
import time  # used for time-related functions (in pause)
import pickle  # used to save an object to a file

class Disc(Turtle):
    def __init__(self, n):
        Turtle.__init__(self, shape="square", visible=False)
        self.pu()
        self.shapesize(1.5, n*1.5, 2)  # square-->rectangle
        self.fillcolor(n/10., 0, 1-n/10.)
        self.st()
        self.speed(11-n)  # sets the speed of movement of the rectangles (the bigger, the slower)
        self.moves = 0  # stores the number of times the disc is moved

class Tower(list):
    """Hanoi tower, a subclass of built-in type list"""
    def __init__(self, x):
        """create an empty tower. x is x-position of peg"""
        self.x = x

    def push(self, d):
        d.setx(self.x)
        d.sety(-150+34*len(self))
        d.clear()
        d.write("Moved %s times" %(str(d.moves)), align="left", font=("Courier", 16, "bold"))
        d.moves += 1  # increments the number of moves each time the disc is moved
        self.append(d)

    def pop(self):
        d = list.pop(self)
        d.sety(150)
        return d

def hanoi(n, from_, with_, to_):
    global moves
    global ans
    clear()
    if n > 0:
        hanoi(n-1, from_, to_, with_)
        moves += 1  # amount of total moves is incremented
        to_.push(from_.pop())
        hanoi(n-1, with_, from_, to_)
    sety(-255)
    write("Total moves: %s" % (moves), align="center", font=("Courier", 16, "bold"))
    sety(-320)
    progress_bar(ans)  # calls progress bar function

def hanoi_2(n, A, B, C):
    global moves
    clear()
    if n%2==0:
        B=C
        C=A
        A=B
    for i in range(1,(2**n)-1):
        if i%3==1:
            C.push(A.pop())
        if i%3==2:
            B.push(A.pop())
        if i%3==0:
            B.push(C.pop())

回答1:


The issue with the even number of discs is that the stack swap is not right: you seem to want to cycle the three stacks (which you do in a wrong way as you lose the reference to the original B list), while actually you need to swap only the B and C stacks, which you can do as follows:

B, C = C, B

The issue with the algorithm is that although you have the involved two stacks right (based on i%3), you must still determine which of the two involved stacks is the giver and which one the taker, as this is not always the same! It is probably best if you write a function for this that takes two stacks and determines which of the two possible "directions" is a valid one and then performs that move:

def validMove(A, B):
    if not len(A): 
        A.push(B.pop())
    elif not len(B):
        B.push(A.pop())
    elif A[-1] > B[-1]:
        A.push(B.pop())
    else:
        B.push(A.pop())

Now the main algorithm will look like this:

for i in range(1,2**n):
    if i%3==1:
        validMove(A, C)
    if i%3==2:
        validMove(A, B)
    if i%3==0:
        validMove(B, C)



回答2:


There are few errors. First, swapping is incorrect. After your substitutions, A and B reference to the same object. Either use temporary variable, or use Python syntax: B, C, A = C, A, B. Second, this kind of substitution should be done inside for loop, not before. Look at recursive version, you change order of the towers each time.

I am writing from my phone so I cannot solve it for you, but good luck!:-)




回答3:


Below is a recursive and equivalent iterative solution. The stack saves the order of the calls and their state. In this case there is one state on the stack.

#recursive solution
def tower(numRings):
    def tower1(numRings,fromPeg,toPeg,usePeg):
        if numRings > 0: #A
            tower1(numRings-1,fromPeg,usePeg,toPeg) #B
            result.append((fromPeg,toPeg)) #C
            tower1(numRings-1,usePeg,toPeg,fromPeg) #D
    result = []
    tower1(numRings,0,1,2)
    return result

#iterative solution
def tower(numRings):
    result = []
    stk = []
    def tower1(numRings):
        In, To = 0, 1
        stk.append((In,numRings,0,1,2))
        while stk:
            state,numRings,fromPeg,toPeg,usePeg = stk.pop()
            if state == In:
                if numRings != 0: #push down to 1 numRing #A
                    stk.append((To,numRings,fromPeg,toPeg,usePeg)) #B save state
                    stk.append((In,numRings-1,fromPeg,usePeg,toPeg)) 
            elif state == To:
                result.append((fromPeg,toPeg)) #C
                stk.append((In,numRings-1,usePeg,toPeg,fromPeg)) #D
            else:
                print 'Error: logic'
                return result
    tower1(numRings)
    return result

a = [1,2,3,4]
for n in a:
    print 'rings',n
    print tower(n)


来源:https://stackoverflow.com/questions/48913319/towers-of-hanoi-non-recursive-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!