class TestExplored(unittest.TestCase): # noinspection PyPep8Naming def __init__(self, methodName='runTest'): super().__init__(methodName) self.explored = Explored() def test_exists(self): example_state = 'hello world' self.explored.add(example_state) self.assertTrue(self.explored.exists(example_state)) def test_non_exists(self): example_state = 'the quick brown fox jumps over the lazy dog' self.assertFalse(self.explored.exists(example_state))
def graph_search(problem): """graph_search(problem) - Given a problem representation attempt to solve the problem. Returns a tuple (path, path_cost) where: path - list of actions to solve the problem or None if no solution was found path_cost - Cost to execute the given path """ initial_node = Node(problem, problem.initial, problem.nodes[problem.initial]) frontier_nodes = PriorityQueue(min, Node.get_total_cost) frontier_nodes.append(initial_node) explored_nodes = Explored() nodes_explored = 0 while len(frontier_nodes) > 0: # Pop the next node from the frontier, add it to the explored set, # and increment the nodes_explored counter current_node = frontier_nodes.pop() explored_nodes.add(current_node.state) nodes_explored += 1 #Check to see if the current node is a goal state if current_node.problem.goal_test(current_node.state): return (current_node.path(), current_node.total_cost) #Generate the possible actions from the current_node successor_nodes = current_node.expand(problem) #For each successor_node, if it hasn't been explored, add it to the frontier set for node in successor_nodes: if explored_nodes.exists(node.state) is False: frontier_nodes.append(node) print("No solution found.") return (None, nodes_explored)
def graph_search(problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) - Given a problem representation (instance of basicsearch_lib02.representation.Problem or derived class), attempt to solve the problem. If debug is True, debugging information will be displayed. if verbose is True, the following information will be displayed: Number of moves to solution List of moves and resulting puzzle states Example: Solution in 25 moves Initial state 0 1 2 0 4 8 7 1 5 . 2 2 3 6 1 Move 1 - [0, -1] 0 1 2 0 4 8 7 1 . 5 2 2 3 6 1 Move 2 - [1, 0] 0 1 2 0 4 8 7 1 3 5 2 2 . 6 1 ... more moves ... 0 1 2 0 1 3 5 1 4 2 . 2 6 7 8 Move 22 - [-1, 0] 0 1 2 0 1 3 . 1 4 2 5 2 6 7 8 Move 23 - [0, -1] 0 1 2 0 1 . 3 1 4 2 5 2 6 7 8 Move 24 - [1, 0] 0 1 2 0 1 2 3 1 4 . 5 2 6 7 8 If no solution were found (not possible with the puzzles we are using), we would display: No solution found Returns a tuple (path, nodes_explored) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) """ rootNode = Node(problem, problem.initial) frontier = PriorityQueue() frontier.append(rootNode) frontierHash = {} frontierHash[hash(rootNode)] = rootNode done = found = False exploredNodes = Explored() while not done: node = frontier.pop() frontierHash.pop(hash(node), None) #print(node) exploredNodes.add(node) if node.problem.goal_test(node.state): found = done = True #print("finished with solution") else: nodes = [] for n in node.expand(node.problem): #may need to come back and compare boards instead of nodes if (hash(n) not in frontierHash or frontierHash[hash(n)] != n ) and exploredNodes.exists(n) == False: #print("adding to the frontier") nodes.append(n) for n in nodes: frontier.append(n) frontierHash[hash(n)] = n if len(frontier) == 0: print("finished, no solution") done = True if verbose == True: #print the path to the solution if found: path = node.path() solution = node.solution() print("Solution in ", len(solution), "moves") print("Initial state") counter = 1 for item in path: print(item.state) if counter <= len(solution): print("Move ", counter, " - ", solution[counter - 1]) counter = counter + 1 else: print("No solution found") if found == True: return (node.solution(), len(node.path())) else: return (None, None)
def graph_search(problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) - Given a problem representation (instance of basicsearch_lib02.representation.Problem or derived class), attempt to solve the problem. If debug is True, debugging information will be displayed. if verbose is True, the following information will be displayed: Number of moves to solution List of moves and resulting puzzle states Example: Solution in 25 moves Initial state 0 1 2 0 4 8 7 1 5 . 2 2 3 6 1 Move 1 - [0, -1] 0 1 2 0 4 8 7 1 . 5 2 2 3 6 1 Move 2 - [1, 0] 0 1 2 0 4 8 7 1 3 5 2 2 . 6 1 ... more moves ... 0 1 2 0 1 3 5 1 4 2 . 2 6 7 8 Move 22 - [-1, 0] 0 1 2 0 1 3 . 1 4 2 5 2 6 7 8 Move 23 - [0, -1] 0 1 2 0 1 . 3 1 4 2 5 2 6 7 8 Move 24 - [1, 0] 0 1 2 0 1 2 3 1 4 . 5 2 6 7 8 If no solution were found (not possible with the puzzles we are using), we would display: No solution found Returns a tuple (path, nodes_explored) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) """ #Initial tileboard for testing tb = problem.initial #Create first node and test if node passes goal node0 = Node(problem, tb) if problem.goal_test(node0.state) == True: return node0.solution() #define frontier set as priority queue and the explored set pq = PriorityQueue() pq.append(node0) new_nodes = [] exploredSet = Explored() frontier = Explored() frontier.add(node0) nodesExpanded = 0 #Expand the search tree until the goal state is found found = False #time.sleep(2) while (not found): #Check if the frontier is empty signifying failure if pq.__len__() == 0: print("No solution found") break #Take the next node from the priority queue and add it to explored set node = pq.pop() exploredSet.add(node) #Check if the goal state has been found if problem.goal_test(node.state) == True: path = node.path() solution = node.solution() steps = len(path) - 1 found = True if verbose == True: verboseFunc(solution, steps, tb, path) else: #Expand the search tree and check if the nodes have been explored new_nodes = node.expand(problem) for j in range(len(new_nodes)): if exploredSet.exists(new_nodes[j].state) or frontier.exists( new_nodes[j].state): continue else: #Add one to the number of nodes explored nodesExpanded += 1 pq.append(new_nodes[j]) #Add the nodes to the priority queue frontier.add( new_nodes[j]) #use hashed set to decrease lookup time if debug == True: debugFunc(debug, pq) return (steps, nodesExpanded)
def graph_search(problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) - Given a problem representation (instance of basicsearch_lib02.representation.Problem or derived class), attempt to solve the problem. If debug is True, debugging information will be displayed. if verbose is True, the following information will be displayed: Number of moves to solution List of moves and resulting puzzle states Example: Solution in 25 moves Initial state 0 1 2 0 4 8 7 1 5 . 2 2 3 6 1 Move 1 - [0, -1] 0 1 2 0 4 8 7 1 . 5 2 2 3 6 1 Move 2 - [1, 0] 0 1 2 0 4 8 7 1 3 5 2 2 . 6 1 ... more moves ... 0 1 2 0 1 3 5 1 4 2 . 2 6 7 8 Move 22 - [-1, 0] 0 1 2 0 1 3 . 1 4 2 5 2 6 7 8 Move 23 - [0, -1] 0 1 2 0 1 . 3 1 4 2 5 2 6 7 8 Move 24 - [1, 0] 0 1 2 0 1 2 3 1 4 . 5 2 6 7 8 If no solution were found (not possible with the puzzles we are using), we would display: No solution found Returns a tuple (path, nodes_explored, elapsed_s) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) elapsed_s is the elapsed wall clock time performing the search """ # Start the timer: timer = Timer() # Create a hashtable to store all explored states exploredStates = Explored() # Create a PriorityQueue to store all current states frontier = PriorityQueue(f=lambda node: node.g + node.h) # Initialize the frontier with the first Node frontier.append(Node(problem, problem.initial)) # Loop until the solution is found or the state space is exhausted while frontier.__len__() != 0: # Pop a node from the frontier node = frontier.pop() if problem.goal_test(node.state): alpha = node.path() actions = node.solution() # If verbose is True, display all moves if verbose: print(f'Solution in {len(actions)} moves') for i in range(len(actions)): print(f'Move {i + 1} - {actions[i]}') print(alpha[i + 1].state, end='\n\n') # Return a Tuple contains: # - List of actions to solve the problem, # - Number of nodes explored, # - elapsed_s in seconds return alpha, len(exploredStates.exploredStates), timer.elapsed_s() else: # Explore the children of current node for child in node.expand(problem): child_tuple = child.state.state_tuple() # if we haven't explored this child yet # Load it into frontier and explore set if not exploredStates.exists(child_tuple): exploredStates.add(child_tuple) frontier.append(child) # If no solution found, return None return None
def graph_search(problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) - Given a problem representation (instance of basicsearch_lib02.representation.Problem or derived class), attempt to solve the problem. If debug is True, debugging information will be displayed. if verbose is True, the following information will be displayed: Number of moves to solution List of moves and resulting puzzle states Example: Solution in 25 moves Initial state 0 1 2 0 4 8 7 1 5 . 2 2 3 6 1 Move 1 - [0, -1] 0 1 2 0 4 8 7 1 . 5 2 2 3 6 1 Move 2 - [1, 0] 0 1 2 0 4 8 7 1 3 5 2 2 . 6 1 ... more moves ... 0 1 2 0 1 3 5 1 4 2 . 2 6 7 8 Move 22 - [-1, 0] 0 1 2 0 1 3 . 1 4 2 5 2 6 7 8 Move 23 - [0, -1] 0 1 2 0 1 . 3 1 4 2 5 2 6 7 8 Move 24 - [1, 0] 0 1 2 0 1 2 3 1 4 . 5 2 6 7 8 If no solution were found (not possible with the puzzles we are using), we would display: No solution found Returns a tuple (path, nodes_explored) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) """ start = time.time() initial_node = Node(problem, problem.initial) node_queue = PriorityQueue(f=lambda x: x.get_f()) explore = Explored() explore.add(initial_node.state) node_num = 1 node = initial_node board = problem.initial solved = board.solved() while (not solved): newNodes = node.expand(problem) #Insert all new nodes into queues and explored for newNode in newNodes: if (not explore.exists(newNode.state)): explore.add(newNode.state) node_queue.append(newNode) node_num += 1 if newNode.state.solved(): node = newNode solved = newNode.state.solved() if len(node_queue) == 0: break if not solved: node = node_queue.pop() board = newNode.state second = (time.time() - start) actions = [a_node.action for a_node in node.path() if a_node.action] return (actions, node_num, second)
def graph_search(problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) - Given a problem representation (instance of basicsearch_lib02.representation.Problem or derived class), attempt to solve the problem. If debug is True, debugging information will be displayed. if verbose is True, the following information will be displayed: Number of moves to solution List of moves and resulting puzzle states Example: Solution in 25 moves Initial state 0 1 2 0 4 8 7 1 5 . 2 2 3 6 1 Move 1 - [0, -1] 0 1 2 0 4 8 7 1 . 5 2 2 3 6 1 Move 2 - [1, 0] 0 1 2 0 4 8 7 1 3 5 2 2 . 6 1 ... more moves ... 0 1 2 0 1 3 5 1 4 2 . 2 6 7 8 Move 22 - [-1, 0] 0 1 2 0 1 3 . 1 4 2 5 2 6 7 8 Move 23 - [0, -1] 0 1 2 0 1 . 3 1 4 2 5 2 6 7 8 Move 24 - [1, 0] 0 1 2 0 1 2 3 1 4 . 5 2 6 7 8 If no solution were found (not possible with the puzzles we are using), we would display: No solution found Returns a tuple (path, nodes_explored) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) """ frontierNodes = PriorityQueue(min, Node.get_f) node = Node(problem, problem.getInitialBoardState()) nodesExplored = 0 exploredStates = Explored() #hash table to store states exploredStates.add(node) for node in node.expand(problem): if not exploredStates.exists(node): #its not a duplicate in explored frontierNodes.append(node) #get initial frontier nodes done = found = False while not done: node = frontierNodes.pop() #loop thru frontier states nodesExplored += 1 exploredStates.add(node) if problem.goal_test(node.state): #if found, set true found = done = True else: #if not, then add the new frontier states to the queue for node in node.expand(problem): if not exploredStates.exists( node): #its not a duplicate in explored #if not frontierNodes.__contains__(node): #not a duplicate in frontier, slow! frontierNodes.append(node) if (frontierNodes.__len__ == 0 ): #if we run thru all frontier, search complete done = True if found: if (verbose): print("Moves to solution: ", node.path().__len__()) print("Nodes Expanded: ", nodesExplored) move = 0 solutionList = node.solution() boardList = [] for node in node.path(): boardList.append(problem.generateDebugBoard(node.state)) print("Initial State") for board in boardList: counter = move + 1 print(board) print() if (move < boardList.__len__() - 1): print("Move ", counter, " ", solutionList[move]) move += 1 if (debug): print() print("Debug Info:") print(print_nodes(node.path())) print() return (node.solution(), nodesExplored ) #returns solution node's path/solution else: if (verbose | debug): print("No solution found") return ("No solution found", nodesExplored)
def graph_search(problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) - Given a problem representation attempt to solve the problem. Returns a tuple (path, nodes_explored) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) """ frontier = PriorityQueue() root = Node(problem, problem.initial) frontier.append(root) node = frontier.pop() pop = True # for right pop left pop for BFS if node.expand(node.problem)[0].g < 0: # DFS which has the negative depth # since start from the deepest node frontier = deque() frontier.append(root) elif node.expand(node.problem)[0].h == 2: # BFS pop = False frontier = deque() frontier.append(root) else: # Manhattan frontier.append(node) DONE = False nodes_explored = 0 explored_set = Explored() while not DONE: if pop: node = frontier.pop() # DFS A* else: node = frontier.popleft() # BFS if debug: print("Next decision is:", str(node)) explored_set.add(node.state.state_tuple()) nodes_explored += 1 if problem.goal_test(node.state): solved_path = node.path() if debug: print("Puzzle solved") # print("path:", str(node.path())) DONE = True # if Verbose True display the info stats in requirement if verbose: print("Solution in %d moves" % (len(solved_path) - 1)) print("Initial State") print(solved_path[0]) for i in range(1, len(solved_path)): print("Move %d - %s" % (i, solved_path[i].action)) print(solved_path[i].state) return solved_path, nodes_explored # Not solved yet else: for child in node.expand(node.problem): # add new child to frontier set if not explored_set.exists(child.state.state_tuple()): frontier.append(child) explored_set.add(child) # finish when there is no node in the queue # if debug: # print("Num node in quenue:", str(len(frontier))) DONE = len(frontier) == 0 if verbose: print("No solution found") return None, nodes_explored
def graph_search(problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) - Given a problem representation (instance of basicsearch_lib02.representation.Problem or derived class), attempt to solve the problem. If debug is True, debugging information will be displayed. if verbose is True, the following information will be displayed: Number of moves to solution List of moves and resulting puzzle states Example: Solution in 25 moves Initial state 0 1 2 0 4 8 7 1 5 . 2 2 3 6 1 Move 1 - [0, -1] 0 1 2 0 4 8 7 1 . 5 2 2 3 6 1 Move 2 - [1, 0] 0 1 2 0 4 8 7 1 3 5 2 2 . 6 1 ... more moves ... 0 1 2 0 1 3 5 1 4 2 . 2 6 7 8 Move 22 - [-1, 0] 0 1 2 0 1 3 . 1 4 2 5 2 6 7 8 Move 23 - [0, -1] 0 1 2 0 1 . 3 1 4 2 5 2 6 7 8 Move 24 - [1, 0] 0 1 2 0 1 2 3 1 4 . 5 2 6 7 8 If no solution were found (not possible with the puzzles we are using), we would display: No solution found Returns a tuple (path, nodes_explored) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) """ #generate initial state, no parent/actions #based off of graph search example on slides node = Node(problem, problem.initial) if (problem.g == DepthFirst.g and problem.h == DepthFirst.h): frontierset = PriorityQueue(node.get_f()) else: frontierset = PriorityQueue() frontierset.append(node) done = False exploredset = Explored() expanded = 0 #number of expansions while not done: node = frontierset.pop() #print(node.__repr__()) exploredset.add(node.state) if problem.goal_test(node.state): done = True else: for nextaction in node.expand(problem): expanded += 1 if not exploredset.exists(nextaction.state): frontierset.append(nextaction) done = frontierset.__len__() == 0 if verbose: if (len(node.solution()) == 0): #No solutions found print("No solution found") else: print("Solution in ", len(node.solution()), " moves") print("Initial State") print(problem.initial) tempboard = problem.initial for i in range(0, len(node.solution())): print("Move ", i + 1, " - ", node.solution()[i]) tempboard = tempboard.move(node.solution()[i]) print(tempboard.__repr__()) return (node.solution(), expanded)
def graph_search(problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) - Given a problem representation (instance of basicsearch_lib02.representation.Problem or derived class), attempt to solve the problem. If debug is True, debugging information will be displayed. if verbose is True, the following information will be displayed: Number of moves to solution List of moves and resulting puzzle states Example: Solution in 25 moves Initial state 0 1 2 0 4 8 7 1 5 . 2 2 3 6 1 Move 1 - [0, -1] 0 1 2 0 4 8 7 1 . 5 2 2 3 6 1 Move 2 - [1, 0] 0 1 2 0 4 8 7 1 3 5 2 2 . 6 1 ... more moves ... 0 1 2 0 1 3 5 1 4 2 . 2 6 7 8 Move 22 - [-1, 0] 0 1 2 0 1 3 . 1 4 2 5 2 6 7 8 Move 23 - [0, -1] 0 1 2 0 1 . 3 1 4 2 5 2 6 7 8 Move 24 - [1, 0] 0 1 2 0 1 2 3 1 4 . 5 2 6 7 8 If no solution were found (not possible with the puzzles we are using), we would display: No solution found Returns a tuple (path, nodes_explored) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) """ # Create explored set and initialize variable to track nodes expanded explored = Explored() frontier = Explored() frontierQ = PriorityQueue() nodes_expanded = 0 # Create initial node as starting point and add to frontier initial_node = Node(problem, problem.puzzle.state_tuple()) frontierQ.append(initial_node) frontier.add(initial_node.state) node = None # Run while loop until graph search is complete done = found = False while not done: # Pop next node from frontier priority queue node = frontierQ.pop() if debug: print("Node:", node, "Action", node.action) # View node for debugging purposes # Add current node state to explored set state = node.state explored.add(state) if problem.goal_test(state): # If goal found, exit while loop and return found = done = True else: # If goal not found, loop through possible actions depending on state for act in problem.actions(state): next_state = problem.result(state, act) next_node = node.child_node(act) # Check if next node after action is in frontier queue or explored set if not explored.exists(next_state) and not frontier.exists(next_state): # If not, add to frontier and track the node as expanded frontier.add(next_state) frontierQ.append(next_node) nodes_expanded += 1 if not found: done = len(frontierQ) <= -1 # Exit loop if frontier is empty if not found: print("No solution found.") # This should not happen, we check if board is solvable in Tileboard class else: if verbose: # If verbose, print puzzle states and actions in path to solution print("Solution in", len(node.solution()), "moves") print(problem.puzzle) # Loop through each action in path for i, act in enumerate(node.solution()): problem.puzzle = problem.puzzle.move(act) # Display move taken and resulting puzzle board print("Move", i + 1, "-", act) print(problem.puzzle) if debug: print("*" * 10, "Win") # Divider for visualization during debugging return node.solution(), nodes_expanded
def graph_search(problem: Problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) - Given a problem representation (instance of basicsearch_lib02.representation.Problem or derived class), attempt to solve the problem. If debug is True, debugging information will be displayed. if verbose is True, the following information will be displayed: Number of moves to solution List of moves and resulting puzzle states Example: Solution in 25 moves Initial state 0 1 2 0 4 8 7 1 5 . 2 2 3 6 1 Move 1 - [0, -1] 0 1 2 0 4 8 7 1 . 5 2 2 3 6 1 Move 2 - [1, 0] 0 1 2 0 4 8 7 1 3 5 2 2 . 6 1 ... more moves ... 0 1 2 0 1 3 5 1 4 2 . 2 6 7 8 Move 22 - [-1, 0] 0 1 2 0 1 3 . 1 4 2 5 2 6 7 8 Move 23 - [0, -1] 0 1 2 0 1 . 3 1 4 2 5 2 6 7 8 Move 24 - [1, 0] 0 1 2 0 1 2 3 1 4 . 5 2 6 7 8 If no solution were found (not possible with the puzzles we are using), we would display: No solution found Returns a tuple (path, nodes_explored) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) """ # Establish frontier set and nodes frontier = PriorityQueue() frontier.append(Node(problem, problem.initial)) node = frontier.pop() popping = True if node.expand(node.problem)[0].g < 0: # Depth First Search frontier = deque() frontier.append(Node(problem, problem.initial)) elif node.expand(node.problem)[0].h < 2: # Breadth First Search popping = False frontier = deque() frontier.append(Node(problem, problem.initial)) else: # Manhattan Search frontier.append(node) # Working with the hash frontier_hash = Explored() frontier_hash.add(problem.initial.state_tuple()) finished = False nodes_explored = 0 explored = Explored() while not finished: if popping: node = frontier.pop() # Manhattan and DFS else: node = frontier.popleft() # BFS if debug: print("Node popped:", str(node)) explored.add(node.state.state_tuple()) nodes_explored += 1 if node.state.solved(): if debug: print("Solution found!") solution_path = node.path() finished = True if verbose: print_solution(solution_path) return solution_path, nodes_explored else: for child in node.expand(node.problem): if not explored.exists(child.state.state_tuple( )) and not frontier_hash.exists(child.state.state_tuple()): frontier.append(child) frontier_hash.add(child) elif debug: print("Skipping...", child) pass finished = len(frontier) == 0 if debug: print("") if verbose: print("No solution found") return None, nodes_explored
def graph_search(problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) -- Given a problem representation (instance of basicsearch_lib02.representation. Problem or derived class), attempt to solve the problem. If debug is True, debugging information will be displayed. if verbose is True, the following information will be displayed: Number of moves to solution List of moves and resulting puzzle states Example: Solution in 25 moves Initial state 0 1 2 0 4 8 7 1 5 . 2 2 3 6 1 Move 1 - [0, -1] 0 1 2 0 4 8 7 1 . 5 2 2 3 6 1 Move 2 - [1, 0] 0 1 2 0 4 8 7 1 3 5 2 2 . 6 1 ... more moves ... 0 1 2 0 1 3 5 1 4 2 . 2 6 7 8 Move 22 - [-1, 0] 0 1 2 0 1 3 . 1 4 2 5 2 6 7 8 Move 23 - [0, -1] 0 1 2 0 1 . 3 1 4 2 5 2 6 7 8 Move 24 - [1, 0] 0 1 2 0 1 2 3 1 4 . 5 2 6 7 8 If no solution were found (not possible with the puzzles we are using), we would display: No solution found Returns a tuple (path, nodes_explored) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) """ # PriorityQueue should be used to maintain the order of the queue. frontier = PriorityQueue() frontier.append(Node(problem, problem.initial)) current_node = frontier.pop() p = True #depth first search if current_node.expand(current_node.problem)[0].g < 0: frontier = deque() frontier.append(Node(problem, problem.initial)) #breadth first search elif current_node.expand(current_node.problem)[0].h < 2: p = False frontier = deque() frontier.append(Node(problem, problem.initial)) #manhattan else: frontier.append(current_node) f_hash = Explored() f_hash.add(problem.initial.state_tuple()) done = False n_explored = 0 explored = Explored() #graph_search while not done: if p: current_node = frontier.pop() else: current_node = frontier.popleft() explored.add(current_node.state.state_tuple()) n_explored = n_explored + 1 #inc the number of explored nodes if current_node.state.solved(): path = current_node.path() done = True return path, n_explored #if not found in the tree return none and number of nodes explored else: for child in current_node.expand(current_node.problem): if not explored.exists(child.state.state_tuple()) and not \ f_hash.exists(child.state.state_tuple()): frontier.append(child) f_hash.add(child) done = len(frontier) == 0 return None, n_explored
def __init__(self, methodName='runTest'): super().__init__(methodName) self.explored = Explored()
def graph_search(problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) - Given a problem representation (instance of basicsearch_lib02.representation.Problem or derived class), attempt to solve the problem. If debug is True, debugging information will be displayed. if verbose is True, the following information will be displayed: Number of moves to solution List of moves and resulting puzzle states Example: Solution in 25 moves Initial state 0 1 2 0 4 8 7 1 5 . 2 2 3 6 1 Move 1 - [0, -1] 0 1 2 0 4 8 7 1 . 5 2 2 3 6 1 Move 2 - [1, 0] 0 1 2 0 4 8 7 1 3 5 2 2 . 6 1 ... more moves ... 0 1 2 0 1 3 5 1 4 2 . 2 6 7 8 Move 22 - [-1, 0] 0 1 2 0 1 3 . 1 4 2 5 2 6 7 8 Move 23 - [0, -1] 0 1 2 0 1 . 3 1 4 2 5 2 6 7 8 Move 24 - [1, 0] 0 1 2 0 1 2 3 1 4 . 5 2 6 7 8 If no solution were found (not possible with the puzzles we are using), we would display: No solution found Returns a tuple (path, nodes_explored, elapsed_s) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) elapsed_s is the elapsed wall clock time performing the search """ """ uses a priority queue for the frontier and an instance of the Explored class for the explored set """ # list of actions to solution t = Timer() # starts the timer frontier = PriorityQueue( ) # we are always going to have a frontier and we always need to put in to priority queue explored = Explored() # explored set, NOT REALLY A SET, it is a dictionary frontier.append(Node(problem, problem.initial)) # add initial node to the frontier solution = None i = 0 # used for debug and verbose purposes while (frontier.__len__() > 0): current = frontier.pop() # Dequeue current node if (debug == True and i % 100000 == 0): print("############# %d #################" % i) # display iteration number print(current.state) # display current node print("nodes in frontier", frontier.__len__()) # display lenght of frontier set print("time elapsed %dmin %dsec" % (t.elapsed_s() / 60, t.elapsed_s() % 60)) # display time elapsed explored.add(current.state) # add current state to explored if problem.goal_test( current.state): # if the current state is the goal if debug: # used for debugging print( "###goal found, i = %d ###" % i ) # display the iteration number for when the goal was found print(current.state) # display current node print("length", len(current.path())) # display current node path length print("time elapsed %dmin %dsec" % (t.elapsed_s() / 60, t.elapsed_s() % 60)) # display time elapsed solution = current # found goal and end loop break else: child_nodes = current.expand( problem) # expand the state to find child nodes for child in child_nodes: if not explored.exists( child.state ): # if we haven't encountered the states yet frontier.append(child) # add it to the frontier explored.add( child.state ) # add to explored to prevent duplication in frontier i = i + 1 # used for debug and verbose purposes if solution != None and verbose == True: # if we found a solution and want more detail solution_path = solution.path() # create list of nodes to solution num_moves = len(solution_path) - 1 # number of moves to goal print("############# %d #################" % i) print("Solution in ", num_moves, " moves.\n") # heading of detail print("Intial state") print(solution_path[0]) # first state printed print("time elapsed %dmin %dsec" % (t.elapsed_s() / 60, t.elapsed_s() % 60)) # display time elapsed for i in range(1, len(solution_path)): # print each move in order print("\nMove ", i, "") # display move number print(solution_path[i]) # display move if solution == None: # no solution found print("no solution found") path = [] # if no solution found return empty list return ( path, len(explored.explored_set), t.elapsed_s() ) # return empty path, number of nodes explored and time elapsed else: # solution found return (solution.path(), len(explored.explored_set), t.elapsed_s() ) # return solution path, number of nodes expanded and time
def graph_search(problem, verbose=False, debug=False): """graph_search(problem, verbose, debug) - Given a problem representation (instance of basicsearch_lib02.representation.Problem or derived class), attempt to solve the problem. If debug is True, debugging information will be displayed. if verbose is True, the following information will be displayed: Number of moves to solution List of moves and resulting puzzle states Example: Solution in 25 moves Initial state 0 1 2 0 4 8 7 1 5 . 2 2 3 6 1 Move 1 - [0, -1] 0 1 2 0 4 8 7 1 . 5 2 2 3 6 1 Move 2 - [1, 0] 0 1 2 0 4 8 7 1 3 5 2 2 . 6 1 ... more moves ... 0 1 2 0 1 3 5 1 4 2 . 2 6 7 8 Move 22 - [-1, 0] 0 1 2 0 1 3 . 1 4 2 5 2 6 7 8 Move 23 - [0, -1] 0 1 2 0 1 . 3 1 4 2 5 2 6 7 8 Move 24 - [1, 0] 0 1 2 0 1 2 3 1 4 . 5 2 6 7 8 If no solution were found (not possible with the puzzles we are using), we would display: No solution found Returns a tuple (path, nodes_explored) where: path - list of actions to solve the problem or None if no solution was found nodes_explored - Number of nodes explored (dequeued from frontier) """ path = [] nodes_explored = 0 return_tuple = () node = Node(problem, problem.initial) # root node frontier = PriorityQueue(order=min, f=lambda x: x.get_f()) # todo Sort this out explored = Explored() frontier.append(node) if problem.goal_test(node.state): path = node.solution() return_tuple = (path, nodes_explored) return return_tuple counter = 0 while True: if frontier.__len__() == 0: path = node.solution() nodes_explored = counter return_tuple = (path, nodes_explored) return return_tuple node = frontier.pop() if problem.goal_test(node.state): break child_nodes = node.expand(problem) if explored.add(node.state): counter = counter + 1 for child_node in child_nodes: if child_node not in frontier and not explored.exists( child_node.state): frontier.append(child_node) path = node.solution() node_path = node.path() if verbose: print("Solution in " + str(len(node_path) - 1) + " moves.") i = 0 for sol in node_path: if i is 0: print("Initial state") print(sol.state) i = i + 1 continue print("Move " + str(i) + " - " + str(path[i - 1])) print(sol.state) i = i + 1 nodes_explored = counter return_tuple = (path, nodes_explored) return return_tuple