Find all possible hamiltonian cycles in a partially oriented graph - java

This is my algorithm to find a Hamiltonian cycle in a graph:
private SolutionArray solution;
private int V, pathCount;
private int[] path;
private int[][] graph;
/**
* Constructor
*/
public ConcreteSolver() {
solution = new SolutionArray();
}
#Override
public SolutionArray solve(PathMatrix input) {
V = input.getNbVertex();
path = new int[V];
/** Set all path to non-visited **/
boolean[] visited = new boolean[V];
for (int i = 0; i < V; i++) {
visited[i] = false;
}
Arrays.fill(path, -1);
graph = input.getMatrix();
try {
path[0] = input.getFirstVertex();
pathCount = 1;
findPaths(0);
System.out.println("No solution");
} catch (Exception e) {
System.out.println("\nSolution found");
//input.printMatrix();
displayAndWrite();
}
return solution;
}
/**
* function to find paths recursively
*/
private void findPaths(int vertex) throws Exception {
/** solution **/
if (graph[vertex][0] >= 1 && pathCount == V) {
throw new Exception();
}
/** all vertices selected but last vertex not linked to 0 **/
if (pathCount == V)
return;
for (int v = 0; v < V; v++) {
/** if connected **/
if (graph[vertex][v] >= 1) {
/** add to path **/
path[pathCount++] = v;
/** if vertex not already selected solve recursively **/
if (!isPresent(v))
findPaths(v);
/** remove path **/
path[--pathCount] = -1;
}
}
}
/**
* function to check if path is already selected
*/
private boolean isPresent(int v) {
for (int i = 0; i < pathCount - 1; i++)
if (path[i] == v)
return true;
return false;
}
I'm able to find a single first Hamiltonian cycle. Is it possible to adapt it to find all possible Hamiltonian cycles found in the graph?
The input is a non-symmetrical matrix (some links between nodes are one way) and some nodes may have 2 or 3 links to other nodes.
Thank you
EDIT:
To clarify, the algorithm can already find a solution but cannot find a second one and so on. From reading, A* using bactracking might solve the issue but I'm not sure if it can be added to what I already have.

Currently you have a single array to capture the current path being explored. presumably your displayAndWrite method uses this information to print the solution.
To record all solutions you need to take a copy of the path when you find a hamiltonian cycle.
Somthing like:
private static final int MAX_SOLUTIONS = 100;
private int[][] solutions = new int[MAX_SOLUTIONS][];
private int solutionCount = 0;
private void addSolution(int[] path) {
if (solutionCount < MAX_SOLUTIONS)
solutions[solutionCoun++] = Arrays.copyOf(path, path.length);
}
You need to call addSolution in the recursive method where you currently through the exception.
As an aside, throwing an exception to denote success would be considered poor style by nearly all experienced Java coders. I expect the same is true in other languages - exceptions are for exceptions :-)

Right now, you throw an Exception when you have detected a cycle:
if (graph[vertex][0] >= 1 && pathCount == V) {
throw new Exception();
}
Aside from the fact that throwing an Exception is the wrong thing to do here because it is not really an exceptional condition - see my comment on the question - all you need to do is to make the action to take when you have found the cycle less "explosive".
Without knowing the definition of SolutionArray I can't give an answer making use of that.
Since you don't know how many cycles you might find, add a List to gather your solutions:
private List<int[]> solutions = new ArrayList<>();
Now, when you find a solution, just add something to this list - and then return from the method:
if (graph[vertex][0] >= 1 && pathCount == V) {
solutions.add(java.util.Arrays.copyOf(path, V));
return;
}
Because this simply returns from the method, rather than throwing an exception, the execution of the calling function continues on to check the next possible path.
It is important that you take a copy of the path, because otherwise you will simply add a reference to the array that you are using as your working copy - so they will all be the same array, and, because you might update it after, will not even necessarily contain a valid solution at the end.
Then, in your main method, just check if this list is non-empty:
if (!solutions.isEmpty()) {
System.out.println("\nSolution(s) found");
displayAndWrite();
}

Related

Java - Content of List is lost in recursion

