How should I implement a flood fill function to my c++ program?









up vote
1
down vote

favorite












Im currently looking to turn something like this:



.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............


into this:



.............
.............
..XXX.....O..
..XXX.....O..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............


with the user entering ./a.exe input4.txt floodfill 2 10 o



I believe im going to need to implement some recursion into the program to be able to only look at indexes that match that of the user pointer (including positions of up, down, left, and right) instead of reading the entire vector (which i wouldn't mind doing but dont see how i would begin doing so).



here is the code I have so far for the flood fill function:



void floodfilll(vector<vector<char>> &vec, int x, int y, char r, char dum)

int ii;
ii = 0;
int jj;
jj = 0;
for (int i = 0; i < vec.size(); i ++)
for (int j = 0; j < vec[i].size(); j++)
if (vec[i][j] == r)
vec[i][j] == r;
if ((i + ii) > 0)
if (vec[i-1][j] == r)
vec[i-1][j] = dum;
vec[i][j] == r;
ii--;
floodfilll(vec, x + ii, y, r, dum);

if ((j + jj) > 0)
if(vec[i][j-1] != r)
vec[i][j-1] = dum;
vec[i][j] == r;
jj--;
floodfilll(vec, x, y + jj, r, dum);

if ((i + ii)<vec.size())
if (vec[i+1][j] != r)
vec[i+1][j] = dum;
vec[i][j] == r;
ii++;
floodfilll(vec, x + ii, y, r, dum);

if ((j + jj)<vec[i].size())
if (vec[i][j+1] != r)
vec[i][j+1] = dum;
vec[i][j] == r;
jj++;
floodfilll(vec, x, y + jj, r, dum);



replacee(vec, dum, r);




NOTE: Im using a function called replacee to replace Var dum, with Var R. Var dum is assigned 'i' and r is 'X'.



Also, the text file is parsed as a 2d vector of char's (char)**



Its just the way the rest of my program is based. Here is the replace function:



 void replacee(vector<vector<char>> &vec, char oldd, char neww)

for (vector<char> &v : vec) // reference to innver vector

replace(v.begin(), v.end(), oldd, neww); // standard library algorithm




This is the int main file im using:



int main(int argc, char* argv) 

fstream fin; char ch;
string name (argv[1]); //File Name.
vector<vector<char>> data;
// 2D Vector.
vector<char> temp;
// Temporary vector to be pushed
// into vec, since its a vector of vectors.
fin.open(name.c_str(),ios::in);
// Assume name as an arbitary file.
string argument2 (argv[2]);
while(fin)

ch = fin.get();
if(ch!='n')
temp.push_back(ch);

else

data.push_back(temp);
temp.clear();


if (argument2 == "floodfill")
string argument3 (argv[3]);
string argument4 (argv[4]);
string argument5 (argv[5]);
int x = 0;
int y = 0;
stringstream xx(argument3);
stringstream yy(argument4);
xx >> x;
yy >> y;
floodfilll(data, x, y, argument5[0], 'i');
for (int m = 0; m < data.size(); m ++)
for (int n = 0; n < data[m].size(); n++)
cout << data[m][n];

cout << endl;



fin.close();



Sorry if it looks like im just pasting code for grabs, this is incase anyone has a solution outside my mode of thought. The int main and replacee functions work as intended. I just need help coming up with a way to make floodfilll work correctly.



This is the output i get with my code:



$ ./a.exe input4.txt floodfill 2 10 o
.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............









share|improve this question

















  • 1




    Rather than iterate over the entire vector<vector<char>> when floodfilling, why not start at x,y and branch out adjacently until no more matches are found? Also, your 5th argument o is the character to search, not the new desired character.
    – Enfyve
    Nov 11 at 9:27






  • 1




    So let me get this straight, all you want is to floodfill the area of x-s defined by the starting position with o-s?
    – Qubit
    Nov 11 at 9:28










  • @Qubit yes thats what im trying to do
    – xannax159
    Nov 11 at 9:31










  • 'The int main [...] functions work as intended.' - only if user provides appropriate number of command line arguments, otherwise undefined behaviour (crash likely). Get used right from the start to check if they are available. Additionally, check the fail bits of your string streams for the case if user did not provide numbers. You could as well check if there are further characters left (to catch input like 7s as invalid).
    – Aconcagua
    Nov 11 at 9:47














up vote
1
down vote

favorite












Im currently looking to turn something like this:



.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............


into this:



.............
.............
..XXX.....O..
..XXX.....O..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............


with the user entering ./a.exe input4.txt floodfill 2 10 o



I believe im going to need to implement some recursion into the program to be able to only look at indexes that match that of the user pointer (including positions of up, down, left, and right) instead of reading the entire vector (which i wouldn't mind doing but dont see how i would begin doing so).



here is the code I have so far for the flood fill function:



void floodfilll(vector<vector<char>> &vec, int x, int y, char r, char dum)

int ii;
ii = 0;
int jj;
jj = 0;
for (int i = 0; i < vec.size(); i ++)
for (int j = 0; j < vec[i].size(); j++)
if (vec[i][j] == r)
vec[i][j] == r;
if ((i + ii) > 0)
if (vec[i-1][j] == r)
vec[i-1][j] = dum;
vec[i][j] == r;
ii--;
floodfilll(vec, x + ii, y, r, dum);

if ((j + jj) > 0)
if(vec[i][j-1] != r)
vec[i][j-1] = dum;
vec[i][j] == r;
jj--;
floodfilll(vec, x, y + jj, r, dum);

if ((i + ii)<vec.size())
if (vec[i+1][j] != r)
vec[i+1][j] = dum;
vec[i][j] == r;
ii++;
floodfilll(vec, x + ii, y, r, dum);

if ((j + jj)<vec[i].size())
if (vec[i][j+1] != r)
vec[i][j+1] = dum;
vec[i][j] == r;
jj++;
floodfilll(vec, x, y + jj, r, dum);



replacee(vec, dum, r);




NOTE: Im using a function called replacee to replace Var dum, with Var R. Var dum is assigned 'i' and r is 'X'.



Also, the text file is parsed as a 2d vector of char's (char)**



Its just the way the rest of my program is based. Here is the replace function:



 void replacee(vector<vector<char>> &vec, char oldd, char neww)

for (vector<char> &v : vec) // reference to innver vector

replace(v.begin(), v.end(), oldd, neww); // standard library algorithm




This is the int main file im using:



int main(int argc, char* argv) 

fstream fin; char ch;
string name (argv[1]); //File Name.
vector<vector<char>> data;
// 2D Vector.
vector<char> temp;
// Temporary vector to be pushed
// into vec, since its a vector of vectors.
fin.open(name.c_str(),ios::in);
// Assume name as an arbitary file.
string argument2 (argv[2]);
while(fin)

ch = fin.get();
if(ch!='n')
temp.push_back(ch);

else

data.push_back(temp);
temp.clear();


if (argument2 == "floodfill")
string argument3 (argv[3]);
string argument4 (argv[4]);
string argument5 (argv[5]);
int x = 0;
int y = 0;
stringstream xx(argument3);
stringstream yy(argument4);
xx >> x;
yy >> y;
floodfilll(data, x, y, argument5[0], 'i');
for (int m = 0; m < data.size(); m ++)
for (int n = 0; n < data[m].size(); n++)
cout << data[m][n];

cout << endl;



fin.close();



Sorry if it looks like im just pasting code for grabs, this is incase anyone has a solution outside my mode of thought. The int main and replacee functions work as intended. I just need help coming up with a way to make floodfilll work correctly.



This is the output i get with my code:



$ ./a.exe input4.txt floodfill 2 10 o
.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............









share|improve this question

















  • 1




    Rather than iterate over the entire vector<vector<char>> when floodfilling, why not start at x,y and branch out adjacently until no more matches are found? Also, your 5th argument o is the character to search, not the new desired character.
    – Enfyve
    Nov 11 at 9:27






  • 1




    So let me get this straight, all you want is to floodfill the area of x-s defined by the starting position with o-s?
    – Qubit
    Nov 11 at 9:28










  • @Qubit yes thats what im trying to do
    – xannax159
    Nov 11 at 9:31










  • 'The int main [...] functions work as intended.' - only if user provides appropriate number of command line arguments, otherwise undefined behaviour (crash likely). Get used right from the start to check if they are available. Additionally, check the fail bits of your string streams for the case if user did not provide numbers. You could as well check if there are further characters left (to catch input like 7s as invalid).
    – Aconcagua
    Nov 11 at 9:47












up vote
1
down vote

favorite









up vote
1
down vote

favorite











Im currently looking to turn something like this:



.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............


into this:



.............
.............
..XXX.....O..
..XXX.....O..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............


with the user entering ./a.exe input4.txt floodfill 2 10 o



I believe im going to need to implement some recursion into the program to be able to only look at indexes that match that of the user pointer (including positions of up, down, left, and right) instead of reading the entire vector (which i wouldn't mind doing but dont see how i would begin doing so).



here is the code I have so far for the flood fill function:



void floodfilll(vector<vector<char>> &vec, int x, int y, char r, char dum)

int ii;
ii = 0;
int jj;
jj = 0;
for (int i = 0; i < vec.size(); i ++)
for (int j = 0; j < vec[i].size(); j++)
if (vec[i][j] == r)
vec[i][j] == r;
if ((i + ii) > 0)
if (vec[i-1][j] == r)
vec[i-1][j] = dum;
vec[i][j] == r;
ii--;
floodfilll(vec, x + ii, y, r, dum);

if ((j + jj) > 0)
if(vec[i][j-1] != r)
vec[i][j-1] = dum;
vec[i][j] == r;
jj--;
floodfilll(vec, x, y + jj, r, dum);

if ((i + ii)<vec.size())
if (vec[i+1][j] != r)
vec[i+1][j] = dum;
vec[i][j] == r;
ii++;
floodfilll(vec, x + ii, y, r, dum);

if ((j + jj)<vec[i].size())
if (vec[i][j+1] != r)
vec[i][j+1] = dum;
vec[i][j] == r;
jj++;
floodfilll(vec, x, y + jj, r, dum);



replacee(vec, dum, r);




NOTE: Im using a function called replacee to replace Var dum, with Var R. Var dum is assigned 'i' and r is 'X'.



Also, the text file is parsed as a 2d vector of char's (char)**



Its just the way the rest of my program is based. Here is the replace function:



 void replacee(vector<vector<char>> &vec, char oldd, char neww)

for (vector<char> &v : vec) // reference to innver vector

replace(v.begin(), v.end(), oldd, neww); // standard library algorithm




This is the int main file im using:



int main(int argc, char* argv) 

fstream fin; char ch;
string name (argv[1]); //File Name.
vector<vector<char>> data;
// 2D Vector.
vector<char> temp;
// Temporary vector to be pushed
// into vec, since its a vector of vectors.
fin.open(name.c_str(),ios::in);
// Assume name as an arbitary file.
string argument2 (argv[2]);
while(fin)

ch = fin.get();
if(ch!='n')
temp.push_back(ch);

else

data.push_back(temp);
temp.clear();


if (argument2 == "floodfill")
string argument3 (argv[3]);
string argument4 (argv[4]);
string argument5 (argv[5]);
int x = 0;
int y = 0;
stringstream xx(argument3);
stringstream yy(argument4);
xx >> x;
yy >> y;
floodfilll(data, x, y, argument5[0], 'i');
for (int m = 0; m < data.size(); m ++)
for (int n = 0; n < data[m].size(); n++)
cout << data[m][n];

cout << endl;



fin.close();



Sorry if it looks like im just pasting code for grabs, this is incase anyone has a solution outside my mode of thought. The int main and replacee functions work as intended. I just need help coming up with a way to make floodfilll work correctly.



This is the output i get with my code:



$ ./a.exe input4.txt floodfill 2 10 o
.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............









share|improve this question













Im currently looking to turn something like this:



.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............


into this:



.............
.............
..XXX.....O..
..XXX.....O..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............


with the user entering ./a.exe input4.txt floodfill 2 10 o



I believe im going to need to implement some recursion into the program to be able to only look at indexes that match that of the user pointer (including positions of up, down, left, and right) instead of reading the entire vector (which i wouldn't mind doing but dont see how i would begin doing so).



here is the code I have so far for the flood fill function:



void floodfilll(vector<vector<char>> &vec, int x, int y, char r, char dum)

int ii;
ii = 0;
int jj;
jj = 0;
for (int i = 0; i < vec.size(); i ++)
for (int j = 0; j < vec[i].size(); j++)
if (vec[i][j] == r)
vec[i][j] == r;
if ((i + ii) > 0)
if (vec[i-1][j] == r)
vec[i-1][j] = dum;
vec[i][j] == r;
ii--;
floodfilll(vec, x + ii, y, r, dum);

if ((j + jj) > 0)
if(vec[i][j-1] != r)
vec[i][j-1] = dum;
vec[i][j] == r;
jj--;
floodfilll(vec, x, y + jj, r, dum);

if ((i + ii)<vec.size())
if (vec[i+1][j] != r)
vec[i+1][j] = dum;
vec[i][j] == r;
ii++;
floodfilll(vec, x + ii, y, r, dum);

if ((j + jj)<vec[i].size())
if (vec[i][j+1] != r)
vec[i][j+1] = dum;
vec[i][j] == r;
jj++;
floodfilll(vec, x, y + jj, r, dum);



replacee(vec, dum, r);




NOTE: Im using a function called replacee to replace Var dum, with Var R. Var dum is assigned 'i' and r is 'X'.



Also, the text file is parsed as a 2d vector of char's (char)**



Its just the way the rest of my program is based. Here is the replace function:



 void replacee(vector<vector<char>> &vec, char oldd, char neww)

for (vector<char> &v : vec) // reference to innver vector

replace(v.begin(), v.end(), oldd, neww); // standard library algorithm




This is the int main file im using:



int main(int argc, char* argv) 

fstream fin; char ch;
string name (argv[1]); //File Name.
vector<vector<char>> data;
// 2D Vector.
vector<char> temp;
// Temporary vector to be pushed
// into vec, since its a vector of vectors.
fin.open(name.c_str(),ios::in);
// Assume name as an arbitary file.
string argument2 (argv[2]);
while(fin)

ch = fin.get();
if(ch!='n')
temp.push_back(ch);

else

data.push_back(temp);
temp.clear();


if (argument2 == "floodfill")
string argument3 (argv[3]);
string argument4 (argv[4]);
string argument5 (argv[5]);
int x = 0;
int y = 0;
stringstream xx(argument3);
stringstream yy(argument4);
xx >> x;
yy >> y;
floodfilll(data, x, y, argument5[0], 'i');
for (int m = 0; m < data.size(); m ++)
for (int n = 0; n < data[m].size(); n++)
cout << data[m][n];

cout << endl;



fin.close();



Sorry if it looks like im just pasting code for grabs, this is incase anyone has a solution outside my mode of thought. The int main and replacee functions work as intended. I just need help coming up with a way to make floodfilll work correctly.



This is the output i get with my code:



$ ./a.exe input4.txt floodfill 2 10 o
.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............






c++ vector flood-fill






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 11 at 9:04









xannax159

448




448







  • 1




    Rather than iterate over the entire vector<vector<char>> when floodfilling, why not start at x,y and branch out adjacently until no more matches are found? Also, your 5th argument o is the character to search, not the new desired character.
    – Enfyve
    Nov 11 at 9:27






  • 1




    So let me get this straight, all you want is to floodfill the area of x-s defined by the starting position with o-s?
    – Qubit
    Nov 11 at 9:28










  • @Qubit yes thats what im trying to do
    – xannax159
    Nov 11 at 9:31










  • 'The int main [...] functions work as intended.' - only if user provides appropriate number of command line arguments, otherwise undefined behaviour (crash likely). Get used right from the start to check if they are available. Additionally, check the fail bits of your string streams for the case if user did not provide numbers. You could as well check if there are further characters left (to catch input like 7s as invalid).
    – Aconcagua
    Nov 11 at 9:47












  • 1




    Rather than iterate over the entire vector<vector<char>> when floodfilling, why not start at x,y and branch out adjacently until no more matches are found? Also, your 5th argument o is the character to search, not the new desired character.
    – Enfyve
    Nov 11 at 9:27






  • 1




    So let me get this straight, all you want is to floodfill the area of x-s defined by the starting position with o-s?
    – Qubit
    Nov 11 at 9:28










  • @Qubit yes thats what im trying to do
    – xannax159
    Nov 11 at 9:31










  • 'The int main [...] functions work as intended.' - only if user provides appropriate number of command line arguments, otherwise undefined behaviour (crash likely). Get used right from the start to check if they are available. Additionally, check the fail bits of your string streams for the case if user did not provide numbers. You could as well check if there are further characters left (to catch input like 7s as invalid).
    – Aconcagua
    Nov 11 at 9:47







1




1




Rather than iterate over the entire vector<vector<char>> when floodfilling, why not start at x,y and branch out adjacently until no more matches are found? Also, your 5th argument o is the character to search, not the new desired character.
– Enfyve
Nov 11 at 9:27




Rather than iterate over the entire vector<vector<char>> when floodfilling, why not start at x,y and branch out adjacently until no more matches are found? Also, your 5th argument o is the character to search, not the new desired character.
– Enfyve
Nov 11 at 9:27




1




1




So let me get this straight, all you want is to floodfill the area of x-s defined by the starting position with o-s?
– Qubit
Nov 11 at 9:28




So let me get this straight, all you want is to floodfill the area of x-s defined by the starting position with o-s?
– Qubit
Nov 11 at 9:28












@Qubit yes thats what im trying to do
– xannax159
Nov 11 at 9:31




@Qubit yes thats what im trying to do
– xannax159
Nov 11 at 9:31












'The int main [...] functions work as intended.' - only if user provides appropriate number of command line arguments, otherwise undefined behaviour (crash likely). Get used right from the start to check if they are available. Additionally, check the fail bits of your string streams for the case if user did not provide numbers. You could as well check if there are further characters left (to catch input like 7s as invalid).
– Aconcagua
Nov 11 at 9:47




'The int main [...] functions work as intended.' - only if user provides appropriate number of command line arguments, otherwise undefined behaviour (crash likely). Get used right from the start to check if they are available. Additionally, check the fail bits of your string streams for the case if user did not provide numbers. You could as well check if there are further characters left (to catch input like 7s as invalid).
– Aconcagua
Nov 11 at 9:47












2 Answers
2






active

oldest

votes

















up vote
2
down vote



accepted










Why do you iterate over the whole field in each recursion?



Normally, flood filling works as follows:



  1. You have a specific starting point.

  2. You fill this starting point with the colour intended

  3. You check for each of the four (or 8, if you consider diagonals as well) neighbours, if they have the same colour as the starting point originally had; if so, you continue with recursively.

So an implementation might look like this:



void floodfill
(
std::vector<std::vector<char>>& v,
unsigned int x, unsigned int y, char r
)

char p = v[x][y];
v[x][y] = r;
if(x > 0 && v[x - 1][y] == p)
floodfill(v, x - 1, y, r);
if(x + 1 < v.size() && v[x + 1][y] == p)
floodfill(v, x + 1, y, r);
if(y > 0 && v[x][y - 1] == p)
floodfill(v, x, y - 1, r);
if(y + 1 < v[x].size() && v[x][y + 1] == p)
floodfill(v, x, y + 1, r);



Note that I did not check for the case of colour to fill being the same as the one of the starting pixel, neither did I initially check the range check of x and y. For efficiency, I wouldn't add these checks in the recursive function, but in a specific entry function starting the recursion, so they are done only once when needed and not needlessly repeated.






share|improve this answer






















  • Thank you, i wasn't using the ++ statement correctly, neither were my if statements, I guess i got carried off with something too deep to even work.
    – xannax159
    Nov 11 at 9:39

















up vote
1
down vote













One option is to use recursion, as suggested by the other answer. However, personally I prefer avoiding recursion where it is not necessary. An alternative, is a queue-based approach.



void floodfill (std::vector<std::vector<char>>& v, unsigned int x, unsigned int y, char r) y >= v[x].size) return; //Index out of bounds. 
std::queue<std::pair<unsigned int, unsigned int>> q;
q.push(std::make_pair(x, y)); //Push the initial position into the queue.
v[x][y] = r; //Replace the initial point.
while (!q.empty()) //Keep looking at relevant neighbours so long as there is something in the queue.
auto pt = q.top(); //Collect the first entry.
q.pop(); //Remove it, we don't want to keep processing the same point.
//Now add neighbours if they match our initial point.
if(pt.first > 0 && v[pt.first - 1][pt.second] == init)
q.push(std::make_pair(pt.first - 1, pt.second);
v[pt.first - 1][pt.second] = r; //Replace the value here to avoid pushing the same point twice.
if(pt.first + 1 < v.size() && v[pt.first + 1][pt.second] == init)
q.push(std::make_pair(pt.first + 1, pt.second);
v[pt.first + 1][pt.second] = r;
if(pt.second > 0 && v[pt.first][pt.second - 1] == init)
q.push(std::make_pair(pt.first, pt.second - 1);
v[pt.first][pt.second - 1] = r;
if(pt.second + 1 < v[pt.first].size() && v[pt.first][pt.second + 1] == init)
q.push(std::make_pair(pt.first, pt.second + 1);
v[pt.first][pt.second + 1] = r;




This gives you a BFS-like flood-fill pattern without recursion. Alternatively you could also use a stack instead of the queue, then the flood-fill would behave more like a DFS (much more similar to what the recursive pattern will do). It might even perform a little better than the queue, given the data structure is a little simpler.






share|improve this answer






















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53247243%2fhow-should-i-implement-a-flood-fill-function-to-my-c-program%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    2
    down vote



    accepted










    Why do you iterate over the whole field in each recursion?



    Normally, flood filling works as follows:



    1. You have a specific starting point.

    2. You fill this starting point with the colour intended

    3. You check for each of the four (or 8, if you consider diagonals as well) neighbours, if they have the same colour as the starting point originally had; if so, you continue with recursively.

    So an implementation might look like this:



    void floodfill
    (
    std::vector<std::vector<char>>& v,
    unsigned int x, unsigned int y, char r
    )

    char p = v[x][y];
    v[x][y] = r;
    if(x > 0 && v[x - 1][y] == p)
    floodfill(v, x - 1, y, r);
    if(x + 1 < v.size() && v[x + 1][y] == p)
    floodfill(v, x + 1, y, r);
    if(y > 0 && v[x][y - 1] == p)
    floodfill(v, x, y - 1, r);
    if(y + 1 < v[x].size() && v[x][y + 1] == p)
    floodfill(v, x, y + 1, r);



    Note that I did not check for the case of colour to fill being the same as the one of the starting pixel, neither did I initially check the range check of x and y. For efficiency, I wouldn't add these checks in the recursive function, but in a specific entry function starting the recursion, so they are done only once when needed and not needlessly repeated.






    share|improve this answer






















    • Thank you, i wasn't using the ++ statement correctly, neither were my if statements, I guess i got carried off with something too deep to even work.
      – xannax159
      Nov 11 at 9:39














    up vote
    2
    down vote



    accepted










    Why do you iterate over the whole field in each recursion?



    Normally, flood filling works as follows:



    1. You have a specific starting point.

    2. You fill this starting point with the colour intended

    3. You check for each of the four (or 8, if you consider diagonals as well) neighbours, if they have the same colour as the starting point originally had; if so, you continue with recursively.

    So an implementation might look like this:



    void floodfill
    (
    std::vector<std::vector<char>>& v,
    unsigned int x, unsigned int y, char r
    )

    char p = v[x][y];
    v[x][y] = r;
    if(x > 0 && v[x - 1][y] == p)
    floodfill(v, x - 1, y, r);
    if(x + 1 < v.size() && v[x + 1][y] == p)
    floodfill(v, x + 1, y, r);
    if(y > 0 && v[x][y - 1] == p)
    floodfill(v, x, y - 1, r);
    if(y + 1 < v[x].size() && v[x][y + 1] == p)
    floodfill(v, x, y + 1, r);



    Note that I did not check for the case of colour to fill being the same as the one of the starting pixel, neither did I initially check the range check of x and y. For efficiency, I wouldn't add these checks in the recursive function, but in a specific entry function starting the recursion, so they are done only once when needed and not needlessly repeated.






    share|improve this answer






















    • Thank you, i wasn't using the ++ statement correctly, neither were my if statements, I guess i got carried off with something too deep to even work.
      – xannax159
      Nov 11 at 9:39












    up vote
    2
    down vote



    accepted







    up vote
    2
    down vote



    accepted






    Why do you iterate over the whole field in each recursion?



    Normally, flood filling works as follows:



    1. You have a specific starting point.

    2. You fill this starting point with the colour intended

    3. You check for each of the four (or 8, if you consider diagonals as well) neighbours, if they have the same colour as the starting point originally had; if so, you continue with recursively.

    So an implementation might look like this:



    void floodfill
    (
    std::vector<std::vector<char>>& v,
    unsigned int x, unsigned int y, char r
    )

    char p = v[x][y];
    v[x][y] = r;
    if(x > 0 && v[x - 1][y] == p)
    floodfill(v, x - 1, y, r);
    if(x + 1 < v.size() && v[x + 1][y] == p)
    floodfill(v, x + 1, y, r);
    if(y > 0 && v[x][y - 1] == p)
    floodfill(v, x, y - 1, r);
    if(y + 1 < v[x].size() && v[x][y + 1] == p)
    floodfill(v, x, y + 1, r);



    Note that I did not check for the case of colour to fill being the same as the one of the starting pixel, neither did I initially check the range check of x and y. For efficiency, I wouldn't add these checks in the recursive function, but in a specific entry function starting the recursion, so they are done only once when needed and not needlessly repeated.






    share|improve this answer














    Why do you iterate over the whole field in each recursion?



    Normally, flood filling works as follows:



    1. You have a specific starting point.

    2. You fill this starting point with the colour intended

    3. You check for each of the four (or 8, if you consider diagonals as well) neighbours, if they have the same colour as the starting point originally had; if so, you continue with recursively.

    So an implementation might look like this:



    void floodfill
    (
    std::vector<std::vector<char>>& v,
    unsigned int x, unsigned int y, char r
    )

    char p = v[x][y];
    v[x][y] = r;
    if(x > 0 && v[x - 1][y] == p)
    floodfill(v, x - 1, y, r);
    if(x + 1 < v.size() && v[x + 1][y] == p)
    floodfill(v, x + 1, y, r);
    if(y > 0 && v[x][y - 1] == p)
    floodfill(v, x, y - 1, r);
    if(y + 1 < v[x].size() && v[x][y + 1] == p)
    floodfill(v, x, y + 1, r);



    Note that I did not check for the case of colour to fill being the same as the one of the starting pixel, neither did I initially check the range check of x and y. For efficiency, I wouldn't add these checks in the recursive function, but in a specific entry function starting the recursion, so they are done only once when needed and not needlessly repeated.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 11 at 9:41

























    answered Nov 11 at 9:28









    Aconcagua

    11.1k32142




    11.1k32142











    • Thank you, i wasn't using the ++ statement correctly, neither were my if statements, I guess i got carried off with something too deep to even work.
      – xannax159
      Nov 11 at 9:39
















    • Thank you, i wasn't using the ++ statement correctly, neither were my if statements, I guess i got carried off with something too deep to even work.
      – xannax159
      Nov 11 at 9:39















    Thank you, i wasn't using the ++ statement correctly, neither were my if statements, I guess i got carried off with something too deep to even work.
    – xannax159
    Nov 11 at 9:39




    Thank you, i wasn't using the ++ statement correctly, neither were my if statements, I guess i got carried off with something too deep to even work.
    – xannax159
    Nov 11 at 9:39












    up vote
    1
    down vote













    One option is to use recursion, as suggested by the other answer. However, personally I prefer avoiding recursion where it is not necessary. An alternative, is a queue-based approach.



    void floodfill (std::vector<std::vector<char>>& v, unsigned int x, unsigned int y, char r) y >= v[x].size) return; //Index out of bounds. 
    std::queue<std::pair<unsigned int, unsigned int>> q;
    q.push(std::make_pair(x, y)); //Push the initial position into the queue.
    v[x][y] = r; //Replace the initial point.
    while (!q.empty()) //Keep looking at relevant neighbours so long as there is something in the queue.
    auto pt = q.top(); //Collect the first entry.
    q.pop(); //Remove it, we don't want to keep processing the same point.
    //Now add neighbours if they match our initial point.
    if(pt.first > 0 && v[pt.first - 1][pt.second] == init)
    q.push(std::make_pair(pt.first - 1, pt.second);
    v[pt.first - 1][pt.second] = r; //Replace the value here to avoid pushing the same point twice.
    if(pt.first + 1 < v.size() && v[pt.first + 1][pt.second] == init)
    q.push(std::make_pair(pt.first + 1, pt.second);
    v[pt.first + 1][pt.second] = r;
    if(pt.second > 0 && v[pt.first][pt.second - 1] == init)
    q.push(std::make_pair(pt.first, pt.second - 1);
    v[pt.first][pt.second - 1] = r;
    if(pt.second + 1 < v[pt.first].size() && v[pt.first][pt.second + 1] == init)
    q.push(std::make_pair(pt.first, pt.second + 1);
    v[pt.first][pt.second + 1] = r;




    This gives you a BFS-like flood-fill pattern without recursion. Alternatively you could also use a stack instead of the queue, then the flood-fill would behave more like a DFS (much more similar to what the recursive pattern will do). It might even perform a little better than the queue, given the data structure is a little simpler.






    share|improve this answer


























      up vote
      1
      down vote













      One option is to use recursion, as suggested by the other answer. However, personally I prefer avoiding recursion where it is not necessary. An alternative, is a queue-based approach.



      void floodfill (std::vector<std::vector<char>>& v, unsigned int x, unsigned int y, char r) y >= v[x].size) return; //Index out of bounds. 
      std::queue<std::pair<unsigned int, unsigned int>> q;
      q.push(std::make_pair(x, y)); //Push the initial position into the queue.
      v[x][y] = r; //Replace the initial point.
      while (!q.empty()) //Keep looking at relevant neighbours so long as there is something in the queue.
      auto pt = q.top(); //Collect the first entry.
      q.pop(); //Remove it, we don't want to keep processing the same point.
      //Now add neighbours if they match our initial point.
      if(pt.first > 0 && v[pt.first - 1][pt.second] == init)
      q.push(std::make_pair(pt.first - 1, pt.second);
      v[pt.first - 1][pt.second] = r; //Replace the value here to avoid pushing the same point twice.
      if(pt.first + 1 < v.size() && v[pt.first + 1][pt.second] == init)
      q.push(std::make_pair(pt.first + 1, pt.second);
      v[pt.first + 1][pt.second] = r;
      if(pt.second > 0 && v[pt.first][pt.second - 1] == init)
      q.push(std::make_pair(pt.first, pt.second - 1);
      v[pt.first][pt.second - 1] = r;
      if(pt.second + 1 < v[pt.first].size() && v[pt.first][pt.second + 1] == init)
      q.push(std::make_pair(pt.first, pt.second + 1);
      v[pt.first][pt.second + 1] = r;




      This gives you a BFS-like flood-fill pattern without recursion. Alternatively you could also use a stack instead of the queue, then the flood-fill would behave more like a DFS (much more similar to what the recursive pattern will do). It might even perform a little better than the queue, given the data structure is a little simpler.






      share|improve this answer
























        up vote
        1
        down vote










        up vote
        1
        down vote









        One option is to use recursion, as suggested by the other answer. However, personally I prefer avoiding recursion where it is not necessary. An alternative, is a queue-based approach.



        void floodfill (std::vector<std::vector<char>>& v, unsigned int x, unsigned int y, char r) y >= v[x].size) return; //Index out of bounds. 
        std::queue<std::pair<unsigned int, unsigned int>> q;
        q.push(std::make_pair(x, y)); //Push the initial position into the queue.
        v[x][y] = r; //Replace the initial point.
        while (!q.empty()) //Keep looking at relevant neighbours so long as there is something in the queue.
        auto pt = q.top(); //Collect the first entry.
        q.pop(); //Remove it, we don't want to keep processing the same point.
        //Now add neighbours if they match our initial point.
        if(pt.first > 0 && v[pt.first - 1][pt.second] == init)
        q.push(std::make_pair(pt.first - 1, pt.second);
        v[pt.first - 1][pt.second] = r; //Replace the value here to avoid pushing the same point twice.
        if(pt.first + 1 < v.size() && v[pt.first + 1][pt.second] == init)
        q.push(std::make_pair(pt.first + 1, pt.second);
        v[pt.first + 1][pt.second] = r;
        if(pt.second > 0 && v[pt.first][pt.second - 1] == init)
        q.push(std::make_pair(pt.first, pt.second - 1);
        v[pt.first][pt.second - 1] = r;
        if(pt.second + 1 < v[pt.first].size() && v[pt.first][pt.second + 1] == init)
        q.push(std::make_pair(pt.first, pt.second + 1);
        v[pt.first][pt.second + 1] = r;




        This gives you a BFS-like flood-fill pattern without recursion. Alternatively you could also use a stack instead of the queue, then the flood-fill would behave more like a DFS (much more similar to what the recursive pattern will do). It might even perform a little better than the queue, given the data structure is a little simpler.






        share|improve this answer














        One option is to use recursion, as suggested by the other answer. However, personally I prefer avoiding recursion where it is not necessary. An alternative, is a queue-based approach.



        void floodfill (std::vector<std::vector<char>>& v, unsigned int x, unsigned int y, char r) y >= v[x].size) return; //Index out of bounds. 
        std::queue<std::pair<unsigned int, unsigned int>> q;
        q.push(std::make_pair(x, y)); //Push the initial position into the queue.
        v[x][y] = r; //Replace the initial point.
        while (!q.empty()) //Keep looking at relevant neighbours so long as there is something in the queue.
        auto pt = q.top(); //Collect the first entry.
        q.pop(); //Remove it, we don't want to keep processing the same point.
        //Now add neighbours if they match our initial point.
        if(pt.first > 0 && v[pt.first - 1][pt.second] == init)
        q.push(std::make_pair(pt.first - 1, pt.second);
        v[pt.first - 1][pt.second] = r; //Replace the value here to avoid pushing the same point twice.
        if(pt.first + 1 < v.size() && v[pt.first + 1][pt.second] == init)
        q.push(std::make_pair(pt.first + 1, pt.second);
        v[pt.first + 1][pt.second] = r;
        if(pt.second > 0 && v[pt.first][pt.second - 1] == init)
        q.push(std::make_pair(pt.first, pt.second - 1);
        v[pt.first][pt.second - 1] = r;
        if(pt.second + 1 < v[pt.first].size() && v[pt.first][pt.second + 1] == init)
        q.push(std::make_pair(pt.first, pt.second + 1);
        v[pt.first][pt.second + 1] = r;




        This gives you a BFS-like flood-fill pattern without recursion. Alternatively you could also use a stack instead of the queue, then the flood-fill would behave more like a DFS (much more similar to what the recursive pattern will do). It might even perform a little better than the queue, given the data structure is a little simpler.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 11 at 9:53

























        answered Nov 11 at 9:46









        Qubit

        972215




        972215



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53247243%2fhow-should-i-implement-a-flood-fill-function-to-my-c-program%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            How to read a connectionString WITH PROVIDER in .NET Core?

            In R, how to develop a multiplot heatmap.2 figure showing key labels successfully

            Museum of Modern and Contemporary Art of Trento and Rovereto