1. goal_state = [1, 8, 7, 2, 0, 6, 3, 4, 5] #goal_state = [1, 0, 7, 2, 8, 6, 3, 4, 5] import sys global
count def display_board( state ): #print "-------------" print " %i %i %i " %
(state[0], state[3], state[6]) #print "-------------" print " %i %i %i " % (state[1],
state[4], state[7]) #print "-------------" print " %i %i %i " % (state[2], state[5],
state[8]) #print "-------------" def move_up( state ): new_state = state[:] index =
new_state.index( 0 ) if index not in [0, 3, 6]: temp = new_state[index - 1]
new_state[index - 1] = new_state[index] new_state[index] = temp return
new_state else: return None def move_down( state ): new_state = state[:]
index = new_state.index( 0 ) if index not in [2, 5, 8]: temp = new_state[index + 1]
new_state[index + 1] = new_state[index] new_state[index] = temp
return new_state else: return None def move_left( state ): new_state = state[:]
index = new_state.index( 0 ) if index not in [0, 1, 2]: temp = new_state[index
- 3] new_state[index - 3] = new_state[index] new_state[index] = temp
return new_state else: return None def move_right( state ): new_state =
state[:] index = new_state.index( 0 ) if index not in [6, 7, 8]: temp =
new_state[index + 3] new_state[index + 3] = new_state[index]
new_state[index] = temp return new_state else: return None def
create_node( state, parent, operator, depth, cost ): return Node( state, parent, operator,
depth, cost ) def expand_node( node, 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! expanded_nodes = [node for node in expanded_nodes if
node not in nodes] #list comprehension! #expanded_nodes = [node for node in
expanded_nodes if node.state!= ((node.parent).parent).state] #list comprehension!
expanded_nodes1 = [] for node in expanded_nodes: temp=node
temp=temp.parent temp=temp.parent if temp==None:
expanded_nodes1.extend(expanded_nodes) break if node.state
!=temp.state: expanded_nodes1.append(node) return
expanded_nodes1 def bfs( start, goal ): nodes = [] count=0 # 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)
2. count=count+1 #display_board(node.state) # 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: #display_board(node.state) moves = []
temp = node print count, " nodes " 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
#count=count+len(expand_node( node, nodes )) nodes.extend( expand_node( node,
nodes ) ) def dfs( start, goal, depth=12 ): depth_limit = depth # A list (can act as a
stack too) for the nodes. nodes = [] count=0 # 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)
count=count+1; #if this node is the goal, return the moves it took to get here. if
node.state == goal: moves = [] temp = node print
count, " nodes " while True: moves.insert(0, temp.operator)
if temp.depth <= 1: break temp =
temp.parent return moves #,count # 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 )
#node_count=node_count+count if result != None: return result def
a_star( start, goal ): # """Perfoms an A* heuristic search""" # ATTEMPTED: does
not work :( nodes = [] count=0 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_a_star ) # take the node from the front of the queue node =
nodes.pop(0) count=count+1 #display_board(node.state) # 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 print count, " nodes " 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,
3. nodes ) ) def cmp_a_star( x, y ): # Compare function for A*. f(n) = g(n) + h(n). I use depth
(number of moves) for g(). if (x.depth + h1( x.state, goal_state )) > (y.depth + h( y.state,
goal_state )): return 1 else: return -1 def h1(start,goal):
#Misplaced tiles no_misplaced_tiles = 0 for i in range(1,9): if
start.index(i)!=goal.index(i): no_misplaced_tiles += 1 return
no_misplaced_tiles def h( state, goal ): #Manhattan Distance score = 0 for i
in range( len( state ) ): if state[i] != goal[i]: for j in range(len(state)):
if(state[j] == state[i]): k = j
break diff = i-k if diff < 0: diff = diff *-1
score += diff%3 if diff<6 and diff>2: score = score +
1 if diff>6: score = score + 2 return score
def best_first( start, goal ): # """Perfoms an A* heuristic search""" # ATTEMPTED:
does not work :( nodes = [] count=0 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_bfs ) # take the node from the front of the queue node =
nodes.pop(0) #display_board(node.state) count=count+1 # 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 print count, "nodes" 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_bfs( x, y ): if h(x.state,goal_state) >= h(y.state,goal_state):
return 1 return -1 # 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 printpath(directions, starting_state): state = starting_state
display_board(state) print ' ----- ' for d in directions: if d == 'u':
state = move_up(state) if d == 'd': state = move_down(state)
if d == 'l': state = move_left(state) if d == 'r':
state = move_right(state) display_board(state) print ' ----- ' # Main
method def main(): starting_state = [2, 1, 7,8, 6, 0, 3, 4, 5] choice = 5
4. if choice==1: print "BFS"
result = bfs( starting_state, goal_state ) if choice==2:
print "DFS" result= dfs( starting_state,
goal_state ) if choice==3:
print "IDS" result = ids( starting_state, goal_state )
if choice==4: print "Best First"
result = best_first( starting_state, goal_state ) if choice==5:
print "A star" result = a_star( starting_state, goal_state )
if result == None: print "No solution found"
elif result == [None]: print "Start node was the goal!" else:
printpath(result,starting_state) print len(result), " moves" if __name__ ==
"__main__": main()
Solution
goal_state = [1, 8, 7, 2, 0, 6, 3, 4, 5] #goal_state = [1, 0, 7, 2, 8, 6, 3, 4, 5] import sys global
count def display_board( state ): #print "-------------" print " %i %i %i " %
(state[0], state[3], state[6]) #print "-------------" print " %i %i %i " % (state[1],
state[4], state[7]) #print "-------------" print " %i %i %i " % (state[2], state[5],
state[8]) #print "-------------" def move_up( state ): new_state = state[:] index =
new_state.index( 0 ) if index not in [0, 3, 6]: temp = new_state[index - 1]
new_state[index - 1] = new_state[index] new_state[index] = temp return
new_state else: return None def move_down( state ): new_state = state[:]
index = new_state.index( 0 ) if index not in [2, 5, 8]: temp = new_state[index + 1]
new_state[index + 1] = new_state[index] new_state[index] = temp
return new_state else: return None def move_left( state ): new_state = state[:]
index = new_state.index( 0 ) if index not in [0, 1, 2]: temp = new_state[index
- 3] new_state[index - 3] = new_state[index] new_state[index] = temp
return new_state else: return None def move_right( state ): new_state =
state[:] index = new_state.index( 0 ) if index not in [6, 7, 8]: temp =
new_state[index + 3] new_state[index + 3] = new_state[index]
new_state[index] = temp return new_state else: return None def
create_node( state, parent, operator, depth, cost ): return Node( state, parent, operator,
depth, cost ) def expand_node( node, 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
5. + 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! expanded_nodes = [node for node in expanded_nodes if
node not in nodes] #list comprehension! #expanded_nodes = [node for node in
expanded_nodes if node.state!= ((node.parent).parent).state] #list comprehension!
expanded_nodes1 = [] for node in expanded_nodes: temp=node
temp=temp.parent temp=temp.parent if temp==None:
expanded_nodes1.extend(expanded_nodes) break if node.state
!=temp.state: expanded_nodes1.append(node) return
expanded_nodes1 def bfs( start, goal ): nodes = [] count=0 # 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)
count=count+1 #display_board(node.state) # 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: #display_board(node.state) moves = []
temp = node print count, " nodes " 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
#count=count+len(expand_node( node, nodes )) nodes.extend( expand_node( node,
nodes ) ) def dfs( start, goal, depth=12 ): depth_limit = depth # A list (can act as a
stack too) for the nodes. nodes = [] count=0 # 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)
count=count+1; #if this node is the goal, return the moves it took to get here. if
node.state == goal: moves = [] temp = node print
count, " nodes " while True: moves.insert(0, temp.operator)
if temp.depth <= 1: break temp =
temp.parent return moves #,count # 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
6. optional.""" for i in range( depth ): result = dfs( start, goal, i )
#node_count=node_count+count if result != None: return result def
a_star( start, goal ): # """Perfoms an A* heuristic search""" # ATTEMPTED: does
not work :( nodes = [] count=0 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_a_star ) # take the node from the front of the queue node =
nodes.pop(0) count=count+1 #display_board(node.state) # 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 print count, " nodes " 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_a_star( x, y ): # Compare function for A*. f(n) = g(n) + h(n). I use depth
(number of moves) for g(). if (x.depth + h1( x.state, goal_state )) > (y.depth + h( y.state,
goal_state )): return 1 else: return -1 def h1(start,goal):
#Misplaced tiles no_misplaced_tiles = 0 for i in range(1,9): if
start.index(i)!=goal.index(i): no_misplaced_tiles += 1 return
no_misplaced_tiles def h( state, goal ): #Manhattan Distance score = 0 for i
in range( len( state ) ): if state[i] != goal[i]: for j in range(len(state)):
if(state[j] == state[i]): k = j
break diff = i-k if diff < 0: diff = diff *-1
score += diff%3 if diff<6 and diff>2: score = score +
1 if diff>6: score = score + 2 return score
def best_first( start, goal ): # """Perfoms an A* heuristic search""" # ATTEMPTED:
does not work :( nodes = [] count=0 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_bfs ) # take the node from the front of the queue node =
nodes.pop(0) #display_board(node.state) count=count+1 # 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 print count, "nodes" while True:
moves.insert( 0, temp.operator ) if temp.depth <=1:
break temp = temp.parent return moves #Expand the
7. node and add all expansions to the end of the queue nodes.extend( expand_node( node,
nodes ) ) def cmp_bfs( x, y ): if h(x.state,goal_state) >= h(y.state,goal_state):
return 1 return -1 # 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 printpath(directions, starting_state): state = starting_state
display_board(state) print ' ----- ' for d in directions: if d == 'u':
state = move_up(state) if d == 'd': state = move_down(state)
if d == 'l': state = move_left(state) if d == 'r':
state = move_right(state) display_board(state) print ' ----- ' # Main
method def main(): starting_state = [2, 1, 7,8, 6, 0, 3, 4, 5] choice = 5
if choice==1: print "BFS"
result = bfs( starting_state, goal_state ) if choice==2:
print "DFS" result= dfs( starting_state,
goal_state ) if choice==3:
print "IDS" result = ids( starting_state, goal_state )
if choice==4: print "Best First"
result = best_first( starting_state, goal_state ) if choice==5:
print "A star" result = a_star( starting_state, goal_state )
if result == None: print "No solution found"
elif result == [None]: print "Start node was the goal!" else:
printpath(result,starting_state) print len(result), " moves" if __name__ ==
"__main__": main()