15拼图BCS Python:未缩进不匹配任何外部缩进级别

15拼图BCS Python:未缩进不匹配任何外部缩进级别,python,bcs,Python,Bcs,这段代码使用Python中的各种广度优先搜索方法来解决15个难题。但是当我运行它时,输出unindent与任何外部缩进级别都不匹配 整个回溯显示: File "main.py", line 58

这段代码使用Python中的各种广度优先搜索方法来解决15个难题。但是当我运行它时,输出unindent与任何外部缩进级别都不匹配

整个回溯显示:

  File "main.py", line 58                                                                                                                                                       
    print "| %i | %i | %i | %i |" % (state[3], state[7], state[11], state[15])                                                                                                  
                                                                             ^                                                                                                  
IndentationError: unindent does not match any outer indentation level     
我试着在每一个动作中(上、下、左、右)改变禁制状态,但还没有成功。每个人都能帮助我分析代码中的问题吗

#!/usr/bin/python
#
### Student Info
# Smith, Christopher, 02386569, 159.302
# Assignment 1: 8 Puzzle.
#
### Language
# This assignment was written in Python. An open source, interpreted language
# with a mix of imperative, OO and functional programming. Syntax is simple
# and easy to learn.
#
# Developed on Ubuntu Linux but this will run on the interpreter available
# from http://python.org. Documentation is also on that site but a good
# tutorial is available for free at http://diveintopython.org.
#
### Data Structures
#
# The state of the board is stored in a list. The list stores values for the
# board in the following positions:
#
# -------------
# | 0 | 3 | 6 |
# -------------
# | 1 | 4 | 7 |
# -------------
# | 2 | 5 | 8 |
# -------------
#
# The goal is defined as:
#
# -------------
# | 1 | 2 | 3 |
# -------------
# | 4 | 5 | 6 |
# -------------
# | 7 | 8 | 0 |
# -------------
#
# Where 0 denotes the blank tile or space.
goal_state = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]
starting_state = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 15]
#
# The code will read state from a file called "state.txt" where the format is
# as above but space seperated. i.e. the content for the goal state would be
# 1 8 7 2 0 6 3 4 5

### Code begins.
import sys

def display_board( state ):
    print "-------------"   
    print "| %i | %i | %i |" % (state[0], state[1], state[2],  state[3])
    print "-------------"
    print "| %i | %i | %i |" % (state[4], state[5], state[6],  state[7])    
    print "-------------"
    print "| %i | %i | %i |" % (state[8], state[9], state[10], state[11])   
    print "-------------"
    print "| %i | %i | %i |" % (state[12], state[13], state[14], state[15])
    print "-------------"

def move_up( state ):
    """Moves the blank tile up on the board. Returns a new state as a list."""
    # Perform an object copy
    new_state = state[:]
    index = new_state.index( 0 )
    # Sanity check
    if index not in [0, 1, 2,3]:
        # Swap the values.
        temp = new_state[index - 1]
        new_state[index - 1] = new_state[index]
        new_state[index] = temp
        return new_state
    else:
        # Can't move, return None (Pythons NULL)
        return None

def move_down( state ):
    """Moves the blank tile down on the board. Returns a new state as a list."""
    # Perform object copy
    new_state = state[:]
    index = new_state.index( 0 )
    # Sanity check
    if index not in [12, 13, 14, 15]:
        # Swap the values.
        temp = new_state[index + 1]
        new_state[index + 1] = new_state[index]
        new_state[index] = temp
        return new_state
    else:
        # Can't move, return None.
        return None

def move_left( state ):
    """Moves the blank tile left on the board. Returns a new state as a list."""
    new_state = state[:]
    index = new_state.index( 0 )
    # Sanity check
    if index not in [0, 4, 8, 12]:
        # Swap the values.
        temp = new_state[index - 4]
        new_state[index - 4] = new_state[index]
        new_state[index] = temp
        return new_state
    else:
        # Can't move it, return None
        return None

def move_right( state ):
    """Moves the blank tile right on the board. Returns a new state as a list."""
    # Performs an object copy. Python passes by reference.
    new_state = state[:]
    index = new_state.index( 0 )
    # Sanity check
    if index not in [3, 7, 11, 15]:
        # Swap the values.
        temp = new_state[index + 4]
        new_state[index + 4] = new_state[index]
        new_state[index] = temp
        return new_state
    else:
        # Can't move, return None
        return None

def create_node( state, parent, operator, depth, cost ):
    return Node( state, parent, operator, depth, cost )

def expand_node( node, nodes ):
    """Returns a list of expanded nodes"""
    expanded_nodes = []
    expanded_nodes.append( create_node( move_up( node.state ), node, "u", node.depth + 1, 0 ) )
    expanded_nodes.append( create_node( move_down( node.state ), node, "d", node.depth + 1, 0 ) )
    expanded_nodes.append( create_node( move_left( node.state ), node, "l", node.depth + 1, 0 ) )
    expanded_nodes.append( create_node( move_right( node.state), node, "r", node.depth + 1, 0 ) )
    # Filter the list and remove the nodes that are impossible (move function returned None)
    expanded_nodes = [node for node in expanded_nodes if node.state != None] #list comprehension!
    return expanded_nodes

