def best_first_graph_search(problem, f): """ Search the nodes with the lowest f scores first. You specify the function f(node) that you want to minimize; for example, if f is a heuristic estimate to the goal, then we have greedy best first search; if f is node.depth then we have breadth-first search. There is a subtlety: the line "f = memoize(f, 'f')" means that the f values will be cached on the nodes as they are computed. So after doing a best first search you can examine the f values of the path returned. """ f = memoize(f, 'f') node = Node(problem.getStartState()) if problem.isGoalState(node.state): return node frontier = PriorityQueue(min, f) frontier.push(node) explored = set() while frontier: node = frontier.pop() if problem.isGoalState(node.state): return node explored.add(node.state) for child in node.expand(problem): if child.state not in explored and not frontier.contains(child): frontier.push(child) elif frontier.contains(child): incumbent = frontier.__getitem__(child) if f(child) < f(incumbent): del frontier[incumbent] frontier.push(child) return None