I been working on this code for a while and can't seem to get it to work. I have started over multiple times. I am not sure if my logic is off or if I could be doing something better. Any suggestion in the right direction or new ideas to try would be helpful. I understand that a maze could be solved recursively but for this part of the assignment I need to use a stack.
I created two stacks. One for the path the other for spots I already searched. Ideally I would check to see if the searched path contains the next spot in a direction. If it does it checks another direction.
Sample maze
0 1 0 1 0
0 0 0 1 0
0 1 0 0 0
0 1 0 1 1
0 1 0 0 0
My algorithm seems to get stuck between 2,3 and 2,4. Never explores 1,4 or 0,4. I see it keep bouncing between 2,3 and 2,4 in an infinite loop. So it seems my searched.contains() is not functioning properly. Any suggestion to fix my searched stack? Ideally, when I run my code. I want it to check East, South, west then North has already been searched or not. If all points have been checked it will pop the last position from my path stack using current= path.pop inside the while loop and repeat.
Position is a custom class. I have considered adding a previous position variable to the constructor in the position class but seems to not to be needed if I can get my path stack to work. If I am wrong on this please let me know.
public static Position [] stackSearch(char [] [] maze){
//todo: your path finding algorithm here using the stack to manage search list
//your algorithm should modify maze to mark positions on the path, and also
//return array of Position objects coressponding to path, or null if no path found
ArrayDeque <Position> path = new ArrayDeque<Position>();
ArrayDeque <Position> searched = new ArrayDeque<Position>();
//creates position object
Position start = new Position(0,0,'0');
Position current;
Position north,south, east, west;
int i = 0; int j = 0;
//push (0,0) onto stack
path.push(start);
searched.push(start);
while(!path.isEmpty()){
current=path.pop();
i=current.i;
j=current.j;
if(i==maze.length-1 && j==maze.length-1 && maze[i][j]=='0'){
Position[] trail= new Position [path.size()];
while(!path.isEmpty()){
for(int k=0; k<path.size();k++){
trail[k]=path.pop();
}
return trail;
}
}
System.out.println(i +"," +j);
//check east.
east= new Position(i,j+1,'0');
south= new Position(i+1,j,'0');
west= new Position(i,j-1,'0');
north= new Position(i-1,j,'0');
if (j+1 >= 0 && j+1 < maze.length && maze[i][j+1] == '0' && searched.contains(east)==false)
{
searched.push(east);
path.push(current);
path.push(east);
}
//check south, add its position to the list.
else if (i+1 >= 0 && i+1 < maze.length && maze[i+1][j] == '0' && searched.contains(south)==false)
{
searched.push(south);
path.push(current);
path.push(south);
}
//check west.
else if (j-1 >= 0 && j-1 < maze.length && maze[i][j-1] == '0' && searched.contains(west)==false)
{
searched.push(west);
path.push(current);
path.push(west);
}
//check north
else if (i-1 >= 0 && i-1 < maze.length && maze[i-1][j] == '0' && searched.contains(north)==false)
{
searched.push(north);
path.push(current);
path.push(north);
}
}
return null;
}
I would guess that the problem lies, not in the code you posted, but rather in the Position class. If you have not overridden hashcode() and equals() in the Position class, the contains() comparison here will be looking for object equality.
So when you ask if searched.contains(east), having just created east as a new object, it will return false, even though east's coordinates perfectly match what is already in your search.
See this answer for more.
A common solution to solving a maze is BFS, which is both optimal and complete [it always find a solution if there is one, and also it finds the shortest one].
Using a stack, is actually simulating a DFS, which is not optimal.
About the specific problem, where contains() doesn't do its job, it will be hard to know what the problem is without the source for the class Position, but a possible reason is you did not override equals(), so the default equals() is still checking for identity, and not equality - which is obviously not true.
Related
I am currently trying to find a single path in a graph leading from source to sink. I am trying to implement a method using dfs to achieve this. However, i can't seem to figure out how to make the method to stop the recursion. For example, i have this graph (in matrix form)
0 1 1 0
0 0 0 1
0 0 0 1
0 0 0 0
So i have an edge from node 0 (the source) to node 1 and 2 respectively, and then an edge from 1 and 2 leading to 3 (the sink). The path i would want to have would be 0>1>3, instead i'm getting 0>1>3>2>3. How can i make the recursion stop as soon as a path to the sink is found?
Here is the code for the method:
public void dfsPath(int i) {
boolean[] visited = new boolean[this.edgeCapacities.length];
visited[i] = true;
this.path.add(i); //Integer ArrayList containing the nodes in the path
//loop through all of the nodes in the matrix to find adjacency
for (int j = 0; j < this.edgeCapacities.length; j++) {
//check if edge exists and node has not been visited
if (this.edgeCapacities[i][j] != 0 && !visited[j]) {
//here is the problem, i want the recursion to stop once the sink is found
//it does not work however.
if(j == this.sink) {
visited[j] = true;
this.path.add(j);
return;
} else {
//recursion
dfsPath(j);
}
}
}
Any help would be greatly appreciated. Thanks in advance.
There seem to be several problems with your DFS algorithm:
by creating a new visited list in each recursive call, it always contains only the current node
you are only adding nodes to this.path, but never removing nodes that did not lead to the goal
you never check whether one of your recursive calls reached the goal, thus adding more nodes to a perfectly good path
To fix this, you should remove the current node from this.path at the end of the method, i.e. in case no path has been found. Also, you can just drop the visited array and just check whether the next node is already in the path. That's not quite as fast, but should suffice for your case and make the code less complex. Also, the method should return true or false depending on whether it found a path.
Try this (not tested, but should work).
public boolean dfsPath(int i) {
this.path.add(i); // add current node to path
if (i == this.sink) {
return true; // if current node is sink, return true
// this.path contains nodes from source to sink
}
for (int j = 0; j < this.edgeCapacities.length; j++) {
if (this.edgeCapacities[i][j] != 0 && ! this.path.contains(j)) {
if (dfsPath(j)) {
return true; // found a path -> search no further
}
}
}
this.path.remove(this.path.size() - 1); // pop last node
return false; // no path found
}
Note that I also moved the sink-check out of the loop. This is purely a matter of taste, but it makes the code a bit simpler, as you don't have to add the sink node separately to the path.
I am writing a code for a class assignment to get a character through a maze. I have been working on this for hours and I can't figure out what I am doing wrong. The character moves left to right and right to left. Except when I add the code to have the character move around a block if (maze.moveRight() == false), it causes the character to move up and down at the end of each row a bunch of times before it moves the other direction. Also it messes up my count as the character moves across the rows. I feel like I am making it much more complicated than it should be. Can someone help?
Algorithm
The student always starts at the top left corner, that is row and column zero.
The Java logo can be anywhere in the maze, which also contains obstacles shown as "Wrong Way" signs.
You must traverse every row in the maze from top to bottom according to the rules below, until you find the Java logo.
Row and column numbers are zero based, so the first row and column is index 0. the second row and column is index 1, and so on. The number zero is even.
On even rows, you must move left to right using maze.moveRight(), on odd rows, you must move right to left using maze.moveLeft().
After completing each row, use maze.moveDown() to proceed to the next row, until you reach the last row or find the Java logo.
You can detect that you have encountered an obstacle by checking the return value from move methods in the Maze object, true means no obstacle, false means obstacle.
If you run into an obstacle when when moving left to right: Move down, right, right, and up.
Adjustment the loop counter for the extra move right!
If you run into an obstacle when when moving right to left: Move down, left, left, and up. Adjustment the loop counter for the extra move left!
Every time you move left or right, not including when avoiding an obstacle, you must call maze.isDone() to see if you have found the Java logo.
When you find the Java logo, you must immediately break out of all loops, and exit the program.
There are mazes that cannot be solved using the algorithm, but we will not test your program with any of them.
public static void main(String[] args) {
// Create maze
String fileName = args[1];
Maze maze = new Maze(fileName);
System.out.println("Maze name: " + fileName);
// Get dimensions
int mazeWidth = maze.getWidth();
int mazeHeight = maze.getHeight();
// Print maze size
System.out.println("Maze width: " + mazeWidth);
System.out.println("Maze height: " + mazeHeight);
int r = 0;
int c = 0;
// Move commands
while (c < maze.getWidth() - 1 && r % 2 == 0 && maze.isDone() == false)
{
maze.moveRight();
maze.isDone();
c++;
if (maze.moveRight() == false && maze.isDone() == false){
maze.moveDown();
maze.moveRight();
maze.moveRight();
maze.moveUp();
}
if (maze.isDone() == true){
System.exit(1);
}
}
while (c == maze.getWidth() - 1 && r % 2 == 0 && maze.isDone() == false)
{
maze.moveDown();
maze.isDone();
r++;
}
while (c != 0 && c <= maze.getWidth() -1 && r % 2 != 0
&& maze.isDone() == false){
maze.moveLeft();
maze.isDone();
c--;
if (maze.moveLeft() == false && maze.isDone() == false) {
maze.moveDown();
maze.moveLeft();
maze.moveLeft();
maze.moveUp();
}
if (maze.isDone() == true){
System.exit(1);
}
}
}
I'm having a hard time following what your intent is and thus what the problem is. Perhaps it's due to lack of understanding of how this maze is set up. I also don't know the scope of the class so I don't know if this is above your current level or not, but here goes how I would personally implement a maze solver:
For each position in a maze that I find myself, I would create a maze "space" object. This object will keep track of remaining options of directions to be traversed and whether or not I have visited that space. If I can turn left and right, I would create new spaces for both, pick one direction, and mark only that one direction to say I've been there. When I reach a dead end, I will turn around until I find a choice of direction to go. If I've not visited a direction, I'd take that. Otherwise, If I've visited all ways, I would call a recursive function to determine if there are any directions available along down any of the paths I've taken previously.
So it's creating objects, using recursion, and flagging an object for whether or not I've been there. (you'd also need a flag to indicate if your recursive algorithm has checked a square as well lest you find yourself in an infinite loop).
Hopefully that's within the constraints of the assignment! Otherwise, we may need more information as to what the limitations are and the true scope of the assignment.
Ok so a few problems you are only moving down on the right wall.
You aren't updating your row column counters when you are navigating hazards.
You should be testing the results of every move and isDone method call and breaking or updating your counters accordingly.
Also you shouldn't be updating your counters as you do outside an if statement associated with a move test method call.
I've written a prototype in java that employs a movable character and tile-based graphics and game logic. The layout of each level is stored in a 10x10 2D array. When I use the following code to detect whether or not the player is colliding with a '1' (empty) tile, it only returns positive when the player is colliding with the final '1' tile in the array, why is this? I understand this method is incredibly inefficient.
for(int r = 0; r < levArray.length; r++) {
for(int c = 0; c < levArray[0].length; c++) {
if(levArray[r][c] == 1) {
if(px >= r*64-9 && px <= (r+1)*64+11 && py >= c*64-30 && py <= (c+1)*64+30) {
isColliding = true;
} else {
isColliding = false;
}
}
}
}
You need to stop looping (for example with break) when you find a collision. Now you loop all the way through and the isColliding variable will be set to whatever the last item in the array is.
You are checking every element of the level against the player position (px,py). Since the only control in these loops is the iteration itself, the last comparison that happens is at the last cell. Any result from previous calculations will be overwritten by this last calculation.
As Kayaman says, you can break or return to exit the loop; better would be to check the player position against the level, instead of checking the level against the player. You know where the player is, if you convert that px,py coordinate into r,c coordinates you only have to look at one element in the level array.
My friend is making a minesweeper clone and he asked me to help with the part where when you click on a non-mine/non-number 'blank' square it reveals all adjacent blanks. The following is the code I wrote. I can't figure out why it never resolves.
My base case should be when the for loops completely execute and the if statement never returns true.
Is there something I'm missing?
This is in java, by the way. Also, I told him the whole slew of button state changing should be assigned to a method :p
public void revealAdjacentNulls(int r, int c)
{
int ir, ic;
//literal edge cases :P
int rmax = (r == 15) ? r : r + 1;
int cmax = (c == 15) ? c : c + 1;
//check all spaces around button at r,c
for(ir = (r==0) ? 0 : r-1; ir <= rmax; ir++){
for (ic = (c==0) ? 0 : c-1; ic <= cmax; ic++){
//if any are blank and uncovered, reveal them, then check again around the blanks
if (buttons[ir][ic].value == 0 && buttons[ir][ic].isCovered == false)
{
buttons[ir][ic].setEnabled(false); //number uncovered
buttons[ir][ic].setBackground(Color.blue);
buttons[ir][ic].setText(Character.toString(buttons[ir][ic].value));
buttons[ir][ic].isCovered = false;
revealAdjacentNulls(ir, ic);
}
}
}
}
Let's consider the case when r==0 and c==0, and let's assume that buttons[0][0].value == 0 and that buttons[0][0].isCovered == false.
The very first iteration of the loop will cause the function to call itself with the same arguments, 0, 0, and with unchanged state of value and isCovered. This will instantly lead to infinite recursion.
P.S. Check out the Wikipedia article for other flood fill algorithms.
Well for one thing, it will always keep recursing for revealAdjacentNulls(r, c). Your condition is that isCovered must be false - but then you're setting isCovered to false as well. Did you mean to write:
buttons[ir][ic].isCovered = true;
? Or possibly your check should be:
if (buttons[ir][ic].value == 0 && buttons[ir][ic].isCovered)
(It depends on what you mean by "is covered".)
Another case: if r == 15 then the loop will be from 14 (r - 1) to 15 (rmax). If your if statement is true, then there will be infinite recursion. The same applies to c.
I am having a lot of trouble with this task. Using the Wikipedia definition for a complete binary tree:
A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible
I need a way of checking for these conditions, but no matter how much I try, I can't seem to come up with anything. If I were to pass a TreeNode tree input into a checkComplete method how could I go about going through the binary tree and checking that it is complete? Can anyone help with pseudocode or an explanation of how this is possible? There was another question here: How to determine whether a binary tree is complete?
This one had an answer with pseudocode in it, but I couldn't understand where all the random variables were coming from or what they were meant to represent or why there were two values in brackets in the last 3 lines. If anyone could help with another representation I'd really appreciate it.
int CT()
{
int lh=0, rh=0, sign=1;
if (!root->left && !root->right)
return 1;
if (!root->left && root->right)
return 0;
lh = CT(root->left);
rh = CT(root->right);
if (lh == 0 || rh == 0)
return 0;
if (lh < 0 && rh < 0)
return 0;
if (lh < 0 || rh < 0)
sign = -1;
if (|lh| == |rh| )
return (|lh|+1)*sign;
elseif (rh == lh-1)
return -(|lh|+1);
else return 0;
}
if CT returns '0' - its not a complete tree.
'-' is used to check mismatch in height is encountered on one subtree only.
Traverse the tree left-to-right. There are several critical points at which you'll want to store or compare information:
When you hit the first leaf node.
When you hit subsequent leaf nodes.
When you hit the first leaf node with a different distance from the root.
Since this is homework, you should probably take it the rest of the way from that hint.