def bfs( start, goal ):
    """Performs a breadth first search from the start state to the goal"""
    # A list (can act as a queue) for the nodes.
    nodes = []
    # Create the queue with the root node in it.
    nodes.append( create_node( start, None, None, 0, 0 ) )
    while True:
        # We've run out of states, no solution.
        if len( nodes ) == 0: return None
        # take the node from the front of the queue
        node = nodes.pop(0)
        # Append the move we made to moves
        # if this node is the goal, return the moves it took to get here.
        if node.state == goal:
            moves = []
            temp = node
            while True:
                moves.insert(0, temp.operator)
                if temp.depth == 1: break
                temp = temp.parent
            return moves                
        # Expand the node and add all the expansions to the front of the stack
        nodes.extend( expand_node( node, nodes ) )

def dfs( start, goal, depth=10 ):
    """Performs a depth first search from the start state to the goal. Depth param is optional."""
    # NOTE: This is a limited search or else it keeps repeating moves. This is an infinite search space.
    # I'm not sure if I implemented this right, but I implemented an iterative depth search below
    # too that uses this function and it works fine. Using this function itself will repeat moves until
    # the depth_limit is reached. Iterative depth search solves this problem, though.
    #
    # An attempt of cutting down on repeat moves was made in the expand_node() function.
    depth_limit = depth
    # A list (can act as a stack too) for the nodes.
    nodes = []
    # Create the queue with the root node in it.
    nodes.append( create_node( start, None, None, 0, 0 ) )
    while True:
        # We've run out of states, no solution.
        if len( nodes ) == 0: return None
        # take the node from the front of the queue
        node = nodes.pop(0)
        # if this node is the goal, return the moves it took to get here.
        if node.state == goal:
            moves = []
            temp = node
            while True:
                moves.insert(0, temp.operator)
                if temp.depth <= 1: break
                temp = temp.parent
            return moves                
        # Add all the expansions to the beginning of the stack if we are under the depth limit
        if node.depth < depth_limit:
            expanded_nodes = expand_node( node, nodes )
            expanded_nodes.extend( nodes )
            nodes = expanded_nodes

def ids( start, goal, depth=50 ):
    """Perfoms an iterative depth first search from the start state to the goal. Depth is optional."""
    for i in range( depth ):
        result = dfs( start, goal, i )
        if result != None:
            return result

def a_star( start, goal ):
    """Perfoms an A* heuristic search"""
    # ATTEMPTED: does not work :(
    nodes = []
    nodes.append( create_node( start, None, None, 0, 0 ) )
    while True:
        # We've run out of states - no solution.
        if len( nodes ) == 0: return None
        # Sort the nodes with custom compare function.
        nodes.sort( cmp )
        # take the node from the front of the queue
        node = nodes.pop(0)
        # if this node is the goal, return the moves it took to get here.
        print "Trying state", node.state, " and move: ", node.operator
        if node.state == goal:
            moves = []
            temp = node
            while True:
                moves.insert( 0, temp.operator )
                if temp.depth <=1: break
                temp = temp.parent
            return moves
        #Expand the node and add all expansions to the end of the queue
        nodes.extend( expand_node( node, nodes ) )

def cmp( x, y ):
    # Compare function for A*. f(n) = g(n) + h(n). I use depth (number of moves) for g().
    return (x.depth + h( x.state, goal_state )) - (y.depth + h( x.state, goal_state ))

def h( state, goal ):
    """Heuristic for the A* search. Returns an integer based on out of place tiles"""
    score = 0
    for i in range( len( state ) ):
        if state[i] != goal[i]:
            score = score + 1
    return score

# Node data structure
class Node:
    def __init__( self, state, parent, operator, depth, cost ):
        # Contains the state of the node
        self.state = state
        # Contains the node that generated this node
        self.parent = parent
        # Contains the operation that generated this node from the parent
        self.operator = operator
        # Contains the depth of this node (parent.depth +1)
        self.depth = depth
        # Contains the path cost of this node from depth 0. Not used for depth/breadth first.
        self.cost = cost

def readfile( filename ):
    f = open( filename )
    data = f.read()
    # Get rid of the newlines
    data = data.strip( "\n" )
    #Break the string into a list using a space as a seperator.
    data = data.split( " " )
    state = []
    for element in data:
        state.append( int( element ) )
    return state

# Main method
def main():
    ### CHANGE THIS FUNCTION TO USE bfs, dfs, ids or a_star
    result = bfs( starting_state, goal_state )
    if result == None:
        print "No solution found"
    elif result == [None]:
        print "Start node was the goal!"
    else:
        print result
        print len(result), " moves"

# A python-isim. Basically if the file is being run execute the main() function.
if __name__ == "__main__":
    main()
