搜索无法解决 python 中的过河问题

Search not working for river crossing problem in python

过河问题描述: 我们有一个农夫、一只狼、一只山羊和一棵卷心菜,他们需要过河,但有以下限制:

  1. 狼不能与羊为敌

  2. 山羊不能和白菜在同一边

  3. -初始状态:(‘L’,‘L’,‘L’,‘L’)

  4. -结局状态:(‘R’,‘R’,‘R’,‘R’)
    状态列表描述了每个人的位置(农民、狼、山羊、卷心菜),所以 state('L','R','L','R') 表示狼和卷心菜在右侧,而农夫和山羊在河的左边。我不想通过实现列表列表来让它变得更复杂。 我的代码的问题是它从初始状态开始,在第一步(右边的农民和山羊)之后停止。我找不到任何方法来使递归工作以获得可接受的结果。所以我可以使用一些帮助来使递归发挥作用并按预期工作。 提前谢谢你。

    """ ----------------------------------------------------------------------------
    ******** Search Code for DFS  and other search methods
    ******** (expanding front and extending queue)
    ******** author:  
    """
    
    
    import copy
    
    #left, right of the river
    spaces = {
      'R': ['L'],
      'L': ['R']
    }
    
    def enter(state):
      if state[0]==state[1] and state[2]==state[3]:
        new_state=state=['R', state[1]] + ['R', state[3]]
        return new_state
    
    #function that swaps the side of the river that the farmer is
    def swap(state_l, i, j): 
    state_l[i] = state_l[j]
    return state_l
    
    '''
    operators for the movement of the farmer
    '''
    
    def neighbour1(state):
      elem=['L']
      i=state.index(elem) if elem in state else -1  #checking if the elem is in the state
      if i >=0:
        swap(state, i, spaces[i][0])
        return state
    
    def neighbour2(state):   
      elem=['L']
      i=state.index(elem) if elem in state else -1
      if i >=0:
        swap(state, i, spaces[i][1])
        return state
    
    
    """ ----------------------------------------------------------------------------
    **** FRONT managment
    **** 
    """
    
    def find_children(state):
    
      children=[]
    
      enter_state=copy.deepcopy(state)
      enter_child=enter(enter_state)
    
      tr1_state=copy.deepcopy(state)
      tr1_child=neighbour1(tr1_state)
    
      tr2_state=copy.deepcopy(state)
      tr2_child=neighbour2(tr2_state)
    
      if tr1_child is not None: 
          children.append(tr1_child)
    
      if tr2_child is not None: 
          children.append(tr2_child)
    
      if enter_child is not None: 
          children.append(enter_child)
    
      return children
    
    
    """ ----------------------------------------------------------------------------
    ** initialization of front
    ** 
    """
    
    def make_front(state):
      return [state]
    
    """ ----------------------------------------------------------------------------
    **** expanding front
    ****   
    """
    
    def expand_front(front, method):  
      if method=='DFS':        
        if front:
            print("Front:")
            print(front)
            node=front.pop(0)
            for child in find_children(node):     
                front.insert(0,child)
    
      elif method=='BFS':
        if front: 
            print("Front:")
            print(front)
            node=front.pop(0)
            for child in find_children(node):     
                front.append(child)
    return front
    '''
    elif method=='BestFS':
    #'''           
    #else: "other methods to be added"        
    
    
    """ ----------------------------------------------------------------------------
    **** QUEUE
    **** 
    """
    
    """ ----------------------------------------------------------------------------
    ** initialization of queue
    ** 
    """
    
    def make_queue(state):
      return [[state]]
    
    """ ----------------------------------------------------------------------------
    **** expanding queue
    **** επέκταση ουράς
    """
    
    def extend_queue(queue, method):
      if method=='DFS':
        print("Queue:")
        print(queue)
        node=queue.pop(0)
        queue_copy=copy.deepcopy(queue)
        children=find_children(node[-1])
        for child in children:
            path=copy.deepcopy(node)
            path.append(child)
            queue_copy.insert(0,path)
    
    elif method=='BFS': 
        if queue:
            print("Queue:")
            print(queue)
            node=queue.pop(0)
            queue_copy=copy.deepcopy(queue)
            children=find_children(node[-1])
            for child in children:
                path=copy.deepcopy(node)
                path.append(child)
                queue_copy.append(path)
    '''
    elif method=='BestFS':
    #'''
    #else: "other methods to be added" 
    
    return queue_copy
    
    """ ----------------------------------------------------------------------------
    **** Basic recursive function to create search tree (recursive tree expansion)
    **** 
    """
    
    def find_solution(front, queue, closed, method):
    
      if not front:
        print('_NO_SOLUTION_FOUND_')
    
      elif front[0] in closed:
        new_front=copy.deepcopy(front)
        new_front.pop(0)
        new_queue=copy.deepcopy(queue)
        new_queue.pop(0)
        find_solution(new_front, new_queue, closed, method)
    
      elif is_goal_state(front[0]):
        print('_GOAL_FOUND_')
        print(queue[0])
    
      else:
        closed.append(front[0])
        front_copy=copy.deepcopy(front)
        front_children=expand_front(front_copy, method)
        queue_copy=copy.deepcopy(queue)
        queue_children=extend_queue(queue_copy, method)
        closed_copy=copy.deepcopy(closed)
        find_solution(front_children, queue_children, closed_copy, method)
    
    
    """" ----------------------------------------------------------------------------
    ** Executing the code
    ** 
    """
    
    def is_goal_state(state):  
      if state == ['R','R','R','R']:
        return True 
    
    def main():
    
    initial_state = ['L','L','L','L']  
    method='DFS'
    
    """ ----------------------------------------------------------------------------
    **** starting search
    **** 
    """
    
    print('____BEGIN__SEARCHING____')
    find_solution(make_front(initial_state), make_queue(initial_state), [], method)
    
    
    if __name__ == "__main__":
      main()
    

