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(); } }