2

I have a grid of connected paths as shown below: enter image description here

The grid is a 2D array created as follows:

for(var x = 0; x < 10; x++){
        hz[x] = new Array(10);

        for(var y = 0; y < 10; y++){
            hz[x][y] = new block(0, 0, 0, 0, 0);
        }
    }

Each element of the array contains an object of type block as follows:

function block(top, bottom, left, right, visited){
    this.top = top;
    this.bottom = bottom;
    this.left = left;
    this.right = right;
    this.visited = visited;
}

I have implemented a breadth-first-search on my grid in order to define the connected components. I need it to be completely connected. This is my code for the BFS:

function search(){
    var count = 0;
    var graph = hz;

    for(var x=0; x < 9; x++){
        for(var y=0; y < 9; y++){
            if(!graph[x][y].visited){ //if block not yet visited
                count++;
                q = new Queue();
                q.enqueue(graph[x][y]);
                graph[x][y].visited = 1;

                while(q.size() > 0){
                    var w = q.dequeue();
                    var ends = numberOfEnds(w);
                    var a = w.x;
                    var b = w.y;

                    for(var t=0; t < ends; t++){
                        if(w.left){
                            if(graph[a][b-1].right){
                                if(!graph[a][b-1].visited){
                                    graph[a][b].left = 0;
                                    graph[a][b-1].visited = 1;
                                    q.enqueue(graph[a][b-1]);
                                }
                            }
                        }
                        else if(w.right){
                            if(graph[a][b+1].left){
                                if(!graph[a][b+1].visited){
                                    graph[a][b].right = 0;
                                    graph[a][b+1].visited = 1;
                                    q.enqueue(graph[a][b+1]);
                                }
                            }
                        }
                        else if (w.top){
                            if(graph[a-1][b].bottom){
                                if(!graph[a-1][b].visited){
                                    graph[a][b].top = 0;
                                    graph[a-1][b].visited = 1;
                                    q.enqueue(graph[a-1][b]);
                                }
                            }
                        }
                        else if (w.bottom){
                            if(graph[a+1][b].top){
                                if(!graph[a+1][b].visited){
                                    graph[a][b].bottom = 0;
                                    graph[a+1][b].visited = 1;
                                    q.enqueue(graph[a+1][b]);
                                }
                            }
                        }
                    } //end for every neighbour of block
                } //end while

            } //end if visited
        } //end for y
    } //end for x

    console.log("Count: " + count);
}

The problem is that when I run the algorithm, the result of count is very high, like in the 50s when it should be 1 or 2 at the most.

What am I doing wrong?

ALR
  • 401
  • 2
  • 7
  • 18
  • 1
    From the code `count` is a simple integral counter, but you say it reaches a value of 50 seconds. This is inconsistent: what are you really measuring and what is the basis for it being only "1 or 2"? – Richard Jun 06 '16 at 09:56
  • you're using the `x,y` of the starting node all the way, instead you should use the `x,y` of the dequeued nodes – BeyelerStudios Jun 06 '16 at 09:59
  • 1
    @Richard *in the fifties* - there are no seconds – BeyelerStudios Jun 06 '16 at 10:00
  • @BeyelerStudios , how do I change the `x,y` values? Should I update them at the end of the `for(t)` loop? – ALR Jun 06 '16 at 10:06
  • You don't change those `x,y` otherwise you'll destroy your outer loops, instead you have to either store the position in each node or store a new object in the queue like: `q.enqueue({node:graph[x][y], x:x, y:y})` and use `w.node, w.x, w.y` in your search. – BeyelerStudios Jun 06 '16 at 10:08
  • Okay, got it. Last question: do I update all the `x,y` values inside the `while()` loop and leave those outside it the same? – ALR Jun 06 '16 at 10:11
  • I'd say yes, but I don't really understand your idea with the `for(t)` loop, maybe you could elaborate or rethink that first: what is `t` really used for in the loop body? Why not remove all the `else` instead? – BeyelerStudios Jun 06 '16 at 10:14
  • Looking at the pseudocode of the breadth-first-search, it says that for every element that is dequeued, you need to look at all of its adjacent elements. So the `for(t)` loop runs for the number of connections that the current block has and enqueues each of those blocks in turn. I just need to do a bunch of extra checks because if a block has `left=1` then the block to the left of it must also have `right=1` for them to be considered connected. – ALR Jun 06 '16 at 10:18
  • Yes, you have up to 4 connections, you already check them with individual if statements, what is the `for` loop for exactly? Just get rid of it. (This is maybe a simple misuse of `else if` in your case.) – BeyelerStudios Jun 06 '16 at 10:21
  • Great, you're right. It was unnecessary. Took it away and changed the `else if`s to `if`s. Thanks, it works now – ALR Jun 06 '16 at 10:26

2 Answers2

0

After looking at your code, mistake I found is when you are checking neighbours of current block you are going only in one direction till you are having a neighbour in that direction, By doing so you missed putting some of the neighbours in the queue and when you reach them by your outermost loop they are considered as new connected component,and your counter is incremented again for the same component.

My solution to this mistake is just change "else if" to "if" i.e. if any block is connected to current block put it in the queue.

I hope this will help you.

HNMN3
  • 522
  • 3
  • 9
  • Welcome to Stackoverflow. Would you mind adding the code snippets to clarify the solution for fellow programmers. – Nagama Inamdar Jun 06 '16 at 12:43
  • code will be the same as in problem statement except in function **search** you have to replace **else if** by **if**. – HNMN3 Jun 07 '16 at 03:15
-1

Based on the comments given, this is the code for the answer:

function search(){
    var count = 0;
    var graph = hz;

    for(var x=0; x < 9; x++){
        for(var y=0; y < 9; y++){
            if(!graph[x][y].visited){ //if block not yet visited
                count++;
                console.log("Component: " + count);
                q = new Queue();
                q.enqueue(graph[x][y]);
                graph[x][y].visited = 1;

                while(q.size() > 0){
                    var w = q.dequeue();
                    var ends = numberOfEnds(w);
                    var a = w.x;
                    var b = w.y;


                        if(w.left){
                            if(graph[a][b-1].right){
                                if(!graph[a][b-1].visited){
                                    graph[a][b].left = 0;
                                    graph[a][b-1].visited = 1;
                                    q.enqueue(graph[a][b-1]);
                                }
                            }
                        }
                        if(w.right){
                            if(graph[a][b+1].left){
                                if(!graph[a][b+1].visited){
                                    graph[a][b].right = 0;
                                    graph[a][b+1].visited = 1;
                                    q.enqueue(graph[a][b+1]);
                                }
                            }
                        }
                        if (w.top){
                            if(graph[a-1][b].bottom){
                                if(!graph[a-1][b].visited){
                                    graph[a][b].top = 0;
                                    graph[a-1][b].visited = 1;
                                    q.enqueue(graph[a-1][b]);
                                }
                            }
                        }
                        if (w.bottom){
                            if(graph[a+1][b].top){
                                if(!graph[a+1][b].visited){
                                    graph[a][b].bottom = 0;
                                    graph[a+1][b].visited = 1;
                                    q.enqueue(graph[a+1][b]);
                                }
                            }
                        }

                } //end while

            } //end if visited
        } //end for y
    } //end for x

    console.log("Count: " + count);
}
ALR
  • 401
  • 2
  • 7
  • 18