农民问题

我将从另一个角度来解决您的问题。我没有调试您的问题,而是通过逐步测试的方法解决了它。

设置和规则

首先让我们定义情况和规则

FARMER = 0
WOLF = 1
GOAT = 2
CABBAGE = 3

START_STATE = ['L','L','L','L']

def wolfRule(state):
    return state[FARMER] == state[WOLF] or state[WOLF] != state[GOAT]

assert( wolfRule(['L','L','L','L']) == True)
assert( wolfRule(['R','L','L','L']) == False)
assert( wolfRule(['R','L','R','L']) == True)

def goatRule(state):
    return state[FARMER] == state[GOAT] or state[GOAT] != state[CABBAGE]

assert( goatRule(['L','L','L','L']) == True)
assert( goatRule(['R','L','L','L']) == False)
assert( goatRule(['R','L','L','R']) == True)

def validRule(state):
    return wolfRule(state) and goatRule(state)

def winRule(state):
    return state == ['R','R','R','R']

assert( winRule(['L','L','L','L']) == False)
assert( winRule(['R','L','L','L']) == False)
assert( winRule(['R','R','R','R']) == True)

我们已经定义了每条规则,添加了一些断言语句,因此我们知道它们有效,当我们运行上面的代码时,我们可以确定一切正常。

生成动作

递归搜索的一部分是生成下一个有效着法。我们将分两部分进行。第一部分只是生成所有可能的着法,第二部分将只过滤出有效的着法

def generateMoves(state):
    # The farmer moves to the other side and can bring 0 or 1 other things so long as it is on the same starting side
    for other in [FARMER, WOLF, GOAT, CABBAGE]:
        if state[FARMER] == state[other]:
            move = copy(state)
            move[FARMER] = 'L' if state[FARMER] == 'R' else 'R'
            move[other] = 'L' if state[other] == 'R' else 'R'
            yield move

assert( list(generateMoves(START_STATE)) == [['R','L','L','L'],['R','R','L','L'],['R','L','R','L'],['R','L','L','R']]  )

同样,我们添加了一个测试,以确保它在生成一些动作时按照我们的预期进行

def validMoves(state_list):
    return [ state for state in state_list if validRule(state)]

assert( list(validMoves(generateMoves(START_STATE))) == [['R','L','R','L']]  )

的确,唯一有效的第一步是农民搬山羊!

深度优先搜索

现在我们进行深度优先搜索,使用 previous_states 列表来跟踪我们去过的地方。此功能仅returns个中奖答案。

def depthFirstSearch(state, previous_states):
    previous_states.append(state)
    if winRule(state):
        return previous_states
    for move in validMoves(generateMoves(state)):
        if move not in previous_states:
            result = depthFirstSearch(move, previous_states)
            if result is not None:
                return result
            previous_states.pop()
    return None

同样,至少进行一次测试以确保它给出预期的结果

assert( depthFirstSearch(['L','R','L','R'],[]) == [['L','R','L','R'],['R','R','R','R']]  )

最终输出

我们运行它

depthFirstSearch(START_STATE,[])

并得到解决方案!

[['L', 'L', 'L', 'L'],
 ['R', 'L', 'R', 'L'],
 ['L', 'L', 'R', 'L'],
 ['R', 'R', 'R', 'L'],
 ['L', 'R', 'L', 'L'],
 ['R', 'R', 'L', 'R'],
 ['L', 'R', 'L', 'R'],
 ['R', 'R', 'R', 'R']]