I am trying to implement a breadth first traversal for a maze. This is the code I have so far using a linked list but I am not sure if it is searching breadth first. Is this the proper way to do it? any suggestions, comments?
public boolean traverseBreadth(){
//traverse the floor from entrance to exit
//stepping only on red tiles
steps = new LinkedList<Tile>();
possibleSteps = new LinkedList<Tile>();
//reset markings
reset();
//push the entrance onto the stack
entrance.setVisited();
steps.add(entrance);
System.out.println("add " + entrance);
nextMoves(entrance);
//keep going as long as we have a possibility to move
//and we haven't reached the end yet
while (!possibleSteps.isEmpty()&& (!possibleSteps.getLast().equals(exit)))
{
Tile x = possibleSteps.removeLast();
x.setMarked(); //walked on that square
steps.add(x); //walk to that square
System.out.println("Walked to the square " + x);
//now figure out where you can walk from this square
nextMoves(x);
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
if (possibleSteps.getLast().equals(exit)){
steps.push(possibleSteps.removeLast());
System.out.println("made it from entrance to exit");
System.out.println(steps.toString());
return true;
}
else
{ JOptionPane.showMessageDialog(null,"sorry can't reach the exit");
return false;
}
}
This isn't a breadth first search - this is depth first.
There are 2 places that are obviously depth first
you remove from the end of the frontier (possibleTiles), not the beginning.
you do not have a traversal hierarchy (parent to child) to rebuild the traversal path, only a single "path" with tiles. Therefore, it is depth first.
Things to change:
instead of LinkedList, change that to Dictionary. The key of the dictionary will be the tile, and the value will be the tile's parent. Use this to reconstruct your final path.
your "moveNext" function is probably right. Make sure it is pushing to the end of the List.
do not pop (getLast()) from PossibleSteps. PossibleSteps should be a First-In-First-Out queue. Retrieve the first Tile of PossibleSteps (this will explore the tiles closest to the start first).
Things to improve:
instead of using Tile to track exploration, use a Set (call it ExploredTile) where you put tiles that you have traversed)
use a Queue instead of List.
Some C#/Pseudo Code (cuz I'm not at an IDE)
Dictionary<Tile,Tile> path = ...;
Queue<Tile> frontier = ...;
Set<Tile> explored = ...;
path[start] = null;
while(frontier.Count > 0){
var tile = frontier.Dequeue();
if(explored.Contains(tile)){
continue;
}
explored.add(tile);
if (Tile == Exit){
rebuildPath(Exit);
}else{
for (Tile t in Tile.neighbours){
if (!explored.Contains(t)){
frontier.Enqueue(t);
path[t] = tile; // Set the path hierarchy
}
}
}
}
RebuildPath
LinkedList<Tile> finalPath = ...;
Tile parent = path[exitTile];
finalPath.push(exitTile);
while(parent != null){
finalPath.push(parent);
parent = path[parent];
}
finalPath.reverse();
Hopefully I got it right... :)
Related
I am developing GUI for algorithm which finds path on grid GUI. Starting point is always 0,0 and is where starfish is located! For calculating destination I am using Random class which generates random x, y depending on grid bounds(of course). I opened debugger debugger results and see that my algorithm became infinite loop and is not able to find path, because at some point starfish starts moving left-right again and again, simply waste of moves. How can i solve this bug, I have hard time on solving it, can anyone help?
private Queue<Point> findPath(Rectangle[][] matrix, Point destPoint) {
Point move = null;
var dir = new ArrayList<Point>();
dir.add(new Point(1, 0)); // right
dir.add(new Point(0, 1)); // down
dir.add(new Point(-1, 0)); // left
dir.add(new Point(0, -1)); // up
Point start = new Point(0, 0);
var tmpPath = new ArrayDeque<Point>();
var path = new ArrayDeque<Point>();
tmpPath.add(new Point(0, 0));
while (!tmpPath.isEmpty()) {
for (int dc = 0; dc < dir.size(); dc++) {
move = new Point(start.x() + dir.get(dc).x(), start.y() + dir.get(dc).y());
if (!move.isValid(matrix[0].length, matrix.length)) {
continue;
}
if (matrix[move.y()][move.x()].getFill() != Color.MAGENTA) {
start = move;
tmpPath.add(move);
path.add(tmpPath.poll());
System.out.println(path.peek());
if (path.getLast().equals(destPoint)) {
path.poll();
return path;
}
break;
}
}
}
return null;
}
Explanation: my method adds all walked path in a queue which if path is found(or when starfish will arrive at destination) will be returned! Color.MAGENTA is considered as wall, if i click on rectangle on my GUI, rectangles color will be assigned to MAGENTA.
I am stuck at solving the bug! Project Repository: https://github.com/gchapidze/maze-solver
This is a bit of a traditional pathfinding approach. You need to keep track of all of your possible paths.
You start at point A, aka path 0. You start by "opening" the path. You go through all of the valid moves for each move you add a new path.
Now you grab the next viable path, then you "open" that path by removing it from the list, and adding a new path for each possible move.
The type of pathfinding algorithm you use determines how you find the next viable path.
In your case, your paths are just a Deque of Points, so you can keep track of your paths with a.
I would select the next path using the length. That way you'll perform a depth first search, which is basically what you're doing.
Point start = new Point(0, 0);
//var tmpPath = new ArrayDeque<Point>(); obsolete
var path = new ArrayDeque<Point>();
//tmpPath.add(new Point(0, 0)); obsolete
Deque<Deque<Point>> availablePaths = new ArrayDeque<>();
//initialize space
path.add(start);
availablePaths.add(path);
while (!availablePaths.isEmpty()) {
//removes the last element, which will be a depth first search.
path = availablePaths.removeLast();
//check for success.
if (path.getLast().equals(destPoint)) {
//path.poll();
return path;
}
//open the current path.
start = path.getLast();
for (int dc = 0; dc < dir.size(); dc++) {
move = new Point(start.x() + dir.get(dc).x(), start.y() + dir.get(dc).y());
if (!move.isValid(matrix[0].length, matrix.length)) {
continue;
}
if(path.contains(move){
continue; //this prevents the path from walking on itself.
}
if (matrix[move.y()][move.x()].getFill() != Color.MAGENTA) {
//start = move; obsolete.
// tmpPath.add(move); obsolete
var newPath = new ArrayDeque(path);
newPath.add(move);
//moved the check for complete to the start of the loop!
availablePaths.add(newPath);
//break; don't break when you find a possible path.
//get all possible paths, and explore in the next loop.
}
}
}
I've updated this to have an example using your code. I've commented out the code of yours I would remove or change and added the other code.
The main difference is there are a lot of paths that it keeps track of. This prevents the paths from overlapping. Also if a path becomes a dead end, it will not ruin the algorithm. If there is a path, this should find it.
I have a graph with nodes to color, where for each node a dataset (a collection of rows / tuples) is associated.
The algorithm is explained by this example:
the uploaded figure shows an execution of Coloring over graph G with
nodes {v1, v3, v2}. Figure (a) initializes nodes as
uncolored. We first consider v1, and select Sσ1 = {{t9, t10}} (Figure (b)). We color nodes v2 and v3 by recursively calling Coloring.
Coloring one node may restrict the color choice of neighboring nodes,
e.g. after we select {{t9, t10}} for v1, we cannot select {{t6, t7,
t10}} for v3 due to the overlapping tuple t10. For node v3,
we have several choices including {{t6, t7}} and {{t7, t8}}. In Figure (c), we assume the coloring algorithm chooses {{t6, t7}} for
v3. As a result, {{t5, t6}}, which was the only choice forv2, cannot
be used due to the overlapping tuple t6. This leads the algorithm
towards an unsatisfying clustering (Figure (d)). The algorithm
backtracks its last decision for v3 by selecting a different color,
{{t7, t8}} for v3 in Figure (e). In this case, the clustering {{t5,
t6}} for v2 does not overlap with {{t7, t8}}. Since we have found a
clustering that satisfies all the constraints (i.e., a coloring of all nodes), Coloring returns true with V containing the nodes and their colors
(i.e., clusterings).
Here's my code i am trying (which i suspect it is wrong the way it colors the nodes because the algorithm runs for too long )
nodeIterator parameter contains all nodes of the graph sorted in customized way.
public Boolean coloring(graph, nodeIterator, vector){
Node nodeIt ;
if (nodeIterator.hasNext())
nodeIt = nodeIterator.next();
else {
return false;
}
// cluster is the current node associated dataset
ArrayList<Dataset<Row>> cluster = allClustersOfGraph.getNextDataset(nodeIt.name);
if (graph.getNeighbors(nodeIt) == null) {
if (!nodeIterator.hasNext()){
colorNode(vector, nodeIt);
return false;
}
else {
colorNode(vector, nodeIt);
nodeIterator.next();
}
}
Iterable<Node> adjNodes = graph.getNeighbors(nodeIt);
Iterator<Node> adjNodesIt = adjNodes.iterator();
// i suspect in the line under, while is an if so that next neighboring nodes of the current processed one, will be in turn processed in the next recursive call of this algorithm
while (adjNodesIt.hasNext()){
Node adjNode = adjNodesIt.next();
if (!checkNodeColored(vector, adjNode)) {
ArrayList<Dataset<Row>> adjCluster = allClustersOfGraph.getNextDataset(adjNode.name);
for (Dataset<Row> subCluster : cluster) {
for (Dataset<Row> subAdjCluster : adjCluster) {
// small datasets (tuples of rows) don't intersect
if (noDatasetIntersection(subCluster, subAdjCluster)) {
colorNode(vector, nodeIt, subCluster);
if (coloring(graph, nodeIterator, vector)) {
return true;
} else {
// vector is where current coloring progress is maintained
// move backwards
vector.remove(vector.size() - 1);
}
}
}
}
} else if (!adjNodesIt.hasNext()) {
// Color last node anyway
colorNode(vector, nodeIt);
return true;
}
}
return false;
}
allClustersOfGraph is of type ArrayList<ArrayList<Dataset<Row>>>
Here's also the pseudo-algorithm :
My question is : i created the loop while (adjNodesIt.hasNext()){...in my code to check for one recursive call all neighboring nodes of the current processed node, is it right to do that in a recursive method ? Also are all limit cases treated through my implementation ?
Thanks for the great help!
I have to develop a Dijkstra Alogirthm in Java and I have a question to Dijkstra in a circle.
So for a Tree or a normal graph without a loop it works.
So I have a Status White means not found, gray = found but not dealt with and black means done.
So when I have a loop I tryed a if (next.status == Node.Black) but then he didn't found all nodes.
So the question is, how can I add a loop detection and found all nodes?
Thanks for help and tips
best regards
witar7
PS: the if (next.equals(startNode) was only an idea to stop the loop.
public void populateDijkstraFrom(Node startNode) {
this.resetState();
PriorityQueue<Node> distanceQueue = new PriorityQueue<Node>();
for (int x = 0; x < nodes.size(); x++) { // for each node
nodes.get(x).distance = Double.POSITIVE_INFINITY; // set distance to inf
nodes.get(x).predecessor = null; // delete existing predecessors
}
startNode.distance = 0.0; // set distance from startNode to zero
startNode.status = Node.GRAY; // mark startNode as active
Node current = startNode;
distanceQueue.add(current); // add startNode to prio queue
while (!distanceQueue.isEmpty()) { // while contains elements
current = distanceQueue.poll(); // set current to head of queue
current.status = Node.BLACK; // mark head as settled
for (Node next : current.getAdjacentNodes() ) { // get all adjacent nodes
if (next.equals(startNode)) {
break;
}
next.status = Node.GRAY;
// stopExecutionUntilSignal();// mark status as found
distanceQueue.add(next);
if (distanceQueue.contains(next)) {
if (next.distance > current.distance + current.getWeight(next)) { // if the found distance is smaller then the existing one
next.predecessor = current; // change distance in node
next.distance = current.distance + current.getWeight(next); // set predecessor
}
}
}
}
this.clearMarks();
}
PS: the if (next.equals(startNode) was only an idea to stop the loop.
There's no need to do this, your while condition will terminate anyway when it can't find anymore unvisited adjacent nodes. You just have to check whether current visited node status is BLACK and if yes, don't add it to the queue (it's already been visited before).
P.S.: I don' think you need GRAY status, just BLACK or WHITE. Deal with the node right away, no need to delay.
Suppose i have an image like this (the numbers are for explaining, so focus on the white):
I'm working on a method to create a hiearchy of the contours instead of a flat list. In the case of the image above:
-n1 holds 1 contour: n2
-n2 hold 3 contours: n3, n4, n5
-n5 holds 1 contour: n6
-n6 holds 1 contour: n7
Make sure you understand the above before continue reading.
I have the method addContainingBlob, this method is in the blob class. I already checked in another method if the blobToAdd is within the bounds of the blob where i add it. I get a StackOverflowError at this line: b.addContainingBlob(blobToAdd); // <<<<<<.
I'm breaking my head around this for the last hour. Can someone see why it goes wrong?
protected void addContainingBlob(Blob blobToAdd) {
if (containingBlobs.size() == 0) {
containingBlobs.add(blobToAdd);
return;
}
Rectangle r1 = new Rectangle();
r1.setBounds(blobToAdd.minX(), blobToAdd.minY(), blobToAdd.width(), blobToAdd.height());
Rectangle r2 = new Rectangle();
// first check if we already have a containing blob that
// can hold the one we like to add
for (Blob b : containingBlobs) {
r2.setBounds(b.minX(), b.minY(), b.width(), b.height());
if (r2.contains(r1)) {
b.addContainingBlob(blobToAdd); // <<<<<<
return;
}
}
// it can also be that one OR MORE of the containing blobs can fit in the blob we like to add
for (int i = containingBlobs.size()-1; i >= 0; i--) {
Blob b = containingBlobs.get(i);
r2.setBounds(b.minX(), b.minY(), b.width(), b.height());
if (r1.contains(r2)) {
containingBlobs.remove(i);
blobToAdd.addContainingBlob(b);
}
}
containingBlobs.add(blobToAdd);
}
If the code allows a blob to contains itself, the call to blobToAdd.addContainingBlob(b) will lead to infinite recursion because of
if (r2.contains(r1)) {
b.addContainingBlob(blobToAdd); // <<<<<<
return;
}
So I the app lets a user place down blocks on a grid, if the user lines up 3 or more blocks with the same suit, or color, then something happens. When player places a block I call this method:
blocks_.add(new Block(new Vector2(rect_mouse.x, rect_mouse.y), blocks_.get(0).blockID, blockCount));
When you place 3 or more together I call these methods:
blocks_.removeValue(blocks_.get(left_bravo_indexNum), true);
blocks_.removeValue(blocks_.get(center_charlie_indexNum), true);
blocks_.removeValue(blocks_.get(right_alpha_indexNum), true);
stack:
Exception in thread "LWJGL Application" java.lang.IndexOutOfBoundsException: 13
at com.badlogic.gdx.utils.Array.get(Array.java:125)
at com.jrp.mygearapp.GameScreen.touchUp(GameScreen.java:1443)
at com.badlogic.gdx.backends.lwjgl.LwjglInput.processEvents(LwjglInput.java:297)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:186)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:110)
This was intended to remove the blocks, but it resulted in this IndexOutOfBoundsException. Is there a way to prevent this error?
This could be occurring because the array auto sorts the number of elements and lowers the number to the correct number of elements in the array, and I still have elements that are labeled higher then the size of the array. I am still a novice, so my analysis could be incorrect. Please alert me if this is the case and help me find a fix.
Thanks.
edirted* TouchUp() function-------
#Override
public boolean touchUp(int x, int y, int pointer, int button) {
if (button == 0) {
display_blockCheck = false;
////set blockCount to the size of blockArray so blocks can properly be indexed
blockCount = blocks_.size;
if (!overlap) {
Gdx.app.log("Block Added", "x: " + x + " y: " + y);
updateQueueBlocks();
//add block
Vector2 rect_vector = new Vector2(rect_mouse.x, rect_mouse.y);
Block block = new Block(rect_vector,blocks_.get(0).blockID, blocks_.size);
blocks_.add(block);
if (center_charlie_suit == "Square") {
center_charlie_bool = true;
if (right_bravo_suit == "Square") {
right_bravo_bool = true;
if (right_alpha_suit == "Square") {
Gdx.app.log("3-pair", "Square:345:lr");
right_alpha_bool = true;
//call 3-pair event
blocks_.removeValue(blocks_.get(center_charlie_indexNum), true);
blocks_.removeValue(blocks_.get(right_alpha_indexNum), true);
blocks_.removeValue(blocks_.get(right_bravo_indexNum), true);
}
}
}
the rest is just really long and just checks for other blocks next to each other..
You're right, as you remove the blocks, the indexes change.
You don't show what type of Collection blocks_ is (Vector2?, did you write it?), however, rather than tracking the indices of the elements, simply track the elements themselves and call remove() to find and remove that element.