Find a close path or area with a recursive method
I have an object in a 2d array and I want to go through them from top, left, right for that object. I want to check if there is some kind of loop or is it better to make some kind of closed area. See this image for a better explanation.
Acutally I have an X x Y slot and when the user touches any area it adds a brick there, so I want the user to add a brick check every time if he makes a close path.
I have a recursive write function for this, but it doesn't work fine, it always only goes to the top and not to the right and left. Here is the code
function checkTrap(y,x)
if all_tiles[y][x].state == "changed" then --if brick is added at that location
last_move_y = y
last_move_x = x
--check for top
y = y - 1
if( y >= 1 and y <= 6 and (last_move_y ~= y or last_move_x ~= x) ) then
print("Moved to top at"..y..", "..x)
return checkTrap(y, x)
end
--check for bottom
y = y + 1
if( y >= 1 and y <= 6 and (last_move_y ~= y or last_move_x ~= x) ) then
print("Moved to bottom at"..y..", "..x)
return checkTrap(y, x)
end
--check for left
x = x - 1
if( x >= 1 and x <= 6 and (last_move_y ~= y or last_move_x ~= x) ) then
print("Moved to left at"..y..", "..x)
return checkTrap(y, x)
end
--check for right
x = x + 1
if( x >= 1 and x <= 6 and (last_move_y ~= y or last_move_x ~= x) ) then
print("Moved to right at"..y..", "..x)
return checkTrap(y, x)
end
elseif all_tiles[y][x] == object then
print("it a loop"..y..", "..x)
return true;
else
print("not changed")
return false
end
end
Edit: new solution
function findClosedRegion()
local currFlag, isClose = -1, false
local isVisited = {
{-1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1}}
local k, m = 1, 1
while k <= 6 and not isClose
do
print("K "..k)
while m <= 6 and not isClose
do
print("M "..m)
if not isBrick[k][m] and isVisited[k][m] == -1 then
local cellsi = Stack:Create()
local cellsj = Stack:Create()
cellsi:push(k)
print("Pushed k "..k)
cellsj:push(m)
print("Pushed m "..m)
currFlag = currFlag + 1
isClose = true
while cellsi:getn() > 0 and isClose do
local p = cellsi:pop()
print("Pop p "..p)
local q = cellsj:pop()
print("Pop q "..q)
if( p >= 1 and p <= 6 and q >= 1 and q <= 6 ) then
if(not isBrick[p][q]) then
print("white ")
if(isVisited[p][q] == -1) then
print("invisited")
isVisited[p][q] = currFlag
cellsi.push(p - 1)
cellsj.push(q)
cellsi.push(p + 1)
cellsj.push(q)
cellsi.push(p)
cellsj.push(q + 1)
cellsi.push(p)
cellsj.push(q - 1)
cellsi:list()
else
if(isVisited[p][q] < currFlag) then
print("visited < currFlag")
isClose = false
end
end
end
else
isClose = false
end --p and q if ends here
end -- tile while end
else
--print("changed and not -1")
end
m = m + 1
end -- m while end
if(isClose) then
print("Closed path")
end
m = 1
k = k + 1
end -- k while end
end
source to share
The implementation structure is ignored in other directions, as only the first branch is named; anyway, all neighbors should be included. Obviously you are trying to implement your Deph-first search array on your array. The approach seems absolutely right, but all the neighbors of the cell must be taken into account. Most likely, this will help to do the analysis of the connected components and fill in all the connected components that touch the boundary.
source to share
EDITED :
Instead, if we search with black cells, we should be looking for white cells, because your goal is to find an area linked by black cells, even if it's diagonally. We need to find a group of white cells that are limited only by black cells, and not by the border of the entire main grid. This should satisfy your purpose.
JS Fiddle: http://jsfiddle.net/4d4wqer2/
This is the reworked algorithm I came across:
for each cell and until closed area not found
if white and visitedValue = -1
push cell to stack
while stack has values and closed area not found
pop cell from stack
if invalid cell // Cell coordinates are invalid
this area is not closed, so break from the while
else
if white
if visitedValue = -1
{
mark visited
push neighboring four cells to the stack
}
else
if visitedValue > currVisitNumber // The current cells are part of previous searched cell group, which was not a closed group.
this area is not closed, so break from the while
if closed area found
show message
Coded with JQuery:
function findArea() {
var currFlag = -1, isvisited = [], isClosed = false;
for (var k = 0; k < rows; k++) { // Initialize the isvisited array
isvisited[k] = [];
for (var m = 0; m < cols; m++)
isvisited[k][m] = -1;
}
for (var k = 0; k < rows && !isClosed; k++)
for (var m = 0; m < cols && !isClosed; m++) {
if (!isblack[k][m] && isvisited[k][m] == -1) { // Unvisited white cell
var cellsi = [k], cellsj = [m];
currFlag++;
isClosed = true;
while (cellsi.length > 0 && isClosed) { // Stack has cells and no closed area is found
var p = cellsi.pop(), q = cellsj.pop();
if (p >= 0 && p < rows && q >= 0 && q < cols) { // The cell coord.s are valid
if (!isblack[p][q])
if (isvisited[p][q] == -1) {
isvisited[p][q] = currFlag; // Mark visited
cellsi.push(p - 1); // Push the coord.s of the four adjacent cells
cellsj.push(q);
cellsi.push(p + 1);
cellsj.push(q);
cellsi.push(p);
cellsj.push(q + 1);
cellsi.push(p);
cellsj.push(q - 1);
}
else
if (isvisited[p][q] < currFlag) // The current group of white cells was part of a previous group of white cells which were found to be unbound by the black cells. So, skip this group.
isClosed = false;
}
else
isClosed = false; // The current cell is out of border. Hence skip the whole group.
}
}
}
if (isClosed)
alert('Closed area found');
}
JS Fiddle: http://jsfiddle.net/4d4wqer2/
source to share