I'm coding a minesweeper game, and when the user clicks an empty cell, all the reachable empty cells must be opened as well.
I'm using a queue to do so, but it seems like I'm having a trouble with an infinite loop.
The part of the code with the problem:
queue<int> q;
q.push(row);
q.push(col);
while(!q.empty()){
int tempRow = q.front();
int tempCol = q.front();
if((tempRow-1)>=0 && (tempRow-1)<s && (tempCol-1)>=0 && (tempCol-1)<s && table[tempRow-1][tempCol-1]==' '){q.push(tempRow-1);q.push(tempCol-1);}
if((tempRow-1)>=0 && (tempRow-1)<s && (tempCol)>=0 && (tempCol)<s && table[tempRow-1][tempCol]==' '){q.push(tempRow-1);q.push(tempCol);}
if((tempRow-1)>=0 && (tempRow-1)<s && (tempCol+1)>=0 && (tempCol+1)<s && table[tempRow-1][tempCol+1]==' '){q.push(tempRow-1);q.push(tempCol+1);}
if((tempRow)>=0 && (tempRow)<s && (tempCol-1)>=0 && (tempCol-1)<s && table[tempRow][tempCol-1]==' '){q.push(tempRow);q.push(tempCol-1);}
if((tempRow)>=0 && (tempRow)<s && (tempCol+1)>=0 && (tempCol+1)<s && table[tempRow][tempCol+1]==' '){q.push(tempRow);q.push(tempCol+1);}
if((tempRow+1)>=0 && (tempRow+1)<s && (tempCol-1)>=0 && (tempCol-1)<s && table[tempRow+1][tempCol-1]==' '){q.push(tempRow+1);q.push(tempCol-1);}
if((tempRow+1)>=0 && (tempRow+1)<s && (tempCol)>=0 && (tempCol)<s && table[tempRow+1][tempCol]==' '){q.push(tempRow+1);q.push(tempCol);}
if((tempRow+1)>=0 && (tempRow+1)<s && (tempCol+1)>=0 && (tempCol+1)<s && table[tempRow+1][tempCol+1]==' '){q.push(tempRow+1);q.push(tempCol+1);}
view[tempRow][tempCol]=' ';
q.pop();
q.pop();
}
Why do I get an infinite loop?
This kind of problem appears in multiple situations. It's actually calculating the 'closure' of a set of instances. Often also found when handling graphs, ...
It's typically solved in the following way:
queue
that will store all the elements that need to be processed.set
) with a key that identifies the items to process and make sure look up is fast (in your case, the key could be the coordinates of the cell)queue
andset
queue
element.process()
)set
, ignore itset
, add it to theset
and push it on thequeue
The principle is that you push neighbors on the
queue
if they are not yet in thequeue
or have not yet been processed (that's why we need theset
, to do the efficient look up).Depending on your exact problem, you could optimize some things, e.g. instead of using a
set
, use a 2-dimensional matrix, orbitset
. This will probably take more memory (depending on your grid size), and might give performance problems if you need to reset the matrix often, but will give anO(1)
lookup instead ofO(log N)
look up for theset
(even anstd::unordered_set
is slower than a simple indexing lookup in a matrix).