I'm currently programming on a little project (which is way to specific to explain here) and I got everything working except one part. I've got a List pZiegel by parameter which is modified in recursion. Because it didn't work, I did a little debugging and found the problem: At one point, the list contains exactly one number at the end of the method. Then, the program jumps one recursion depth back. And directly after that, it doesn't contains any numbers anymore. How did it lose the number? Lists as parameters work with pass-by-reference, so it shouldn't just reject it, right?
public void erstelleBaum (Tree pTree, List<Integer> pZiegel, List<Integer> pFugen, int tiefe) {
if (tiefe / n >= maxHoehe) {
System.out.println("hi");
mauerGefunden = true;
alleFugen = pFugen;
}
if (!mauerGefunden) {
pZiegel.toFirst();
while (pZiegel.hasAccess() && !mauerGefunden) {
boolean ziegelHinzufügen = false;
möglich = true;
aktZiegel = pZiegel.getContent();
// ...
if (möglich) {
// ...
pZiegel.remove();
if (pZiegel.isEmpty()) {
ziegelHinzufügen = true;
pZiegel = new List();
for (int i = 1; i <= n; i++) {
pZiegel.append(i);
}
}
// Recursion
erstelleBaum(neuesBlatt, pZiegel, neueFugen, neueTiefe);
// Here, it tells me that pZiegel is empty (at recursion depth 17)
if (ziegelHinzufügen) {
pZiegel.toFirst();
while (pZiegel.hasAccess()) {
pZiegel.remove();
}
pZiegel.append(aktZiegel);
}
else {
pZiegel.toFirst();
while (pZiegel.hasAccess() && pZiegel.getContent() < aktZiegel) {
pZiegel.next();
}
if (pZiegel.hasAccess()) {
pZiegel.insert(aktZiegel);
pZiegel.toFirst();
while (pZiegel.getContent() != aktZiegel) {
pZiegel.next();
}
}
else {
pZiegel.toLast();
pZiegel.append(aktZiegel);
pZiegel.toLast();
}
}
}
pZiegel.next();
}
}
// Here, pZiegel contained one number (at recursion depth 18)
}
I hope, the code isn't too messy. I tried to keep out the parts that doesn't involve pZiegel. And sorry, that the variables are named in german. I didn't want to change them for this post because I know I would forget to change something in the code.
Feel free to ask, if something is unclear.
I believe the pZiegel List reference is being lost at some point. You should check the pZiegel object ID (a number displayed when you inspect the object) to make sure it is the same List instance all over the recursions.
Notice that there's one part of your code that makes the pZiegel identifier reference a new List:
...
if (pZiegel.isEmpty()) {
ziegelHinzufügen = true;
pZiegel = new List(); // <---- this line
for (int i = 1; i <= n; i++) {
pZiegel.append(i);
}
}
...
I believe you are calling the 18th recursion with pZiegel referencing one list (maybe empty). Inside the 18th recursion that line is called and pZiegel starts referencing a new List (realize that the last List still exists and is referenceed by the pZiegiel identifier of the 17th recursion). On the last line of the 18th recursion call you believe you are inspecting the same pZiegiel List from the 17th recursion, but that's not the case.

Implementing an equals() method to compare contents of two 'bag' objects

