package aima.core.search.uninformed;
import java.util.List;
import aima.core.agent.Action;
import aima.core.search.framework.Metrics;
import aima.core.search.framework.Node;
import aima.core.search.framework.NodeExpander;
import aima.core.search.framework.QueueFactory;
import aima.core.search.framework.SearchForActions;
import aima.core.search.framework.SearchForStates;
import aima.core.search.framework.SearchUtils;
import aima.core.search.framework.problem.Problem;
import aima.core.search.framework.qsearch.GraphSearch;
import aima.core.search.framework.qsearch.QueueSearch;
/**
* Artificial Intelligence A Modern Approach (3rd Edition): Figure 3.11, page
* 82.<br>
* <br>
*
* <pre>
* function BREADTH-FIRST-SEARCH(problem) returns a solution, or failure
* node <- a node with STATE = problem.INITIAL-STATE, PATH-COST=0
* if problem.GOAL-TEST(node.STATE) then return SOLUTION(node)
* frontier <- a FIFO queue with node as the only element
* explored <- an empty set
* loop do
* if EMPTY?(frontier) then return failure
* node <- POP(frontier) // chooses the shallowest node in frontier
* add node.STATE to explored
* for each action in problem.ACTIONS(node.STATE) do
* child <- CHILD-NODE(problem, node, action)
* if child.STATE is not in explored or frontier then
* if problem.GOAL-TEST(child.STATE) then return SOLUTION(child)
* frontier <- INSERT(child, frontier)
* </pre>
*
* Figure 3.11 Breadth-first search on a graph.<br>
* <br>
* <b>Note:</b> Supports TreeSearch, GraphSearch, and BidirectionalSearch. Just
* provide an instance of the desired QueueSearch implementation to the
* constructor!
*
* @author Ciaran O'Reilly
* @author Ruediger Lunde
*/
public class BreadthFirstSearch implements SearchForActions, SearchForStates {
private final QueueSearch implementation;
public BreadthFirstSearch() {
this(new GraphSearch());
}
public BreadthFirstSearch(QueueSearch impl) {
implementation = impl;
// Goal test is to be applied to each node when it is generated
// rather than when it is selected for expansion.
implementation.setEarlyGoalTest(true);
}
@Override
public List<Action> findActions(Problem p) {
implementation.getNodeExpander().useParentLinks(true);
Node node = implementation.findNode(p, QueueFactory.<Node>createFifoQueue());
return node == null ? SearchUtils.failure() : SearchUtils.getSequenceOfActions(node);
}
@Override
public Object findState(Problem p) {
implementation.getNodeExpander().useParentLinks(false);
Node node = implementation.findNode(p, QueueFactory.<Node>createFifoQueue());
return node == null ? null : node.getState();
}
@Override
public NodeExpander getNodeExpander() {
return implementation.getNodeExpander();
}
@Override
public Metrics getMetrics() {
return implementation.getMetrics();
}
}