#/usr/bin/python
#
###学生信息
#史密斯,克里斯托弗,02386569159.302
#作业1:8。
#
###语言
#这个作业是用Python编写的。一种开源的解释性语言
#混合了命令式、面向对象和函数式编程。语法很简单
#而且容易学。
#
#在Ubuntu Linux上开发,但将在可用的解释器上运行
#从http://python.org. 该站点上也有文档,但这是一个很好的解决方案
#本教程免费提供,网址为http://diveintopython.org.
#
###数据结构
#
#电路板的状态存储在列表中。该列表存储
#董事会在以下职位:
#
# -------------
# | 0 | 3 | 6 |
# -------------
# | 1 | 4 | 7 |
# -------------
# | 2 | 5 | 8 |
# -------------
#
#目标定义为:
#
# -------------
# | 1 | 2 | 3 |
# -------------
# | 4 | 5 | 6 |
# -------------
# | 7 | 8 | 0 |
# -------------
#
其中0表示空白瓦片或空格。
目标状态=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0]
起始状态=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,0,15]
#
#代码将从名为“state.txt”的文件中读取state,其中的格式为
#如上所述,但空间分开。i、 e.目标状态的内容为
# 1 8 7 2 0 6 3 4 5
###代码开始。
导入系统
def显示板(状态):
打印“------------”
打印“|%i |%i |%i |”%(状态[0]、状态[1]、状态[2]、状态[3])
打印“------------”
打印“|%i |%i |%i |”%(状态[4]、状态[5]、状态[6]、状态[7])
打印“------------”
打印“|%i |%i |%i |”%(状态[8]、状态[9]、状态[10]、状态[11])
打印“------------”
打印“|%i |%i |%i |”%(状态[12]、状态[13]、状态[14]、状态[15])
打印“------------”
def上移(状态):
“”将空白的瓦片移动到板上。将新的状态作为列表返回。
#执行对象复制
新状态=状态[:]
索引=新状态。索引(0)
#健康检查
如果索引不在[0,1,2,3]中:
#交换值。
temp=新状态[索引-1]
新_状态[索引-1]=新_状态[索引]
新状态[索引]=临时
返回新状态
其他:
#无法移动,返回None(Pythons NULL)
一无所获
def下移(状态):
“”将空白瓦片移动到板上。将新的状态作为列表返回。
#执行对象复制
新状态=状态[:]
索引=新状态。索引(0)
#健康检查
如果索引不在[12,13,14,15]中:
#交换值。
temp=新状态[索引+1]
新_状态[索引+1]=新_状态[索引]
新状态[索引]=临时
返回新状态
其他:
#不能移动,不返回。
一无所获
def向左移动(状态):
“”移动在板上留下的空白瓦片。返回一个新的状态作为一个列表。
新状态=状态[:]
索引=新状态。索引(0)
#健康检查
如果索引不在[0,4,8,12]中:
#交换值。
temp=新状态[索引-4]
新_状态[索引-4]=新_状态[索引]
新状态[索引]=临时
返回新状态
其他:
#无法移动它,不返回任何值
一无所获
def向右移动(状态):
“”在板上移动空白瓦片。返回一个新的状态作为列表。
#执行对象复制。Python通过引用传递。
新状态=状态[:]
索引=新状态。索引(0)
#健康检查
如果索引不在[3,7,11,15]中:
#交换值。
temp=新状态[索引+4]
新_状态[索引+4]=新_状态[索引]
新状态[索引]=临时
返回新状态
其他:
#不能移动,不返回
一无所获
def create_节点(状态、父级、操作员、深度、成本):
返回节点(状态、父节点、操作员、深度、成本)
def展开_节点(节点,节点):
“”“返回扩展节点的列表”“”
扩展的_节点=[]
扩展的_节点。追加(创建_节点(向上移动(node.state),节点,“u”,node.depth+1,0))
扩展的_节点.append(创建_节点(向下移动(node.state),节点,“d”,node.depth+1,0))
扩展的_节点。追加(创建_节点(向左移动(node.state),节点,“l”,node.depth+1,0))
扩展的_节点.append(创建_节点(向右移动(node.state),节点,“r”,node.depth+1,0))
#过滤列表并删除不可能的节点(move函数返回None)
扩展的_节点=[如果node.state!=无,则扩展的_节点中的节点对应节点]#列表理解!
返回扩展的节点
def bfs(开始、目标):
“”“从开始状态到目标执行广度优先搜索”“”
#节点的列表(可以用作队列)。
节点=[]
#创建包含根节点的队列。
追加(创建_节点(开始、无、无、0、0))
尽管如此:
#我们的州已经用完了,没有解决办法。
如果len(节点)==0:返回None
#从队列前面获取节点
node=nodes.pop(0)
#将我们的移动附加到移动
#如果此节点是目标,请返回到达此处所需的移动。
如果node.state==目标:
移动=[]
温度=节点
尽管如此:
移动.插入(0,临时运算符)
如果温度深度==1:中断
临时=临时父项
回击动作
#展开节点并将所有展开添加到堆栈的前面
扩展(扩展_节点(节点,节点))
def dfs(开始、目标、深度=10):
"""