I am working on a school assignment. The objective is to practice GUI's, clone() methods, and using/ modifying existing code. I am trying to write an equals method in the way the instructor desires-- by using a clone of the object, removing items from the bag (returns boolean based on success or failure to remove).
The bag is represented in an array, and should return true in cases such as {1,2,3} and {3,2,1}, ie order does not matter, only the number of each number present in the arrays.
Here is the issue
It works in most cases, however there is a bug in cases where the bags contain numbers as such: {1,1,2} and {1,2,2} and other similar iterations. It is returning true instead of false.
I believe it has something to do with the remove() method we are supposed to use. If i understand it correctly, it is supposed to put the value at the 'end' of the array and decrease the manyItems counter (this is a variable for number of items in the array, because array.length is by default in the constructor 10.)
The code is largely written by another person. We had to import the existing files and write new methods to complete the task we were given. I have all the GUI part done so i will not include that class, only the used methods in the IntArrayBag class.
A second pair of eyes would be helpful. Thanks.
public class IntArrayBag implements Cloneable
{
// Invariant of the IntArrayBag class:
// 1. The number of elements in the bag is in the instance variable
// manyItems, which is no more than data.length.
// 2. For an empty bag, we do not care what is stored in any of data;
// for a non-empty bag, the elements in the bag are stored in data[0]
// through data[manyItems-1], and we don�t care what�s in the
// rest of data.
private int[ ] data;
private int manyItems;
public IntArrayBag( )
{
final int INITIAL_CAPACITY = 10;
manyItems = 0;
data = new int[INITIAL_CAPACITY];
}
public IntArrayBag clone( )
{ // Clone an IntArrayBag object.
IntArrayBag answer;
try
{
answer = (IntArrayBag) super.clone( );
}
catch (CloneNotSupportedException e)
{ // This exception should not occur. But if it does, it would probably
// indicate a programming error that made super.clone unavailable.
// The most common error would be forgetting the "Implements Cloneable"
// clause at the start of this class.
throw new RuntimeException
("This class does not implement Cloneable");
}
answer.data = data.clone( );
return answer;
}
public int size( )
{
return manyItems;
}
public boolean remove(int target)
{
int index; // The location of target in the data array.
// First, set index to the location of target in the data array,
// which could be as small as 0 or as large as manyItems-1; If target
// is not in the array, then index will be set equal to manyItems;
for (index = 0; (index < manyItems) && (target != data[index]); index++)
// No work is needed in the body of this for-loop.
;
if (index == manyItems)
// The target was not found, so nothing is removed.
return false;
else
{ // The target was found at data[index].
// So reduce manyItems by 1 and copy the last element onto data[index].
manyItems--;
data[index] = data[manyItems];
return true;
}
}
//I added extra variables that are not needed to try to increase readability,
//as well as when i was trying to debug the code originally
public boolean equals(Object obj){
if (obj instanceof IntArrayBag){
IntArrayBag canidate = (IntArrayBag) obj; // i know this can be changed, this was required
IntArrayBag canidateTest = (IntArrayBag) canidate.clone(); //this was created
//as a clone because it was otherwise referring to the same memory address
//this caused items to be removed from bags when testing for equality
IntArrayBag test = (IntArrayBag) this.clone();
//fast check to see if the two objects have the same number of items,
//if they dont will return false and skip the item by item checking
if (test.size() != canidateTest.size())
return false;
//the loop will go through every element in the test bag it will
//then remove the value that is present at the first index of the test bag
for (int i = 0; (i < (test.size()) || i < (canidateTest.size())); i++){
int check = test.data[i];
//remove() returns a boolean so if the value is not present in each bag
//then the conditional will be met and the method will return false
boolean test1 = test.remove(check);
boolean test2 = canidateTest.remove(check);
if (test1 != test2)
return false;
}//end for loop
// if the loop goes through every element
//and finds every value was true it will return true
return true;
}//end if
else
return false;
}//end equals
}
I cannot see the big picture, as I havent coded GUIs in Java before, however, as far as comparing 2 int[] arrays, I would sort the arrays before the comparison. This will allow you to eliminate problem cases like the one you stated ( if sorting is possible), then apply something like:
while(array_1[index]==array_2[index] && index<array_1.length)
{index++;}
and find where did the loop break by checking the final value of index
Is it explicitly stated to use clone? You can achieve it easily by overriding the hashCode() for this Object.
You can override the hashCode() for this object as follows:
#Override
public int hashCode() {
final int prime = 5;
int result = 1;
/* Sort Array */
Arrays.sort(this.data);
/* Calculate Hash */
for(int d : this.data) {
result = prime * result + d;
}
/* Return Result */
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || this.getClass() != obj.getClass()){
return false;
}
return false;
}
If you want to continue using your implementation for equals to compare test and CandidateTest then also you can compute unique hashes and make decision based on the results.
Here is the code snippet:
/* Assuming that you have put size comparison logic on top
and the two objects are of same size */
final int prime = 31;
int testResult = 1;
int candidateTestResult = 1;
for(int i = 0; i < test.size(); i++) {
testResult = prime * testResult + test.data[i];
candidateTestResult = prime * candidateTestResult + candidateTest.data[i];
}
/* Return Result */
return testResult == candidateTestResult;
I believe the problem is in this line:
for (int i = 0; (i < (test.size()) || i < (canidateTest.size())); i++){
The problem here is that test and canidateTest are the clones that you made, and you are removing elements from those bags. And any time you remove an element from the bag, the size will decrease (because you decrease manyItems, and size() returns manyItems). This means you're only going to go through half the array. Suppose the original size is 4. Then, the first time through the loop, i==0 and test.size()==4; the second time, i==0 and test.size()==3; the third time, i==2 and test.size()==2, and you exit the loop. So you don't look at all 4 elements--you only look at 2.
You'll need to decide: do you want to go through the elements of the original array, or the elements of the clone? If you go through the elements of the clone, you actually never need to increment i. You can always look at test.data[0], since once you look at it, you remove it, so you know test.data[0] will be replaced with something else. In fact, you don't need i at all. Just loop until the bag size is 0, or until you determine that the bags aren't equal. On the other hand, if you go through the elements of this.data (i.e. look at this.data[i] or just data[i]), then make sure i goes all the way up to this.size().
(One more small point: the correct spelling is "candidate".)
Maybe you should try SET interface
view this in detail :http://www.tutorialspoint.com/java/java_set_interface.htm
A set object cannot contains duplicate elements, so it's suitable for your assignment than build your own class.
For example:[1,1,2] and [1,2,2]
you can use this to test whether they are equal
arr1 = {1,1,2}
arr2 = {1,2,2}
Set<Integer> set = new HashSet<Integer>();
for(int i : arr1){//build set of arr1
if(set.contains(i)==false){
set.add(i)
}
}
for(int i:arr2){
if(set.contains(i)==false){
System.out.println('not equal');
break;
}
}
Hope this is helpful.

Recursive Backtracking in tree structure

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.

A-Star Algorithm is running like Dijkstra and delivers a wrong result

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)

Maze recursion solving StackOverflow error

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.

Categories