package searchCustom; import java.util.ArrayList; import java.util.HashSet; import searchShared.NodeQueue; import searchShared.Problem; import searchShared.SearchObject; import searchShared.SearchNode; import world.GridPos; public class CustomGraphSearch implements SearchObject { private HashSet explored; private NodeQueue frontier; protected ArrayList path; private boolean insertFront; /** * The constructor tells graph search whether it should insert nodes to front or back of the frontier */ public CustomGraphSearch(boolean bInsertFront) { insertFront = bInsertFront; } /** * Implements "graph search", which is the foundation of many search algorithms */ public ArrayList search(Problem problem) { // The frontier is a queue of expanded SearchNodes not processed yet frontier = new NodeQueue(); // The explored set is a set of nodes that have been processed explored = new HashSet(); // The start state is given GridPos startState = (GridPos) problem.getInitialState(); // Initialise the frontier with the start state frontier.addNodeToFront(new SearchNode(startState)); // Path will be empty until we find the goal. path = new ArrayList(); /* * Note on how java and this program work: * -ArrayList are just resizable array. "<>" contains the type of the listed objects * -Structures : * while (boolean) {} * while (a > 0) {} * for (int i = 0; i < 5; i++){} --> 5 iterations * for (String i : StringList){} --> Iterations on all the objects in the list * -Class used here: * -SearchNode --> Equivalent of the "Node" class in the Python program. Represent a node. * -Problem --> Class containing lot of informations on the problem * like the reachable states from a position, the start, the end * -GridPos --> represent a position (with x and y coordinates) */ // While we have something to explore while (frontier.size() > 0) { // Get the first node on the list SearchNode Node = frontier.removeFirst(); // We check if it is our destination if (problem.isGoalState(Node.getState())) { return path = Node.getPathFromRoot(); } // if not, we continue // Get the list of children of the current node ArrayList childPosition = problem.getReachableStatesFrom(Node.getState()); // For every child in the list for (GridPos position : childPosition) { // Creating a new node SearchNode childNode = new SearchNode(position, Node); // If we have not explored the node if (explored.contains(childNode) == false) { // Adding the child node to the frontier // Front --> DFS (LIFO queue) // Back --> BFS (FIFO queue) if (insertFront) { frontier.addNodeToFront(childNode); } else { frontier.addNodeToBack(childNode); } // We add the node to explored node explored.add(childNode); } } } /* Some hints: * -Read early part of chapter 3 in the book! * -You are free to change anything how you wish as long as the program runs, but some structure is given to help you. * -You can Google for "javadoc " if you are uncertain of what you can do with a particular Java type. * * -SearchNodes are the nodes of the search tree and contains the relevant problem state, in this case x,y position (GridPos) of the agent * --You can create a new search node from a state by: SearchNode childNode = new SearchNode(childState, currentNode); * --You can also extract the state by .getState() method * --All search structures use search nodes, but the problem object only speaks in state, so you may need to convert between them * * -The frontier is a queue of search nodes, open this class to find out what you can do with it! * * -If you are unfamiliar with Java, the "HashSet" used for the explored set means a set of SearchNode objects. * --You can add nodes to the explored set, or check if it contains a node! * * -To get the child states (adjacent grid positions that are not walls) of a particular search node, do: ArrayList childStates = p.getReachableStatesFrom(currentState); * * -Depending on the addNodesToFront boolean variable, you may need to do something with the frontier... (see book) * * -You can check if you have reached the goal with p.isGoalState(NodeState) * * When the goal is found, the path to be returned can be found by: path = node.getPathFromRoot(); */ /* Note: Returning an empty path signals that no path exists */ return path; } /* * Functions below are just getters used externally by the program */ public ArrayList getPath() { return path; } public ArrayList getFrontierNodes() { return new ArrayList(frontier.toList()); } public ArrayList getExploredNodes() { return new ArrayList(explored); } public ArrayList getAllExpandedNodes() { ArrayList allNodes = new ArrayList(); allNodes.addAll(getFrontierNodes()); allNodes.addAll(getExploredNodes()); return allNodes; } }