package search; import java.util.List; /** * Depth first search with a limit on the search depth. This version of depth first search * is a "tree search" style algorithm implemented using recursion. It does check for loops, * by avoiding visiting the same state more than once on a single search path from the root to * the bottom of the search recursion, however, it can visit states more than once if they * occur on multiple search paths. * * @author pippin * */ public class DepthLimitedSearch implements Search { private int limit = 0; // depth limit /** * Constructor * * @param limit: the depth limit at which the search will halt */ public DepthLimitedSearch(int limit) { this.limit = limit; } /** * Implements the pathSearch method of the Search interface. This implementation is * recursive and depth limited. * * @returns a list of states on the path to the goal, or null, if the goal * was not found within the given depth limit. */ public List<State> pathSearch(ProblemGraph graph, String startStateString) { GraphNode startNode = new GraphNode(graph.getState(startStateString)); if (startNode.getState().isGoal()) return startNode.getPath(); return expandNode(startNode, 0); } /** * Recursively expands a single node in the graph. * * @param node: the node being recursively expanded * @param depth: maximum search depth * @return a list of states on the path to the goal, or null if the goal was not found * on this particular branch of the search within the given depth. */ private List<State> expandNode(GraphNode node, int depth) { // if depth has passed the limit, return null if (depth >= limit) return null; // get children List<GraphNode> children = node.getState().expandNode(); for (GraphNode childNode : children) { // if the next child has already been visited on this specific search path, skip it if (node.visited(childNode)) continue; childNode.setParent(node); // check for goal - return parent chain from goal node if found. if (childNode.getState().isGoal()) return childNode.getPath(); // if not a goal, expand each child, setting the parent List<State> childResult = expandNode(childNode, depth+1); // if the childResult is null, keep searching. Otherwise, return the // solution found. if(childResult != null) return childResult; } // no more children to check - bottom of the recursion return null; } }