I'm trying to solve a maze using recursion. It's declared Cell [][] maze.
public class Cell {
private Wall left;
private Wall right;
private Wall up;
private Wall down;
private boolean end;
// Setters and getters not shown
}
If there is no Wall for some side of the cell then it has value null, else it refers to a Wall object. Wall references are consistent: Both cells adjacent to single wall refer to it with the appropriate fields. If a wall is missing, then both adjacent cells have corresponding null entries. Here is the search:
public boolean solveMaze(Cell[][] maze, int i, int j) {
if (maze[i][j].isEnd()){
System.out.println(maze[i][j].toString());
return true;
}
if (maze[i][j].getDown() == null) {
return solveMaze(maze, i, j + 1);
}
if (maze[i][j].getUp() == null) {
return solveMaze(maze, i, j - 1) ;
}
if (maze[i][j].getLeft() == null) {
return solveMaze(maze, i - 1, j);
}
if (maze[i][j].getRight() == null) {
return solveMaze(maze, i + 1, j) ;
}
return false;
}
I'm getting a Stack Overflow error. What is wrong with my recursion stop condition?
Update:
With your highly appreciated help I solved this problem: This is correct solution which works flawless:
public boolean solveMaze(Cell[][] maze, int i, int j){
if (maze[i][j].isEnd()){
System.out.println("Maze Exit :["+i+","+j+"]" );
return true;
}
if (maze[i][j].isVisited()){
return false;
}
maze[i][j].setVisited(true);
if ((maze[i][j].getButtom() == null) ){
if (solveMaze(maze,i,j+1)==true)
return true;
}
if ((maze[i][j].getUp() == null) ){
if ( solveMaze(maze,i,j-1) ==true )
return true;
}
if ((maze[i][j].getLeft() == null)){
if (solveMaze(maze,i-1,j))
return true;
}
if ((maze[i][j].getRight() == null)){
if (solveMaze(maze,i+1,j))
return true;
}
maze[i][j].setVisited(false);
return false;
}
may be it will be helpful for any body in the future.
If the maze has a cycle, the solver can run around this cycle forever, which will cause the stack overflow you're seeing. You need a way of determining when you're seeing a maze square that's already been seen. In this case you should backtrack immediately.
This can be done either with a boolean flag visited in each cell initially set to false and then set true for each square you search, or you can maintain a separate Set of (i,j) pairs that have been searched, which is initially empty.
NB: Your use of i and j is unconventional. If someone else wrote the maze reading code with the conventional usage, this could be causing a problem. In math, i is usually used for the row number and j for the column. With this convention your wall tests do not agree with your increments and decrements. Missing the bottom wall would require you to increment i for example.
It seems to me like you're running in circles in your solver method.
I suggest you familiarize yourself with Breadth-First Search, which is often used for not too big state-search problems.
If you have some "knowledge", a heuristic, on how to search the maze then you might also take a look at A-Star Search
What BFS could do in your case is the following: (BTW, be nice and use appropriate construtors, getters and setters)
public class Cell {
public int x;
public int y;
public Cell parent;
#Override
public boolean equals(Object obj) {
// TODO Override equals so it only incudes x and y coorinates, and not parent
return true;
}
#Override
public int hashCode() {
// TODO Override hash code as well
return 0;
}
}
public Cell seachFor(Cell start, Cell finish) {
Queue<Cell> open = new LinkedList<>();
Set<Cell> closed = new HashSet<>();
open.add(start);
while (!open.isEmpty()) {
Cell current = open.poll();
if (current.equals(finish)) {
return current;
}
closed.add(current);
for (Cell neighbour : getNeighbours(current)) {
if (!closed.contains(neighbour)) {
open.add(neighbour);
}
}
}
return null;
}
private List<Cell> getNeighbours(Cell current) {
/* TODO Set the neighbour's "parent"
* Return valid adjacent neighbour cells
*/
return null;
}
public Deque<Cell> pathfinder(Cell start) {
Deque<Cell> path = new ArrayDeque<>();
path.push(start);
Cell current = start;
while (current.parent != null) {
current = current.parent;
path.push(current);
}
return path;
}
public static void main(String[] args) {
Cell start = maze.getStart();
Cell finish = maze.getFinish();
Deque<Cell> path = pathFinder(searchFor(start, finish))
while (!path.isEmpty()) {
Cell current = path.pop();
maze.moveTo(current);
}
}
Note that this is a mock code and you need to refine it before it works.
You do not have anything in your code to detect places you've already been before. If your maze contains any passages in which you can go in a circle or loop back to someplace you've been before without backtracking, it will continue to recurse down that same path infinitely.
First you go down until you reach a wall. Then, one up - then down again. And one up, and one down - until java detects that this is pretty silly and stops with a StackOverFlowError ;)
your running out of memory allocated on the stack. aka your recursion is multiply too fast where you exceed the resources of the JVM at the given time.
you can increase memory and then kill all the other iterations of this method, or change your algorithim. Changing the stacksize would be a poor solution but it may work even though your code if flawed howto increase the stacksize in eclipse I would suggest marking which areas you already visited
the maze is Cell[][] maze
public class Cell{
boolean visited = false;
Wall left;
Wall right;
Wall up;
Wall bottom;
boolean end;
//Settters and Getters
}
set that visited variable to true each time you hit it and then change your code to
public boolean solveMaze(Cell[][] maze, int i, int j){
if (maze[i][j].isEnd()){
System.out.println(maze[i][j].toString());
return true;
}
if (maze[i][j].getButton() == null)&&(maze[i][j].visited==false)){
return solveMaze(maze,i,j+1);
}
if (maze[i][j].getUp() == null){
return solveMaze(maze,i,j-1) ;
}
// ect
I wont implement it unless you have issues doing it yourself, with interview questions I think its neat if you solve them yourself with hints that way you get the feeling that you could solve something similar again, where if you just read and understand an answer you may be able to reiterate the answer to the same problem but you may not be able to come up with a novel answer to a similar problem using similar strategies.
Related
We are implementing the rules of the game called Hive. In the game the Spider piece can only move three Hexagons.
We are trying to find a path using dfs, but the problem is that our dfs search stops after looking at one branch.
We tried to make use of depth - 1. So when the depth == 0 then it should go to the next branch. But it seems that something is wrong with the return statement.
What's wrong with this recursion?
public Set findPathForSpider(Game game, Point origin, Point destination, Point actualOrigin, Set<Point> hasVisited, int depth) throws Exception {
if(origin.equals(destination)) {
game.moveWithoutRestriction(destination.x, destination.y, actualOrigin.x, actualOrigin.y);
return hasVisited;
}
if(depth == 0) {
return new HashSet();
}
hasVisited.add(origin);
for (Point emptyNeighbor : getEmptyNeighbors(game, origin)) {
if (!hasVisited.contains(emptyNeighbor)) {
if (!game.isHiveBrokenAfterPush(origin, emptyNeighbor)) {
hasVisited.add(emptyNeighbor);
game.moveWithoutRestriction(origin.x, origin.y, emptyNeighbor.x, emptyNeighbor.y);
return findPathForSpider(game, emptyNeighbor, destination, actualOrigin, hasVisited, depth - 1);
}
}
}
return new HashSet();
}
We call the findPathForSpider in the spiderRestrictions that is in a Game class. The recursion depth is 3
public boolean spiderRestrictions(Point originPoint, Point destinationPoint) throws Exception{
Set path = b.findPathForSpider(this, originPoint, destinationPoint, originPoint, new HashSet<>(), 3);
return !path.isEmpty() &&
!originPoint.equals(destinationPoint) &&
b.isHexagonEmpty(destinationPoint);
}
While trying to run the code for 24 Tile puzzle and above, the code executes for a very long time (Greater than 3 minutes) (It runs pretty quick for 8 Tile puzzle). The code can be found below.
while (openQueue.isEmpty() == false) {
State queueHead = openQueue.remove();
openMap.remove(queueHead.hashCode());
closedMap.put(queueHead.hashCode(), queueHead);
State queueHeadState = queueHead;
if (Constants.debug) {
System.out.println("Popped State");
HeuristicSolverUtility.printState(queueHead);
}
// If reached goal state . Termination condition.
if (queueHead.equals(goalState)) {
break;
} else {
List<Action> listOfPossibleActions = queueHeadState
.getPossibleActions();
Iterator<Action> actIter = listOfPossibleActions.iterator();
while (actIter.hasNext()) {
// Here it performs Tile UP, DOWN, LEFT and RIGHT operations
Action actionOnState = actIter.next();
StateP newState = actionOnState.applyTo(queueHeadState);
newState.setHeuristicCost((double) ManhattanDistance
.calculate(newState));
newState.setParent(queueHead);
newState.setAction(actionOnState);
if (!closedMap.containsKey(newState.hashCode()) && !openMap.containsKey(newState.hashCode())) {
openQueue.offer(newState);
openMap.put(newState.hashCode(), newState);
} else if (openMap.containsKey(newState.hashCode())) {
System.out.println("State found in Open Map");
State stateFetchedFromOpenMap = openMap.get(newState.hashCode());
if (stateFetchedFromOpenMap.getPathCost() > newState.getPathCost()) {
openMap.remove(stateFetchedFromOpenMap.hashCode());
openMap.put(newState.hashCode(), newState);
openQueue.remove(stateFetchedFromOpenMap);
openQueue.add(newState);
}
}
}
}
}
This is my hashcode :
#Override
public int hashCode() {
return Arrays.hashCode(allCells);
}
And this is the code for Priority Queue comparator :-
public static class HeuristicComparator implements Comparator<State> {
public int compare(State o1, State o2) {
Double result;
result = o1.getKey() - o2.getKey();
if (result == 0.0) {
// Ties among minimal f values are resolved in favor of the
// deepest node in the search tree
// i.e. the closest node to the goal
result = (double) (o2.getPathCost() - o1.getPathCost());
}
if (result > 0.0) {
return 1;
}
return -1;
}
}
I am not sure why does it take so long for my A* implementation to compute for 24 tile puzzle and up. How can I optimize my code to compute faster, also is there any bug that is causing it to take so long?
If you are interested in the entire code, it can be found here
As Turing85 has mentioned, this is an NP-complete problem, so it's unlikely that you will have a fast runtime.
I would suggest that you can do the following:
Try to use different heuristic
Try to use bidirectional search
I know this is an old question, but I just had the same problem.
Apparently, Arrays.hashCode(allCells); is really really slow, and using another hash code can make the algorithm run much faster.
Try this answer for alternative hash.
I have this algorithm and I want to implement a graph search, using recursive backtracking.
First of all my code:
public static boolean buildTree(GenericTreeNode<String> inputNode){
while(!interruptFlag)
{
try { Thread.sleep(200); } catch(InterruptedException e) {}
gui.frame.MainWindow.progress.setText("Iterations Deployment: " + c);
gui.panel.ResultMatrix.setResult(mappingList);
Multimap<String,String> openList = LinkedHashMultimap.create();
openList = UtilityClasses.getOpenList.getOpenList(dataMap, ApplicationList, HardwareList, mappingList);
if(openList.isEmpty() && !mappingList.keySet().containsAll(XMLParser.ApplicationsListGUI))
{
gui.frame.MainWindow.labelSuccess.setText("Mapping not succesful!");
return false;
}
if(openList.isEmpty() && mappingList.keySet().containsAll(XMLParser.ApplicationsListGUI))
{
System.out.println(calculateOverallCost.getOverallCosts());
System.out.println("Mapping done:" + " " + mappingList);
gui.panel.ResultMatrix.setResult(mappingList);
return true;
}
if(!openList.isEmpty() && (!mappingList.keySet().containsAll(XMLParser.ApplicationsListGUI)))
{
for(String s : openList.keySet())
{
for(String h : openList.get(s))
{
GenericTreeNode<String> child = new GenericTreeNode<String>(s + ":" + h);
inputNode.addChild(child);
child.setCosts(UtilityClasses.CostFunction.calculateCostFunction(s, h));
}
}
List<GenericTreeNode<String>> childlist = inputNode.getChildren();
Collections.sort(childlist);
for(int i = 0; i < childlist.size() ; i++)
{
inputNode = childlist.get(i);
// do something
if (buildTree(inputNode))
{
return true;
}
else
{
// undo something
}
}
Thats the code I have so far. It builds the tree in everystep. Every node in the tree is a possible solution, ordered by a heuristic costfunction. The first 2 if-clauses are the conditions to terminate and return. If there is a solution, it finds it pretty smoothly. But if there is no quick solution, I need to undo the last step and try some other combinations. In the worst case, every combination should be tested.
The childlist holds every child nodes, ordered by their costfunction. The one with the least costfunction, will be chosen for expansion. Building the tree is done recursively, but I have problems with the backtracking. I dont get the search to go back a step and try the second best node and so on. The graph is expanded every step with the new calculated openList. I saved a reference to the parent node, if that could be a help.
The openlist is a list, which holds every possible next step -> nodes.
Maybe this picture will help explaining my problem better:
thats more or less the search I wanted to realize. But the code i have till now, stucks at the end of a leave, no matter if a solution is found or not. I tried many different things, but this backtracking dont seem to work, for my kind of problem or at least I cant get it going.
If I understood correctly, this needs a pre-order tree vist.
I ommited some details, but I think this code will help you (I haven't test it):
public static boolean buildTree(GenericTreeNode<String> inputNode) {
if (interruptFlag) {
// search was interrupted
// answer has not be found yet
return false;
}
boolean something = openList.isEmpty() && !mappingList.keySet().containsAll(XMLParser.ApplicationsListGUI);
if (something) {
// ... Mapping not succesful!
// answer can't be found
return false;
}
boolean answerFound = openList.isEmpty() && (mappingList.keySet().containsAll(XMLParser.ApplicationsListGUI));
if (answerFound) {
// ...
return true;
}
// answer has not been found
// visit each children
// order children list by cost
// ...
List<GenericTreeNode<String>> childlist = // ...
Collections.sort(childlist);
for (int i = 0; i < childlist.size(); i++) {
inputNode = childlist.get(i);
// do something
boolean childHasAnswer = buildTree(inputNode);
if (childHasAnswer) {
// answer was found
return true;
} // else: our children do not have the answer
}
// neither we or our children have the answer, let's go to the parent
return false;
}
I mainly deleted the first while, and deleted the last else.
I am trying to make a deductive Algorithm for solving a Sudoku puzzle. My Board is made up of 81 Nodes in an ArrayList.
- Each Node has a boolean Value
I want my algorithm (called CRME) to be continue to try and solve the puzzle if it finds that at least one of the nodes has it's boolean value (hasChanged) equal to true but I am unsure how to do this. canChange is also a global variable in the class this method is contained in.
public void CRME() {
canChange = true;
while (canChange == true) {
for (Node node : cells) {
scanColumn(node);
scanRow(node);
scanMiniGrid(node);
}
}
}
public void scanRow(Node n){
for(Node node : cells){
int arraySize = node.posVals.size();
ArrayList<Integer> toRemove = new ArrayList<Integer>();
if(node.get_ROW_ID() == n.get_ROW_ID()){
toRemove.add(node.getValue());
}
n.posVals.removeAll(toRemove);
if(arraySize < node.posVals.size()){
node.hasChanged = true;
}
}
}
This is the scanRow method, the two other similarly named methods are the same but with the obvious syntax changed, such as node.get_ROW_ID(); would be node.get_COL_ID();.
I assume you have a static variable
static boolean hasChanged; // in the Node class
so you can use:
node.hasChanged = true;
or you can create hasChange method to set the variable like so
boolean hasChanged;
public void hasChanged(boolean val){
this.hasChanged = val;
}
and use in the loop, like so:
hasChanged(true); or hasChanged(false);
Not saying your approach is best, but if you are trying to simply continue while one of hasChanged is true for any of your nodes, the following will suffice:
public void CRME()
{
goOn = false;
for (Node node : yourArrayListOfNodes)
{
if (node.hasChanged)
{
goOn = true;
break;
}
}
if (goOn)
{
//Insert Whatever code you want to run after the check
//.........................................
//Use recursion to repeat process
//Note recursive call will only take place if goOn is true
CRME()
}
}
This seems like what you want to do, just note that if your logic is incorrect, you can get a StackOverflowError, since you would keep making recursive calls.
I'm trying to implement A-Star in Java based on OSM Data. My problem is that my implementation is not working correctly. First of all the path is not the shortest. Second the closedlist contains more 1/3 more nodes in the end as Dijkstra. Thats actuall not that what I expected.
Here is my A-Star code which is based on Wikipedia Pseudocode
public Object[] executeAstar(ArrayList<Arclistentry> data, NodeD start, NodeD dest,long[] nodenur)
{
openlist = new PriorityQueue<NodeD>(1,comp);
closedlist.clear();
openlist.offer(start);
start.setg(0);
start.seth(calccost(start, dest));
start.setf(start.getg()+start.geth());
while(!openlist.isEmpty())
{
NodeD currentnode = openlist.poll();
if(currentnode.getnodenumber() == dest.getpredessor())
{
closedlist.add(currentnode);
return drawway(closedlist, start, dest);
}
closedlist.add(currentnode);
ArrayList<Arclistentry> entries = neighbors.get((int)currentnode.getnodenumber()-1);
for(Arclistentry aentry:entries)
{
NodeD successor = new NodeD(aentry.getnode(),aentry.getstart(), aentry.getcoorddest());
float tentative_g = currentnode.getg()+calccost(currentnode,successor);//+aentry.getcost();
if(contains(successor, closedlist))
{
continue;
}
if((contains(successor,openlist))&& tentative_g >= aentry.getcost())
{
continue;
}
if(!contains(successor, openlist))
{
successor.setpredessor(currentnode.getnodenumber());
successor.setg(tentative_g);
successor.seth(calccost(successor, dest));
successor.setf(successor.getg()+successor.geth());
openlist.offer(successor);
}
else
{
openlist.remove(successor);
successor.setpredessor(currentnode.getnodenumber());
successor.setg(tentative_g);
successor.seth(calccost(successor, dest));
successor.setf(successor.getg()+successor.geth());
openlist.offer(successor);
}
}
}
return drawway(closedlist,start, dest);
}
My Heuristics will be calculated by using the euclidian distance. But to consider also the cost of the node, the costs are multiplied with the heuristics result. My Data structure contains the following:
private long nodenumber;
private long predessor;
private float label;
private float f;
private float g;
private float h;
private double[] coord = new double[2];
public NodeD(long nodenr, long predessor, double[] coor)
{
this.nodenumber = nodenr;
this.predessor = predessor;
this.coord = coor;
}
public NodeD(long nodenr, long predessor, float label)
{
this.nodenumber = nodenr;
this.predessor = predessor;
this.label = label;
}
and for the arclist I use the following:
private long start;
private long dest_node;
private float cost_;
private double[]coordstart = new double[2];
private double[]coorddest = new double[2];
Contains Function for Priority Queue:
public boolean contains(NodeD o, PriorityQueue<NodeD> al)
{
Iterator<NodeD> e = al.iterator();
if (o==null)
{
while (e.hasNext())
{
if (e.next()==null)
{
return true;
}
}
}
else
{
while (e.hasNext())
{
NodeD t = e.next();
if(t.equals(null))
{
return false;
}
if (((o.getnodenumber()==t.getnodenumber()) & (o.getpredessor()==t.getpredessor()))||(o.getnodenumber()==t.getpredessor() & o.getpredessor()==t.getnodenumber()))
{
return true;
}
}
return false;
}
return false;
}
and contains for ArrayList (because it was not detecting right with the ArrayList.contains function
public boolean contains(NodeD o, ArrayList<NodeD> al) {
return indexOf(o,al) >= 0;
}
public int indexOf(NodeD o, ArrayList<NodeD> al) {
if (o == null) {
for (int i = 0; i < al.size(); i++)
if (al.get(i)==null)
return i;
} else {
for (int i = 0; i < al.size(); i++)
{
if ((o.getpredessor()==al.get(i).getpredessor())) //(o.getnodenumber()==al.get(i).getnodenumber()) &&
{
return i;
}
else if((o.getpredessor()==al.get(i).getnodenumber())&&(o.getnodenumber()==al.get(i).getpredessor()))
{
return i;
}
}
}
return -1;
}
The problem is that the algorithm is visiting all nodes. The other problem is the sorted openlist, which is pushing neighbors of the currentnode up, because they have a lower f value. So what I'm duing wrong by implementing this algorithm?
Recap of all our previous answers:
Make sure the A* estimation is a lower estimate otherwise it will wrongly skip parts
Do not iterate over all nodes to determine the index of the edges of your current node's edge set in an array
When creating new objects to put in your queue/sets, checks should be done on the properties of the nodes
If your focus is on speed, avoid as much work as possible by aborting non-interesting searches as soon as possible
I'm still unsure about this line:
if((contains(successor,openlist))&& tentative_g >= aentry.getcost())
What I think you are trying to do is to avoid adding a new node to the queue when you already have a better value for it in there. However, tentative_g is the length of the path from your starting node to your current node while aentry.getcost seems to be the length of the edge you are relaxing. That doesn't seem right to me... Try to retrieve the correct (old) value to compare against your new tentative label.
Lastly, for your current code, I would also make the following changes:
Use HashSet for your closedlist. Every time you check if a node is in there, you have to go over them all, which is not that efficient... Try using a HashSet by overriding the hash function of your NodeD objects. The built-in contains-function is much faster than your current approach. A similar argument can be made for your openlist. You cannot change the PQ to a set but you could omit the contains-checks. If you add a node with a bad priority, you will always first poll the correct priority (because it PQ) and could then, when polling the bad priority, just skip it. That's a small optimisation that trades off size of PQ to PQ lookup-operations
avoid recalculating stuff (mainly calccost()) by calculating it once and reusing the value when you need it (small time gain but nicer code).
try to avoid multiple lines with the same code by placing them on the correct line (e.g. 2 closedlist.add function can be merged to 1 add-call placed above the if condition, if you have something like if(..){doA();doB()}else{doA();doC();} try to put doA() before the if for legibility)