141 wiersze
5,3 KiB
Java
141 wiersze
5,3 KiB
Java
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<SearchNode> explored;
|
|
private NodeQueue frontier;
|
|
protected ArrayList<SearchNode> 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<SearchNode> 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<SearchNode>();
|
|
// 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<SearchNode>();
|
|
|
|
|
|
/*
|
|
* 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<GridPos> 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 <class>" 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<SearchNode>" 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<GridPos> 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<SearchNode> getPath() {
|
|
return path;
|
|
}
|
|
|
|
public ArrayList<SearchNode> getFrontierNodes() {
|
|
return new ArrayList<SearchNode>(frontier.toList());
|
|
}
|
|
public ArrayList<SearchNode> getExploredNodes() {
|
|
return new ArrayList<SearchNode>(explored);
|
|
}
|
|
public ArrayList<SearchNode> getAllExpandedNodes() {
|
|
ArrayList<SearchNode> allNodes = new ArrayList<SearchNode>();
|
|
allNodes.addAll(getFrontierNodes());
|
|
allNodes.addAll(getExploredNodes());
|
|
return allNodes;
|
|
}
|
|
|
|
}
|